1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * part of this file is taken from libcli (libcli.sourceforge.net) *
6 * Copyright (C) David Parrish (david@dparrish.com) *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
27 #include "replacements.h"
32 #include "time_support.h"
41 #include <openocd_tcl.h>
43 int fast_and_dangerous
= 0;
44 extern command_context_t
*active_cmd_ctx
;
46 int handle_sleep_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
47 int handle_fast_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
);
48 static void tcl_output(void *privData
, const char *file
, int line
, const char *function
, const char *string
)
50 Jim_Obj
*tclOutput
=(Jim_Obj
*)privData
;
52 Jim_AppendString(interp
, tclOutput
, string
, strlen(string
));
55 static int script_command(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
57 /* the private data is stashed in the interp structure */
59 command_context_t
*context
;
65 target_call_timer_callbacks_now();
66 LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
68 c
= interp
->cmdPrivData
;
69 LOG_DEBUG("script_command - %s", c
->name
);
72 words
= malloc(sizeof(char *) * nwords
);
73 for (i
= 0; i
< nwords
; i
++)
77 words
[i
] = strdup(Jim_GetString(argv
[i
], &len
));
82 LOG_DEBUG("script_command - %s, argv[%u]=%s", c
->name
, i
, words
[i
]);
85 /* grab the command context from the associated data */
86 context
= Jim_GetAssocData(interp
, "context");
87 retval
= Jim_GetAssocData(interp
, "retval");
88 if (context
!= NULL
&& retval
!= NULL
)
90 /* capture log output and return it */
91 Jim_Obj
*tclOutput
= Jim_NewStringObj(interp
, "", 0);
92 log_add_callback(tcl_output
, tclOutput
);
94 *retval
= run_command(context
, c
, words
, nwords
);
96 log_remove_callback(tcl_output
, tclOutput
);
98 /* We dump output into this local variable */
99 Jim_SetVariableStr(interp
, "openocd_output", tclOutput
);
102 for (i
= 0; i
< nwords
; i
++)
106 return (*retval
==ERROR_OK
)?JIM_OK
:JIM_ERR
;
109 command_t
* register_command(command_context_t
*context
, command_t
*parent
, char *name
, int (*handler
)(struct command_context_s
*context
, char* name
, char** args
, int argc
), enum command_mode mode
, char *help
)
113 if (!context
|| !name
)
116 c
= malloc(sizeof(command_t
));
118 c
->name
= strdup(name
);
121 c
->handler
= handler
;
127 /* place command in tree */
130 if (parent
->children
)
132 /* find last child */
133 for (p
= parent
->children
; p
&& p
->next
; p
= p
->next
);
139 parent
->children
= c
;
144 if (context
->commands
)
146 /* find last command */
147 for (p
= context
->commands
; p
&& p
->next
; p
= p
->next
);
153 context
->commands
= c
;
157 /* just a placeholder, no handler */
158 if (c
->handler
==NULL
)
161 /* If this is a two level command, e.g. "flash banks", then the
162 * "unknown" proc in startup.tcl must redirect to this command.
164 * "flash banks" is translated by "unknown" to "flash_banks"
165 * if such a proc exists
167 /* Print help for command */
171 /* maximum of two levels :-) */
178 const char *full_name
=alloc_printf("%s%s%s", t1
, t2
, t3
);
179 Jim_CreateCommand(interp
, full_name
, script_command
, c
, NULL
);
180 free((void *)full_name
);
183 /* accumulate help text in Tcl helptext list. */
184 Jim_Obj
*helptext
=Jim_GetGlobalVariableStr(interp
, "ocd_helptext", JIM_ERRMSG
);
185 if (Jim_IsShared(helptext
))
186 helptext
= Jim_DuplicateObj(interp
, helptext
);
187 Jim_Obj
*cmd_entry
=Jim_NewListObj(interp
, NULL
, 0);
189 Jim_Obj
*cmd_list
=Jim_NewListObj(interp
, NULL
, 0);
191 /* maximum of two levels :-) */
194 Jim_ListAppendElement(interp
, cmd_list
, Jim_NewStringObj(interp
, c
->parent
->name
, -1));
196 Jim_ListAppendElement(interp
, cmd_list
, Jim_NewStringObj(interp
, c
->name
, -1));
198 Jim_ListAppendElement(interp
, cmd_entry
, cmd_list
);
199 Jim_ListAppendElement(interp
, cmd_entry
, Jim_NewStringObj(interp
, help
, -1));
200 Jim_ListAppendElement(interp
, helptext
, cmd_entry
);
204 int unregister_all_commands(command_context_t
*context
)
212 while(NULL
!= context
->commands
)
214 c
= context
->commands
;
216 while(NULL
!= c
->children
)
219 c
->children
= c
->children
->next
;
226 context
->commands
= context
->commands
->next
;
237 int unregister_command(command_context_t
*context
, char *name
)
239 command_t
*c
, *p
= NULL
, *c2
;
241 if ((!context
) || (!name
))
242 return ERROR_INVALID_ARGUMENTS
;
245 for (c
= context
->commands
; c
; c
= c
->next
)
247 if (strcmp(name
, c
->name
) == 0)
256 context
->commands
= c
->next
;
259 /* unregister children */
262 for (c2
= c
->children
; c2
; c2
= c2
->next
)
274 /* remember the last command for unlinking */
282 void command_output_text(command_context_t
*context
, const char *data
)
284 if( context
&& context
->output_handler
&& data
){
285 context
->output_handler( context
, data
);
289 void command_print_n(command_context_t
*context
, char *format
, ...)
294 va_start(ap
, format
);
296 string
= alloc_vprintf(format
, ap
);
299 /* we want this collected in the log + we also want to pick it up as a tcl return
302 * The latter bit isn't precisely neat, but will do for now.
304 LOG_USER_N("%s", string
);
305 // We already printed it above
306 //command_output_text(context, string);
313 void command_print(command_context_t
*context
, char *format
, ...)
318 va_start(ap
, format
);
320 string
= alloc_vprintf(format
, ap
);
323 strcat(string
, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
324 /* we want this collected in the log + we also want to pick it up as a tcl return
327 * The latter bit isn't precisely neat, but will do for now.
329 LOG_USER_N("%s", string
);
330 // We already printed it above
331 //command_output_text(context, string);
338 int run_command(command_context_t
*context
, command_t
*c
, char *words
[], int num_words
)
341 if (!((context
->mode
== COMMAND_CONFIG
) || (c
->mode
== COMMAND_ANY
) || (c
->mode
== context
->mode
) ))
343 /* Config commands can not run after the config stage */
347 int retval
= c
->handler(context
, c
->name
, words
+ start_word
+ 1, num_words
- start_word
- 1);
348 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
)
350 /* Print help for command */
354 /* maximum of two levels :-) */
361 command_run_linef(context
, "help {%s%s%s}", t1
, t2
, t3
);
363 else if (retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
365 /* just fall through for a shutdown request */
367 else if (retval
!= ERROR_OK
)
369 /* we do not print out an error message because the command *should*
370 * have printed out an error
372 LOG_DEBUG("Command failed with error code %d", retval
);
378 int command_run_line(command_context_t
*context
, char *line
)
380 /* all the parent commands have been registered with the interpreter
381 * so, can just evaluate the line as a script and check for
384 /* run the line thru a script engine */
387 Jim_DeleteAssocData(interp
, "context"); /* remove existing */
388 retcode
= Jim_SetAssocData(interp
, "context", NULL
, context
);
389 if (retcode
!= JIM_OK
)
392 /* associated the return value */
394 Jim_DeleteAssocData(interp
, "retval"); /* remove existing */
395 retcode
= Jim_SetAssocData(interp
, "retval", NULL
, &retval
);
396 if (retcode
!= JIM_OK
)
399 active_cmd_ctx
= context
;
400 retcode
= Jim_Eval(interp
, line
);
401 if (retcode
== JIM_ERR
) {
402 if (retval
!=ERROR_COMMAND_CLOSE_CONNECTION
)
404 /* We do not print the connection closed error message */
405 Jim_PrintErrorMessage(interp
);
407 if (retval
==ERROR_OK
)
409 /* It wasn't a low level OpenOCD command that failed */
413 } else if (retcode
== JIM_EXIT
) {
415 /* exit(Jim_GetExitCode(interp)); */
420 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
424 for (i
= 0; i
< reslen
; i
+= 256)
430 strncpy(buff
, result
+i
, chunk
);
432 LOG_USER_N("%s", buff
);
434 LOG_USER_N("%s", "\n");
441 int command_run_linef(command_context_t
*context
, char *format
, ...)
443 int retval
=ERROR_FAIL
;
446 va_start(ap
, format
);
447 string
= alloc_vprintf(format
, ap
);
450 retval
=command_run_line(context
, string
);
458 void command_set_output_handler(command_context_t
* context
, int (*output_handler
)(struct command_context_s
*context
, const char* line
), void *priv
)
460 context
->output_handler
= output_handler
;
461 context
->output_handler_priv
= priv
;
464 command_context_t
* copy_command_context(command_context_t
* context
)
466 command_context_t
* copy_context
= malloc(sizeof(command_context_t
));
468 *copy_context
= *context
;
473 int command_done(command_context_t
*context
)
481 command_context_t
* command_init()
483 command_context_t
* context
= malloc(sizeof(command_context_t
));
485 context
->mode
= COMMAND_EXEC
;
486 context
->commands
= NULL
;
487 context
->current_target
= 0;
488 context
->output_handler
= NULL
;
489 context
->output_handler_priv
= NULL
;
491 register_command(context
, NULL
, "sleep", handle_sleep_command
,
492 COMMAND_ANY
, "sleep for <n> milliseconds");
494 register_command(context
, NULL
, "fast", handle_fast_command
,
495 COMMAND_ANY
, "fast <enable/disable> - place at beginning of config files. Sets defaults to fast and dangerous.");
500 int command_context_mode(command_context_t
*cmd_ctx
, enum command_mode mode
)
503 return ERROR_INVALID_ARGUMENTS
;
505 cmd_ctx
->mode
= mode
;
509 /* sleep command sleeps for <n> miliseconds
510 * this is useful in target startup scripts
512 int handle_sleep_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
514 unsigned long duration
= 0;
518 duration
= strtoul(args
[0], NULL
, 0);
519 usleep(duration
* 1000);
525 int handle_fast_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
528 return ERROR_COMMAND_SYNTAX_ERROR
;
530 fast_and_dangerous
= strcmp("enable", args
[0])==0;
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)