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.
 
 
 
 
 
 

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