You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

928 lines
23 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2005 by Dominic Rath *
  3. * Dominic.Rath@gmx.de *
  4. * *
  5. * Copyright (C) 2007,2008 Øyvind Harboe *
  6. * oyvind.harboe@zylin.com *
  7. * *
  8. * Copyright (C) 2008, Duane Ellis *
  9. * openocd@duaneeellis.com *
  10. * *
  11. * part of this file is taken from libcli (libcli.sourceforge.net) *
  12. * Copyright (C) David Parrish (david@dparrish.com) *
  13. * *
  14. * This program is free software; you can redistribute it and/or modify *
  15. * it under the terms of the GNU General Public License as published by *
  16. * the Free Software Foundation; either version 2 of the License, or *
  17. * (at your option) any later version. *
  18. * *
  19. * This program is distributed in the hope that it will be useful, *
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  22. * GNU General Public License for more details. *
  23. * *
  24. * You should have received a copy of the GNU General Public License *
  25. * along with this program; if not, write to the *
  26. * Free Software Foundation, Inc., *
  27. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  28. ***************************************************************************/
  29. #ifdef HAVE_CONFIG_H
  30. #include "config.h"
  31. #endif
  32. #if !BUILD_ECOSBOARD
  33. /* see Embedder-HOWTO.txt in Jim Tcl project hosted on BerliOS*/
  34. #define JIM_EMBEDDED
  35. #endif
  36. // @todo the inclusion of target.h here is a layering violation
  37. #include "target.h"
  38. #include "command.h"
  39. #include "configuration.h"
  40. #include "log.h"
  41. #include "time_support.h"
  42. #include "jim-eventloop.h"
  43. int fast_and_dangerous = 0;
  44. Jim_Interp *interp = NULL;
  45. int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
  46. int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
  47. int run_command(command_context_t *context, command_t *c, char *words[], int num_words);
  48. static void tcl_output(void *privData, const char *file, int line, const char *function, const char *string)
  49. {
  50. Jim_Obj *tclOutput = (Jim_Obj *)privData;
  51. Jim_AppendString(interp, tclOutput, string, strlen(string));
  52. }
  53. extern command_context_t *global_cmd_ctx;
  54. void script_debug(Jim_Interp *interp, const char *name, int argc, Jim_Obj *const *argv)
  55. {
  56. int i;
  57. LOG_DEBUG("command - %s", name);
  58. for (i = 0; i < argc; i++) {
  59. int len;
  60. const char *w = Jim_GetString(argv[i], &len);
  61. /* end of line comment? */
  62. if (*w == '#')
  63. break;
  64. LOG_DEBUG("%s - argv[%d]=%s", name, i, w);
  65. }
  66. }
  67. static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  68. {
  69. /* the private data is stashed in the interp structure */
  70. command_t *c;
  71. command_context_t *context;
  72. int retval;
  73. int i;
  74. int nwords;
  75. char **words;
  76. /* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
  77. * get overwritten by running other Jim commands! Treat it as an
  78. * emphemeral global variable that is used in lieu of an argument
  79. * to the fn and fish it out manually.
  80. */
  81. c = interp->cmdPrivData;
  82. if (c == NULL)
  83. {
  84. LOG_ERROR("BUG: interp->cmdPrivData == NULL");
  85. return JIM_ERR;
  86. }
  87. target_call_timer_callbacks_now();
  88. LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
  89. script_debug(interp, c->name, argc, argv);
  90. words = malloc(sizeof(char *) * argc);
  91. for (i = 0; i < argc; i++)
  92. {
  93. int len;
  94. const char *w = Jim_GetString(argv[i], &len);
  95. if (*w=='#')
  96. {
  97. /* hit an end of line comment */
  98. break;
  99. }
  100. words[i] = strdup(w);
  101. if (words[i] == NULL)
  102. {
  103. int j;
  104. for (j = 0; j < i; j++)
  105. free(words[j]);
  106. free(words);
  107. return JIM_ERR;
  108. }
  109. }
  110. nwords = i;
  111. /* grab the command context from the associated data */
  112. context = Jim_GetAssocData(interp, "context");
  113. if (context == NULL)
  114. {
  115. /* Tcl can invoke commands directly instead of via command_run_line(). This would
  116. * happen when the Jim Tcl interpreter is provided by eCos.
  117. */
  118. context = global_cmd_ctx;
  119. }
  120. /* capture log output and return it */
  121. Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
  122. /* a garbage collect can happen, so we need a reference count to this object */
  123. Jim_IncrRefCount(tclOutput);
  124. log_add_callback(tcl_output, tclOutput);
  125. retval = run_command(context, c, words, nwords);
  126. log_remove_callback(tcl_output, tclOutput);
  127. /* We dump output into this local variable */
  128. Jim_SetResult(interp, tclOutput);
  129. Jim_DecrRefCount(interp, tclOutput);
  130. for (i = 0; i < nwords; i++)
  131. free(words[i]);
  132. free(words);
  133. int *return_retval = Jim_GetAssocData(interp, "retval");
  134. if (return_retval != NULL)
  135. {
  136. *return_retval = retval;
  137. }
  138. return (retval == ERROR_OK)?JIM_OK:JIM_ERR;
  139. }
  140. /* nice short description of source file */
  141. #define __THIS__FILE__ "command.c"
  142. 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)
  143. {
  144. command_t *c, *p;
  145. if (!context || !name)
  146. return NULL;
  147. c = malloc(sizeof(command_t));
  148. c->name = strdup(name);
  149. c->parent = parent;
  150. c->children = NULL;
  151. c->handler = handler;
  152. c->mode = mode;
  153. if (!help)
  154. help="";
  155. c->next = NULL;
  156. /* place command in tree */
  157. if (parent)
  158. {
  159. if (parent->children)
  160. {
  161. /* find last child */
  162. for (p = parent->children; p && p->next; p = p->next);
  163. if (p)
  164. p->next = c;
  165. }
  166. else
  167. {
  168. parent->children = c;
  169. }
  170. }
  171. else
  172. {
  173. if (context->commands)
  174. {
  175. /* find last command */
  176. for (p = context->commands; p && p->next; p = p->next);
  177. if (p)
  178. p->next = c;
  179. }
  180. else
  181. {
  182. context->commands = c;
  183. }
  184. }
  185. /* just a placeholder, no handler */
  186. if (c->handler == NULL)
  187. return c;
  188. /* If this is a two level command, e.g. "flash banks", then the
  189. * "unknown" proc in startup.tcl must redirect to this command.
  190. *
  191. * "flash banks" is translated by "unknown" to "flash_banks"
  192. * if such a proc exists
  193. */
  194. /* Print help for command */
  195. const char *t1="";
  196. const char *t2="";
  197. const char *t3="";
  198. /* maximum of two levels :-) */
  199. if (c->parent != NULL)
  200. {
  201. t1 = c->parent->name;
  202. t2="_";
  203. }
  204. t3 = c->name;
  205. const char *full_name = alloc_printf("ocd_%s%s%s", t1, t2, t3);
  206. Jim_CreateCommand(interp, full_name, script_command, c, NULL);
  207. free((void *)full_name);
  208. /* we now need to add an overrideable proc */
  209. const char *override_name = alloc_printf("proc %s%s%s {args} {if {[catch {eval ocd_%s%s%s $args}]==0} {return \"\"} else { return -code error }", t1, t2, t3, t1, t2, t3);
  210. Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
  211. free((void *)override_name);
  212. /* accumulate help text in Tcl helptext list. */
  213. Jim_Obj *helptext = Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
  214. if (Jim_IsShared(helptext))
  215. helptext = Jim_DuplicateObj(interp, helptext);
  216. Jim_Obj *cmd_entry = Jim_NewListObj(interp, NULL, 0);
  217. Jim_Obj *cmd_list = Jim_NewListObj(interp, NULL, 0);
  218. /* maximum of two levels :-) */
  219. if (c->parent != NULL)
  220. {
  221. Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, c->parent->name, -1));
  222. }
  223. Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, c->name, -1));
  224. Jim_ListAppendElement(interp, cmd_entry, cmd_list);
  225. Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, help, -1));
  226. Jim_ListAppendElement(interp, helptext, cmd_entry);
  227. return c;
  228. }
  229. int unregister_all_commands(command_context_t *context)
  230. {
  231. command_t *c, *c2;
  232. if (context == NULL)
  233. return ERROR_OK;
  234. while (NULL != context->commands)
  235. {
  236. c = context->commands;
  237. while (NULL != c->children)
  238. {
  239. c2 = c->children;
  240. c->children = c->children->next;
  241. free(c2->name);
  242. c2->name = NULL;
  243. free(c2);
  244. c2 = NULL;
  245. }
  246. context->commands = context->commands->next;
  247. free(c->name);
  248. c->name = NULL;
  249. free(c);
  250. c = NULL;
  251. }
  252. return ERROR_OK;
  253. }
  254. int unregister_command(command_context_t *context, char *name)
  255. {
  256. command_t *c, *p = NULL, *c2;
  257. if ((!context) || (!name))
  258. return ERROR_INVALID_ARGUMENTS;
  259. /* find command */
  260. c = context->commands;
  261. while (NULL != c)
  262. {
  263. if (strcmp(name, c->name) == 0)
  264. {
  265. /* unlink command */
  266. if (p)
  267. {
  268. p->next = c->next;
  269. }
  270. else
  271. {
  272. /* first element in command list */
  273. context->commands = c->next;
  274. }
  275. /* unregister children */
  276. while (NULL != c->children)
  277. {
  278. c2 = c->children;
  279. c->children = c->children->next;
  280. free(c2->name);
  281. c2->name = NULL;
  282. free(c2);
  283. c2 = NULL;
  284. }
  285. /* delete command */
  286. free(c->name);
  287. c->name = NULL;
  288. free(c);
  289. c = NULL;
  290. return ERROR_OK;
  291. }
  292. /* remember the last command for unlinking */
  293. p = c;
  294. c = c->next;
  295. }
  296. return ERROR_OK;
  297. }
  298. void command_output_text(command_context_t *context, const char *data)
  299. {
  300. if (context && context->output_handler && data) {
  301. context->output_handler(context, data);
  302. }
  303. }
  304. void command_print_sameline(command_context_t *context, const char *format, ...)
  305. {
  306. char *string;
  307. va_list ap;
  308. va_start(ap, format);
  309. string = alloc_vprintf(format, ap);
  310. if (string != NULL)
  311. {
  312. /* we want this collected in the log + we also want to pick it up as a tcl return
  313. * value.
  314. *
  315. * The latter bit isn't precisely neat, but will do for now.
  316. */
  317. LOG_USER_N("%s", string);
  318. /* We already printed it above */
  319. /* command_output_text(context, string); */
  320. free(string);
  321. }
  322. va_end(ap);
  323. }
  324. void command_print(command_context_t *context, const char *format, ...)
  325. {
  326. char *string;
  327. va_list ap;
  328. va_start(ap, format);
  329. string = alloc_vprintf(format, ap);
  330. if (string != NULL)
  331. {
  332. strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
  333. /* we want this collected in the log + we also want to pick it up as a tcl return
  334. * value.
  335. *
  336. * The latter bit isn't precisely neat, but will do for now.
  337. */
  338. LOG_USER_N("%s", string);
  339. /* We already printed it above */
  340. /* command_output_text(context, string); */
  341. free(string);
  342. }
  343. va_end(ap);
  344. }
  345. int run_command(command_context_t *context, command_t *c, char *words[], int num_words)
  346. {
  347. int start_word = 0;
  348. if (!((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode)))
  349. {
  350. /* Config commands can not run after the config stage */
  351. LOG_ERROR("Command '%s' only runs during configuration stage", c->name);
  352. return ERROR_FAIL;
  353. }
  354. int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
  355. if (retval == ERROR_COMMAND_SYNTAX_ERROR)
  356. {
  357. /* Print help for command */
  358. const char *t1="";
  359. const char *t2="";
  360. const char *t3="";
  361. /* maximum of two levels :-) */
  362. if (c->parent != NULL)
  363. {
  364. t1 = c->parent->name;
  365. t2=" ";
  366. }
  367. t3 = c->name;
  368. command_run_linef(context, "help {%s%s%s}", t1, t2, t3);
  369. }
  370. else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
  371. {
  372. /* just fall through for a shutdown request */
  373. }
  374. else if (retval != ERROR_OK)
  375. {
  376. /* we do not print out an error message because the command *should*
  377. * have printed out an error
  378. */
  379. LOG_DEBUG("Command failed with error code %d", retval);
  380. }
  381. return retval;
  382. }
  383. int command_run_line(command_context_t *context, char *line)
  384. {
  385. /* all the parent commands have been registered with the interpreter
  386. * so, can just evaluate the line as a script and check for
  387. * results
  388. */
  389. /* run the line thru a script engine */
  390. int retval = ERROR_FAIL;
  391. int retcode;
  392. /* Beware! This code needs to be reentrant. It is also possible
  393. * for OpenOCD commands to be invoked directly from Tcl. This would
  394. * happen when the Jim Tcl interpreter is provided by eCos for
  395. * instance.
  396. */
  397. Jim_DeleteAssocData(interp, "context");
  398. retcode = Jim_SetAssocData(interp, "context", NULL, context);
  399. if (retcode == JIM_OK)
  400. {
  401. /* associated the return value */
  402. Jim_DeleteAssocData(interp, "retval");
  403. retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
  404. if (retcode == JIM_OK)
  405. {
  406. retcode = Jim_Eval_Named(interp, line, __THIS__FILE__, __LINE__);
  407. Jim_DeleteAssocData(interp, "retval");
  408. }
  409. Jim_DeleteAssocData(interp, "context");
  410. }
  411. if (retcode == JIM_ERR) {
  412. if (retval != ERROR_COMMAND_CLOSE_CONNECTION)
  413. {
  414. /* We do not print the connection closed error message */
  415. Jim_PrintErrorMessage(interp);
  416. }
  417. if (retval == ERROR_OK)
  418. {
  419. /* It wasn't a low level OpenOCD command that failed */
  420. return ERROR_FAIL;
  421. }
  422. return retval;
  423. } else if (retcode == JIM_EXIT) {
  424. /* ignore. */
  425. /* exit(Jim_GetExitCode(interp)); */
  426. } else {
  427. const char *result;
  428. int reslen;
  429. result = Jim_GetString(Jim_GetResult(interp), &reslen);
  430. if (reslen > 0)
  431. {
  432. int i;
  433. char buff[256 + 1];
  434. for (i = 0; i < reslen; i += 256)
  435. {
  436. int chunk;
  437. chunk = reslen - i;
  438. if (chunk > 256)
  439. chunk = 256;
  440. strncpy(buff, result + i, chunk);
  441. buff[chunk] = 0;
  442. LOG_USER_N("%s", buff);
  443. }
  444. LOG_USER_N("%s", "\n");
  445. }
  446. retval = ERROR_OK;
  447. }
  448. return retval;
  449. }
  450. int command_run_linef(command_context_t *context, const char *format, ...)
  451. {
  452. int retval = ERROR_FAIL;
  453. char *string;
  454. va_list ap;
  455. va_start(ap, format);
  456. string = alloc_vprintf(format, ap);
  457. if (string != NULL)
  458. {
  459. retval = command_run_line(context, string);
  460. }
  461. va_end(ap);
  462. return retval;
  463. }
  464. void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, const char* line), void *priv)
  465. {
  466. context->output_handler = output_handler;
  467. context->output_handler_priv = priv;
  468. }
  469. command_context_t* copy_command_context(command_context_t* context)
  470. {
  471. command_context_t* copy_context = malloc(sizeof(command_context_t));
  472. *copy_context = *context;
  473. return copy_context;
  474. }
  475. int command_done(command_context_t *context)
  476. {
  477. free(context);
  478. context = NULL;
  479. return ERROR_OK;
  480. }
  481. /* find full path to file */
  482. static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  483. {
  484. if (argc != 2)
  485. return JIM_ERR;
  486. const char *file = Jim_GetString(argv[1], NULL);
  487. char *full_path = find_file(file);
  488. if (full_path == NULL)
  489. return JIM_ERR;
  490. Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
  491. free(full_path);
  492. Jim_SetResult(interp, result);
  493. return JIM_OK;
  494. }
  495. static int jim_echo(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  496. {
  497. if (argc != 2)
  498. return JIM_ERR;
  499. const char *str = Jim_GetString(argv[1], NULL);
  500. LOG_USER("%s", str);
  501. return JIM_OK;
  502. }
  503. static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *cookie)
  504. {
  505. size_t nbytes;
  506. const char *ptr;
  507. Jim_Interp *interp;
  508. /* make it a char easier to read code */
  509. ptr = _ptr;
  510. interp = cookie;
  511. nbytes = size * n;
  512. if (ptr == NULL || interp == NULL || nbytes == 0) {
  513. return 0;
  514. }
  515. /* do we have to chunk it? */
  516. if (ptr[nbytes] == 0)
  517. {
  518. /* no it is a C style string */
  519. LOG_USER_N("%s", ptr);
  520. return strlen(ptr);
  521. }
  522. /* GRR we must chunk - not null terminated */
  523. while (nbytes) {
  524. char chunk[128 + 1];
  525. int x;
  526. x = nbytes;
  527. if (x > 128) {
  528. x = 128;
  529. }
  530. /* copy it */
  531. memcpy(chunk, ptr, x);
  532. /* terminate it */
  533. chunk[n] = 0;
  534. /* output it */
  535. LOG_USER_N("%s", chunk);
  536. ptr += x;
  537. nbytes -= x;
  538. }
  539. return n;
  540. }
  541. static size_t openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie)
  542. {
  543. /* TCL wants to read... tell him no */
  544. return 0;
  545. }
  546. static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
  547. {
  548. char *cp;
  549. int n;
  550. Jim_Interp *interp;
  551. n = -1;
  552. interp = cookie;
  553. if (interp == NULL)
  554. return n;
  555. cp = alloc_vprintf(fmt, ap);
  556. if (cp)
  557. {
  558. LOG_USER_N("%s", cp);
  559. n = strlen(cp);
  560. free(cp);
  561. }
  562. return n;
  563. }
  564. static int openocd_jim_fflush(void *cookie)
  565. {
  566. /* nothing to flush */
  567. return 0;
  568. }
  569. static char* openocd_jim_fgets(char *s, int size, void *cookie)
  570. {
  571. /* not supported */
  572. errno = ENOTSUP;
  573. return NULL;
  574. }
  575. static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  576. {
  577. if (argc != 2)
  578. return JIM_ERR;
  579. int retcode;
  580. const char *str = Jim_GetString(argv[1], NULL);
  581. /* capture log output and return it */
  582. Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
  583. /* a garbage collect can happen, so we need a reference count to this object */
  584. Jim_IncrRefCount(tclOutput);
  585. log_add_callback(tcl_output, tclOutput);
  586. retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
  587. log_remove_callback(tcl_output, tclOutput);
  588. /* We dump output into this local variable */
  589. Jim_SetResult(interp, tclOutput);
  590. Jim_DecrRefCount(interp, tclOutput);
  591. return retcode;
  592. }
  593. command_context_t* command_init()
  594. {
  595. command_context_t* context = malloc(sizeof(command_context_t));
  596. extern const char startup_tcl[];
  597. const char *HostOs;
  598. context->mode = COMMAND_EXEC;
  599. context->commands = NULL;
  600. context->current_target = 0;
  601. context->output_handler = NULL;
  602. context->output_handler_priv = NULL;
  603. #if !BUILD_ECOSBOARD
  604. Jim_InitEmbedded();
  605. /* Create an interpreter */
  606. interp = Jim_CreateInterp();
  607. /* Add all the Jim core commands */
  608. Jim_RegisterCoreCommands(interp);
  609. #endif
  610. #if defined(_MSC_VER)
  611. /* WinXX - is generic, the forward
  612. * looking problem is this:
  613. *
  614. * "win32" or "win64"
  615. *
  616. * "winxx" is generic.
  617. */
  618. HostOs = "winxx";
  619. #elif defined(__LINUX__)
  620. HostOs = "linux";
  621. #elif defined(__DARWIN__)
  622. HostOs = "darwin";
  623. #elif defined(__CYGWIN__)
  624. HostOs = "cygwin";
  625. #elif defined(__MINGW32__)
  626. HostOs = "mingw32";
  627. #else
  628. HostOs = "other";
  629. #endif
  630. Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS", Jim_NewStringObj(interp, HostOs , strlen(HostOs)));
  631. Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
  632. Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
  633. Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);
  634. /* Set Jim's STDIO */
  635. interp->cookie_stdin = interp;
  636. interp->cookie_stdout = interp;
  637. interp->cookie_stderr = interp;
  638. interp->cb_fwrite = openocd_jim_fwrite;
  639. interp->cb_fread = openocd_jim_fread ;
  640. interp->cb_vfprintf = openocd_jim_vfprintf;
  641. interp->cb_fflush = openocd_jim_fflush;
  642. interp->cb_fgets = openocd_jim_fgets;
  643. #if !BUILD_ECOSBOARD
  644. Jim_EventLoopOnLoad(interp);
  645. #endif
  646. if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl",1) == JIM_ERR)
  647. {
  648. LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD compile time)");
  649. Jim_PrintErrorMessage(interp);
  650. exit(-1);
  651. }
  652. register_command(context, NULL, "sleep", handle_sleep_command,
  653. COMMAND_ANY, "<n> [busy] - sleep for n milliseconds. \"busy\" means busy wait");
  654. register_command(context, NULL, "fast", handle_fast_command,
  655. COMMAND_ANY, "fast <enable/disable> - place at beginning of config files. Sets defaults to fast and dangerous.");
  656. return context;
  657. }
  658. int command_context_mode(command_context_t *cmd_ctx, enum command_mode mode)
  659. {
  660. if (!cmd_ctx)
  661. return ERROR_INVALID_ARGUMENTS;
  662. cmd_ctx->mode = mode;
  663. return ERROR_OK;
  664. }
  665. /* sleep command sleeps for <n> miliseconds
  666. * this is useful in target startup scripts
  667. */
  668. int handle_sleep_command(struct command_context_s *cmd_ctx,
  669. char *cmd, char **args, int argc)
  670. {
  671. bool busy = false;
  672. if (argc == 2)
  673. {
  674. if (strcmp(args[1], "busy") == 0)
  675. busy = true;
  676. else
  677. return ERROR_COMMAND_SYNTAX_ERROR;
  678. }
  679. else if (argc < 1 || argc > 2)
  680. return ERROR_COMMAND_SYNTAX_ERROR;
  681. unsigned long duration = 0;
  682. int retval = parse_ulong(args[0], &duration);
  683. if (ERROR_OK != retval)
  684. return retval;
  685. if (!busy)
  686. {
  687. long long then = timeval_ms();
  688. while (timeval_ms() - then < (long long)duration)
  689. {
  690. target_call_timer_callbacks_now();
  691. usleep(1000);
  692. }
  693. }
  694. else
  695. busy_sleep(duration);
  696. return ERROR_OK;
  697. }
  698. int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
  699. {
  700. if (argc != 1)
  701. return ERROR_COMMAND_SYNTAX_ERROR;
  702. fast_and_dangerous = strcmp("enable", args[0]) == 0;
  703. return ERROR_OK;
  704. }
  705. void process_jim_events(void)
  706. {
  707. #if !BUILD_ECOSBOARD
  708. static int recursion = 0;
  709. if (!recursion)
  710. {
  711. recursion++;
  712. Jim_ProcessEvents (interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
  713. recursion--;
  714. }
  715. #endif
  716. }
  717. void register_jim(struct command_context_s *cmd_ctx, const char *name, int (*cmd)(Jim_Interp *interp, int argc, Jim_Obj *const *argv), const char *help)
  718. {
  719. Jim_CreateCommand(interp, name, cmd, NULL, NULL);
  720. /* FIX!!! it would be prettier to invoke add_help_text...
  721. * accumulate help text in Tcl helptext list. */
  722. Jim_Obj *helptext = Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
  723. if (Jim_IsShared(helptext))
  724. helptext = Jim_DuplicateObj(interp, helptext);
  725. Jim_Obj *cmd_entry = Jim_NewListObj(interp, NULL, 0);
  726. Jim_Obj *cmd_list = Jim_NewListObj(interp, NULL, 0);
  727. Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, name, -1));
  728. Jim_ListAppendElement(interp, cmd_entry, cmd_list);
  729. Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, help, -1));
  730. Jim_ListAppendElement(interp, helptext, cmd_entry);
  731. }
  732. /* return global variable long value or 0 upon failure */
  733. long jim_global_long(const char *variable)
  734. {
  735. Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, variable, JIM_ERRMSG);
  736. long t;
  737. if (Jim_GetLong(interp, objPtr, &t) == JIM_OK)
  738. {
  739. return t;
  740. }
  741. return 0;
  742. }
  743. #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
  744. int parse##name(const char *str, type *ul) \
  745. { \
  746. if (!*str) \
  747. { \
  748. LOG_ERROR("Invalid command argument"); \
  749. return ERROR_COMMAND_ARGUMENT_INVALID; \
  750. } \
  751. char *end; \
  752. *ul = func(str, &end, 0); \
  753. if (*end) \
  754. { \
  755. LOG_ERROR("Invalid command argument"); \
  756. return ERROR_COMMAND_ARGUMENT_INVALID; \
  757. } \
  758. if ((max == *ul) && (ERANGE == errno)) \
  759. { \
  760. LOG_ERROR("Argument overflow"); \
  761. return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
  762. } \
  763. if (min && (min == *ul) && (ERANGE == errno)) \
  764. { \
  765. LOG_ERROR("Argument underflow"); \
  766. return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
  767. } \
  768. return ERROR_OK; \
  769. }
  770. DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long , strtoul, 0, ULONG_MAX)
  771. DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX)
  772. DEFINE_PARSE_NUM_TYPE(_long, long , strtol, LONG_MIN, LONG_MAX)
  773. DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
  774. #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
  775. int parse##name(const char *str, type *ul) \
  776. { \
  777. functype n; \
  778. int retval = parse##funcname(str, &n); \
  779. if (ERROR_OK != retval) \
  780. return retval; \
  781. if (n > max) \
  782. return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
  783. if (min) \
  784. return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
  785. *ul = n; \
  786. return ERROR_OK; \
  787. }
  788. #define DEFINE_PARSE_ULONG(name, type, min, max) \
  789. DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
  790. DEFINE_PARSE_ULONG(_uint, unsigned, 0, UINT_MAX)
  791. DEFINE_PARSE_ULONG(_u32, uint32_t, 0, UINT32_MAX)
  792. DEFINE_PARSE_ULONG(_u16, uint16_t, 0, UINT16_MAX)
  793. DEFINE_PARSE_ULONG(_u8, uint8_t, 0, UINT8_MAX)
  794. #define DEFINE_PARSE_LONG(name, type, min, max) \
  795. DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
  796. DEFINE_PARSE_LONG(_int, int, n < INT_MIN, INT_MAX)
  797. DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
  798. DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
  799. DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)