From 32e2554f105163017052572a1830f3caa19ba625 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 14 Jun 2000 17:22:59 +0000 Subject: Patch rtems-4.5-beta3-mon.diff from Chris Johns to: I have also added the ability to register and unregister commands. This allows me to create a set of monitor commands for the network stack plus basic memory dump/patch commands (needs a working probe interface). I will also look at a basic ls/cd/rm/mv/cp command set at some stage. I have been thinking about changing the monitor in the future to more like a light weight RTEMS shell, `eshell' for embedded shell. This is a story for another day but is a process or getting the commands to map to the filesystem (eg, major=commands, minor=command) and supporting an environment. The filesystem provide a structure for the commands. --- c/src/libmisc/monitor/mon-command.c | 695 +++++++++++++++++++++++++++++++----- c/src/libmisc/monitor/mon-monitor.c | 233 ++++++++---- c/src/libmisc/monitor/monitor.h | 7 +- 3 files changed, 761 insertions(+), 174 deletions(-) (limited to 'c/src/libmisc') diff --git a/c/src/libmisc/monitor/mon-command.c b/c/src/libmisc/monitor/mon-command.c index 5c733b60d9..cf25325880 100644 --- a/c/src/libmisc/monitor/mon-command.c +++ b/c/src/libmisc/monitor/mon-command.c @@ -13,10 +13,421 @@ #include #include +/* + * CCJ: 26-3-2000, adding command history and command line + * editing. This code is donated from My Right Boot and not + * covered by GPL, only the RTEMS license. + */ + +/* + * Some key labels to define special keys. + */ + +#define KEYS_EXTENDED (0x8000) +#define KEYS_NORMAL_MASK (0x00ff) +#define KEYS_INS (0) +#define KEYS_DEL (1) +#define KEYS_UARROW (2) +#define KEYS_DARROW (3) +#define KEYS_LARROW (4) +#define KEYS_RARROW (5) +#define KEYS_HOME (6) +#define KEYS_END (7) +#define KEYS_F1 (8) +#define KEYS_F2 (9) +#define KEYS_F3 (10) +#define KEYS_F4 (11) +#define KEYS_F5 (12) +#define KEYS_F6 (13) +#define KEYS_F7 (14) +#define KEYS_F8 (15) +#define KEYS_F9 (16) +#define KEYS_F10 (17) + +#define RTEMS_COMMAND_BUFFER_SIZE (75) + +static char monitor_prompt[32]; +static char buffer[RTEMS_COMMAND_BUFFER_SIZE]; +static int pos; +static int logged_in; + +/* + * History data. + */ + +#define RTEMS_COMMAND_HISTORIES (20) + +static char history_buffer[RTEMS_COMMAND_HISTORIES][RTEMS_COMMAND_BUFFER_SIZE]; +static int history_pos[RTEMS_COMMAND_HISTORIES]; +static int history; +static int history_next; + +/* + * Translation tables. Not sure if this is the best way to + * handle this, how-ever I wish to avoid the overhead of + * including a more complete and standard environment such + * as ncurses. + */ + +struct translation_table +{ + char expecting; + struct translation_table *branch; + unsigned int key; +}; + +static struct translation_table trans_two[] = +{ + { '~', 0, KEYS_INS }, + { 0, 0, 0 } +}; + +static struct translation_table trans_three[] = +{ + { '~', 0, KEYS_DEL }, + { 0, 0, 0 } +}; + +static struct translation_table trans_tab_csi[] = +{ + { '2', trans_two, 0 }, + { '3', trans_three, 0 }, + { 'A', 0, KEYS_UARROW }, + { 'B', 0, KEYS_DARROW }, + { 'D', 0, KEYS_LARROW }, + { 'C', 0, KEYS_RARROW }, + { 'F', 0, KEYS_END }, + { 'H', 0, KEYS_HOME }, + { 0, 0, 0 } +}; + +static struct translation_table trans_tab_O[] = +{ + { '1', 0, KEYS_F1 }, + { '2', 0, KEYS_F2 }, + { '3', 0, KEYS_F3 }, + { '4', 0, KEYS_F4 }, + { '5', 0, KEYS_F5 }, + { '6', 0, KEYS_F6 }, + { '7', 0, KEYS_F7 }, + { '8', 0, KEYS_F8 }, + { '9', 0, KEYS_F9 }, + { ':', 0, KEYS_F10 }, + { 'P', 0, KEYS_F1 }, + { 'Q', 0, KEYS_F2 }, + { 'R', 0, KEYS_F3 }, + { 'S', 0, KEYS_F4 }, + { 'T', 0, KEYS_F5 }, + { 'U', 0, KEYS_F6 }, + { 'V', 0, KEYS_F7 }, + { 'W', 0, KEYS_F8 }, + { 'X', 0, KEYS_F9 }, + { 'Y', 0, KEYS_F10 }, + { 0, 0, 0 } +}; + +static struct translation_table trans_tab[] = +{ + { '[', trans_tab_csi, 0 }, /* CSI command sequences */ + { 'O', trans_tab_O, 0 }, /* O are the fuction keys */ + { 0, 0, 0 } +}; + +/* + * Perform a basic tranlation for some ANSI/VT100 key codes. + * This code could do with a timeout on the ESC as it is + * now lost from the input stream. It is not* used by the + * line editor below so considiered not worth the effort. + */ + +static unsigned int +rtems_monitor_getchar ( +) +{ + struct translation_table *translation = 0; + for (;;) + { + char c = getchar (); + if (c == 27) + translation = trans_tab; + else + { + /* + * If no translation happing just pass through + * and return the key. + */ + if (translation) + { + /* + * Scan the current table for the key, and if found + * see if this key is a fork. If so follow it and + * wait else return the extended key. + */ + int index = 0; + int branched = 0; + while ((translation[index].expecting != '\0') || + (translation[index].key != '\0')) + { + if (translation[index].expecting == c) + { + /* + * A branch is take if more keys are to come. + */ + if (translation[index].branch == 0) + return KEYS_EXTENDED | translation[index].key; + else + { + translation = translation[index].branch; + branched = 1; + break; + } + } + index++; + } + /* + * Who knows what these keys are, just drop them. + */ + if (!branched) + translation = 0; + } + else + return c; + } + } +} + +/* + * The line editor with history. + */ + +static int +rtems_monitor_line_editor ( + char *command +) +{ + int repeating = 0; + + memset (buffer, 0, RTEMS_COMMAND_BUFFER_SIZE); + history = history_next; + pos = 0; + + if (!logged_in) + printf ("\nMonitor ready, press enter to login.\n\n"); + else + printf ("%s $ ", monitor_prompt); + + while (1) + { + unsigned int extended_key = rtems_monitor_getchar (); + char c = extended_key & KEYS_NORMAL_MASK; + + /* + * Make the extended_key usable as a boolean. + */ + extended_key &= ~KEYS_NORMAL_MASK; + + if (!extended_key && !logged_in) + { + if (c == '\n') + { + logged_in = 1; + /* + * The prompt has changed from `>' to `$' to help know + * which version of the monitor code people are using. + */ + printf("%s $ ", monitor_prompt); + } + } + else + { + if (extended_key) + { + switch (c) + { + case KEYS_END: + printf (buffer + pos); + pos = (int) strlen (buffer); + break; + + case KEYS_HOME: + printf ("\r%s $ ", monitor_prompt); + pos = 0; + break; + + case KEYS_LARROW: + if (pos > 0) + { + pos--; + putchar ('\b'); + } + break; + + case KEYS_RARROW: + if ((pos < RTEMS_COMMAND_BUFFER_SIZE) && (buffer[pos] != '\0')) + { + putchar (buffer[pos]); + pos++; + } + break; + + case KEYS_UARROW: + /* + * If we are moving up the histories then we need to save the working + * buffer. + */ + if (history) + { + int end; + int bs; + if (history == history_next) + { + memcpy (history_buffer[history_next], buffer, + RTEMS_COMMAND_BUFFER_SIZE); + history_pos[history_next] = pos; + } + history--; + memcpy (buffer, history_buffer[history], + RTEMS_COMMAND_BUFFER_SIZE); + pos = history_pos[history]; + printf ("\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' '); + printf ("\r%s $ %s", monitor_prompt, buffer); + end = (int) strlen (buffer); + for (bs = 0; bs < (end - pos); bs++) + putchar ('\b'); + } + break; + + case KEYS_DARROW: + if (history < history_next) + { + int end; + int bs; + history++; + memcpy (buffer, history_buffer[history], + RTEMS_COMMAND_BUFFER_SIZE); + pos = history_pos[history]; + printf ("\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' '); + printf ("\r%s $ %s", monitor_prompt, buffer); + end = (int) strlen (buffer); + for (bs = 0; bs < (end - pos); bs++) + putchar ('\b'); + } + break; + + case KEYS_DEL: + if (buffer[pos] != '\0') + { + int end; + int bs; + strcpy (&buffer[pos], &buffer[pos + 1]); + printf ("\r%s $ %s", monitor_prompt, buffer); + end = (int) strlen (buffer); + for (bs = 0; bs < (end - pos); bs++) + putchar ('\b'); + } + break; + } + } + else + { + switch (c) + { + case '\b': + case '\x7e': + case '\x7f': + if (pos > 0) + { + int bs; + pos--; + strcpy (buffer + pos, buffer + pos + 1); + printf ("\b%s \b", buffer + pos); + for (bs = 0; bs < ((int) strlen (buffer) - pos); bs++) + putchar ('\b'); + } + break; + + case '\n': + /* + * Process the command. + */ + printf ("\n"); + repeating = 1; + /* + * Only process the history if we have a command and + *a history. + */ + if (strlen (buffer)) + { + if (history_next && (history == history_next)) + { + /* + * Do not place the last command into the history + *if the same. + */ + if (strcmp (history_buffer[history_next - 1], buffer)) + repeating = 0; + } + else + repeating = 0; + } + if (!repeating) + { + memcpy (history_buffer[history_next], buffer, + RTEMS_COMMAND_BUFFER_SIZE); + history_pos[history_next] = pos; + if (history_next < (RTEMS_COMMAND_HISTORIES - 1)) + history_next++; + else + { + memmove (history_buffer[0], history_buffer[1], + RTEMS_COMMAND_BUFFER_SIZE * (RTEMS_COMMAND_HISTORIES - 1)); + memmove (&history_pos[0], &history_pos[1], + sizeof (history_pos[0]) * (RTEMS_COMMAND_HISTORIES - 1)); + } + } + else + { + if (history_next) + memcpy (buffer, history_buffer[history_next - 1], + RTEMS_COMMAND_BUFFER_SIZE); + } + memmove (command, buffer, RTEMS_COMMAND_BUFFER_SIZE); + return repeating; + break; + + default: + if ((pos < (RTEMS_COMMAND_BUFFER_SIZE - 1)) && + (c >= ' ') && (c <= 'z')) + { + int end; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + end = strlen (buffer); + if ((pos < end) && (end < RTEMS_COMMAND_BUFFER_SIZE)) + { + int ch, bs; + for (ch = end + 1; ch > pos; ch--) + buffer[ch] = buffer[ch - 1]; + printf (buffer + pos); + for (bs = 0; bs < (end - pos + 1); bs++) + putchar ('\b'); + } + buffer[pos++] = c; + if (pos > end) + buffer[pos] = '\0'; + putchar (c); + } + break; + } + } + } + } +} + /* * make_argv(cp): token-count - * Break up the command line in 'cp' into global argv[] and argc (return - * value). + * Break up the command line in 'cp' into global argv[] and argc (return + * value). */ int @@ -25,16 +436,16 @@ rtems_monitor_make_argv( int *argc_p, char **argv) { - int argc = 0; + int argc = 0; - while ((cp = strtok(cp, " \t\n\r"))) - { - argv[argc++] = cp; - cp = (char *) NULL; - } - argv[argc] = (char *) NULL; /* end of argv */ + while ((cp = strtok(cp, " \t\n\r"))) + { + argv[argc++] = cp; + cp = (char *) NULL; + } + argv[argc] = (char *) NULL; /* end of argv */ - return *argc_p = argc; + return *argc_p = argc; } @@ -50,34 +461,29 @@ rtems_monitor_command_read(char *command, int *argc, char **argv) { - static char monitor_prompt[32]; - - /* - * put node number in the prompt if we are multiprocessing - */ + /* + * put node number in the prompt if we are multiprocessing + */ - if (!rtems_configuration_get_user_multiprocessing_table()) - sprintf(monitor_prompt, "%s", MONITOR_PROMPT); - else if (rtems_monitor_default_node != rtems_monitor_node) - sprintf(monitor_prompt, "%d-%s-%d", rtems_monitor_node, MONITOR_PROMPT, rtems_monitor_default_node); - else - sprintf(monitor_prompt, "%d-%s", rtems_monitor_node, MONITOR_PROMPT); + if (!rtems_configuration_get_user_multiprocessing_table ()) + sprintf (monitor_prompt, "%s", MONITOR_PROMPT); + else if (rtems_monitor_default_node != rtems_monitor_node) + sprintf (monitor_prompt, "%d-%s-%d", rtems_monitor_node, + MONITOR_PROMPT, rtems_monitor_default_node); + else + sprintf (monitor_prompt, "%d-%s", rtems_monitor_node, MONITOR_PROMPT); #ifdef RTEMS_UNIX - /* RTEMS on unix gets so many interrupt system calls this is hosed */ - printf("%s> ", monitor_prompt); - fflush(stdout); - while (gets(command) == (char *) 0) - ; + /* RTEMS on unix gets so many interrupt system calls this is hosed */ + printf ("%s> ", monitor_prompt); + fflush (stdout); + while (gets(command) == (char *) 0) + ; #else - do - { - printf("%s> ", monitor_prompt); - fflush(stdout); - } while (gets(command) == (char *) 0); + rtems_monitor_line_editor (command); #endif - return rtems_monitor_make_argv(command, argc, argv); + return rtems_monitor_make_argv (command, argc, argv); } /* @@ -92,74 +498,177 @@ rtems_monitor_command_lookup( char **argv ) { - rtems_monitor_command_entry_t *p; - rtems_monitor_command_entry_t *abbreviated_match = 0; - int abbreviated_matches = 0; - char *command; - int command_length; + char *command; - command = argv[0]; + command = argv[0]; - if ((table == 0) || (command == 0)) - goto failed; + if ((table == 0) || (command == 0)) + return 0; - command_length = strlen(command); + while (table) + { + if (table->command) + { + if (STREQ (command, table->command)) /* exact match */ + { + if (table->command_function == 0) + return 0; + return table; + } + } + table = table->next; + } - for (p = table; p->command; p++) - if (STREQ(command, p->command)) /* exact match */ - goto done; - else if (STRNEQ(command, p->command, command_length)) - { - abbreviated_matches++; - abbreviated_match = p; - } + return 0; +} - /* no perfect match; is there a non-ambigous abbreviated match? */ - if ( ! abbreviated_match) - { - printf("Unrecognized command '%s'; try 'help'\n", command); - goto failed; - } +void +rtems_monitor_show_help ( + rtems_monitor_command_entry_t *help_cmd, + int max_cmd_len +) +{ +#define MAX_HELP_LINE_LENGTH (75 - max_cmd_len - 2) + + if (help_cmd && help_cmd->command) + { + const char *help = help_cmd->usage; + int help_len = strlen (help); + int spaces = max_cmd_len - strlen (help_cmd->command); + int show_this_line = 0; + int line_one = 1; + int c; - if (abbreviated_matches > 1) + printf ("%s", help_cmd->command); + + if (help_len == 0) { - printf("Command '%s' is ambiguous; try 'help'\n", command); - goto failed; + printf (" - No help associated.\n"); + return; } - - p = abbreviated_match; + + while (help_len) + { + printf ("%*c", spaces, ' '); + + if (line_one) + printf (" - "); -done: - if (p->command_function == 0) - goto failed; - return p; + spaces = max_cmd_len + 2; + line_one = 0; -failed: - return 0; + /* + * See if greater then the line length if so, work back + * from the end for a space, tab or lf or cr. + */ + + if (help_len > MAX_HELP_LINE_LENGTH) + { + for (show_this_line = MAX_HELP_LINE_LENGTH - 1; + show_this_line; + show_this_line--) + if ((help[show_this_line] == ' ') || + (help[show_this_line] == '\n') || + (help[show_this_line] == '\r')) + break; + + /* + * If show_this_line is 0, it is a very long word !! + */ + + if (show_this_line == 0) + show_this_line = MAX_HELP_LINE_LENGTH - 1; + } + else + show_this_line = help_len; + + for (c = 0; c < show_this_line; c++) + if ((help[c] == '\r') || (help[c] == '\n')) + show_this_line = c; + else + putchar (help[c]); + + printf ("\n"); + + help += show_this_line; + help_len -= show_this_line; + + /* + * Move past the line feeds or what ever else is being skipped. + */ + + while (help_len) + { + if ((*help != '\r') && (*help != '\n')) + break; + + if (*help != ' ') + { + help++; + help_len--; + break; + } + help++; + help_len--; + } + } + } } void -rtems_monitor_command_usage(rtems_monitor_command_entry_t *table, - char *command_string) +rtems_monitor_command_usage( + rtems_monitor_command_entry_t *table, + char *command_string +) { - rtems_monitor_command_entry_t *help = 0; - char *help_command_argv[2]; + rtems_monitor_command_entry_t *command = table; + int max_cmd_len = 0; - /* if first entry in table is a usage, then print it out */ - if (command_string == 0) - { - if (STREQ(table->command, "--usage--") && table->usage) - help = table; - } + /* if first entry in table is a usage, then print it out */ + + if (command_string && (*command_string != '\0')) + { + char *argv[2]; + + argv[0] = command_string; + argv[1] = 0; + + command = rtems_monitor_command_lookup (table, 1, argv); + + if (command) + rtems_monitor_show_help (command, strlen (command_string)); else - { - help_command_argv[0] = command_string; - help_command_argv[1] = 0; - help = rtems_monitor_command_lookup(table, 1, help_command_argv); - } + printf ("Unrecognised command; try just 'help'\n"); + return; + } + + /* + * Find the largest command size. + */ + + while (command) + { + int len = strlen (command->command); + + if (len > max_cmd_len) + max_cmd_len = len; - if (help) - printf("%s\n", help->usage); + command = command->next; + } + + max_cmd_len++; + + command = table; + + /* + * Now some nice formatting for the help. + */ + + while (command) + { + rtems_monitor_show_help (command, max_cmd_len); + command = command->next; + } } @@ -171,16 +680,16 @@ rtems_monitor_help_cmd( boolean verbose ) { - int arg; - rtems_monitor_command_entry_t *command; + int arg; + rtems_monitor_command_entry_t *command; - command = (rtems_monitor_command_entry_t *) command_arg; + command = (rtems_monitor_command_entry_t *) command_arg; - if (argc == 1) - rtems_monitor_command_usage(command, 0); - else - { - for (arg=1; argv[arg]; arg++) - rtems_monitor_command_usage(command, argv[arg]); - } + if (argc == 1) + rtems_monitor_command_usage(command, 0); + else + { + for (arg = 1; argv[arg]; arg++) + rtems_monitor_command_usage(command, argv[arg]); + } } diff --git a/c/src/libmisc/monitor/mon-monitor.c b/c/src/libmisc/monitor/mon-monitor.c index 289425d8e4..478e904feb 100644 --- a/c/src/libmisc/monitor/mon-monitor.c +++ b/c/src/libmisc/monitor/mon-monitor.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -53,187 +54,175 @@ unsigned32 rtems_monitor_default_node; /* current default for commands */ rtems_symbol_table_t *rtems_monitor_symbols; +/* + * User registered commands. + */ + +rtems_monitor_command_entry_t rtems_registered_commands; + /* * The top-level commands */ rtems_monitor_command_entry_t rtems_monitor_commands[] = { - { "--usage--", - "\n" - "RTEMS monitor\n" - "\n" - "Commands (may be abbreviated)\n" - "\n" - " help -- get this message or command specific help\n" - " pause -- pause monitor for a specified number of ticks\n" - " exit -- invoke a fatal RTEMS error\n" - " symbol -- show entries from symbol table\n" - " continue -- put monitor to sleep waiting for explicit wakeup\n" - " config -- show system configuration\n" - " itask -- list init tasks\n" - " mpci -- list mpci config\n" - " task -- show task information\n" - " queue -- show message queue information\n" - " extension -- user extensions\n" - " driver -- show information about named drivers\n" - " dname -- show information about named drivers\n" - " object -- generic object information\n" - " node -- specify default node for commands that take id's\n" -#ifdef CPU_INVOKE_DEBUGGER - " debugger -- invoke system debugger\n" -#endif - , - 0, - 0, - (unsigned32) rtems_monitor_commands, - }, { "config", - "config\n" - " Show the system configuration.\n", + "Show the system configuration.", 0, rtems_monitor_object_cmd, RTEMS_MONITOR_OBJECT_CONFIG, + &rtems_monitor_commands[1], }, { "itask", - "itask\n" - " List init tasks for the system\n", + "List init tasks for the system", 0, rtems_monitor_object_cmd, RTEMS_MONITOR_OBJECT_INIT_TASK, + &rtems_monitor_commands[2], }, { "mpci", - "mpci\n" - " Show the MPCI system configuration, if configured.\n", + "Show the MPCI system configuration, if configured.", 0, rtems_monitor_object_cmd, RTEMS_MONITOR_OBJECT_MPCI, + &rtems_monitor_commands[3], }, { "pause", - "pause [ticks]\n" - " monitor goes to \"sleep\" for specified ticks (default is 1)\n" - " monitor will resume at end of period or if explicitly awakened\n", + "Monitor goes to \"sleep\" for specified ticks (default is 1). " + "Monitor will resume at end of period or if explicitly awakened\n" + " pause [ticks]", 0, rtems_monitor_pause_cmd, 0, + &rtems_monitor_commands[4], }, { "continue", - "continue\n" - " put the monitor to sleep waiting for an explicit wakeup from the\n" - " program running.\n", + "Put the monitor to sleep waiting for an explicit wakeup from the " + "program running.\n", 0, rtems_monitor_continue_cmd, 0, + &rtems_monitor_commands[5], }, { "go", - "go\n" - " Alias for 'continue'\n", + "Alias for 'continue'", 0, rtems_monitor_continue_cmd, 0, + &rtems_monitor_commands[6], }, { "node", - "node [ node number ]\n" - " Specify default node number for commands that take id's\n", + "Specify default node number for commands that take id's.\n" + " node [ node number ]", 0, rtems_monitor_node_cmd, 0, + &rtems_monitor_commands[7], }, { "symbol", - "symbol [ symbolname [symbolname ... ] ]\n" - " display value associated with specified symbol.\n" - " Defaults to displaying all known symbols.\n", + "Display value associated with specified symbol. " + "Defaults to displaying all known symbols.\n" + " symbol [ symbolname [symbolname ... ] ]", 0, rtems_monitor_symbol_cmd, (unsigned32) &rtems_monitor_symbols, + &rtems_monitor_commands[8], }, { "extension", - "extension [id [id ...] ]\n" - " display information about specified extensions.\n" - " Default is to display information about all extensions on this node\n", + "Display information about specified extensions. " + "Default is to display information about all extensions on this node.\n" + " extension [id [id ...] ]", 0, rtems_monitor_object_cmd, RTEMS_MONITOR_OBJECT_EXTENSION, + &rtems_monitor_commands[9], }, { "task", - "task [id [id ...] ]\n" - " display information about the specified tasks.\n" - " Default is to display information about all tasks on this node\n", + "Display information about the specified tasks. " + "Default is to display information about all tasks on this node.\n" + " task [id [id ...] ]", 0, rtems_monitor_object_cmd, RTEMS_MONITOR_OBJECT_TASK, + &rtems_monitor_commands[10], }, { "queue", - "queue [id [id ... ] ]\n" - " display information about the specified message queues\n" - " Default is to display information about all queues on this node\n", + "Display information about the specified message queues. " + "Default is to display information about all queues on this node.\n" + " queue [id [id ... ] ]", 0, rtems_monitor_object_cmd, RTEMS_MONITOR_OBJECT_QUEUE, + &rtems_monitor_commands[11], }, { "object", - "object [id [id ...] ]\n" - " display information about specified RTEMS objects.\n" - " Object id's must include 'type' information.\n" - " (which may normally be defaulted)\n", + "Display information about specified RTEMS objects. " + "Object id's must include 'type' information. " + "(which may normally be defaulted)\n" + " object [id [id ...] ]", 0, rtems_monitor_object_cmd, RTEMS_MONITOR_OBJECT_INVALID, + &rtems_monitor_commands[12], }, { "driver", - "driver [ major [ major ... ] ]\n" - " Display the RTEMS device driver table.\n", + "Display the RTEMS device driver table.\n" + " driver [ major [ major ... ] ]", 0, rtems_monitor_object_cmd, RTEMS_MONITOR_OBJECT_DRIVER, + &rtems_monitor_commands[13], }, { "dname", - "dname\n" - " Displays information about named drivers.\n", + "Displays information about named drivers.\n", 0, rtems_monitor_object_cmd, RTEMS_MONITOR_OBJECT_DNAME, + &rtems_monitor_commands[14], }, { "exit", - "exit [status]\n" - " Invoke 'rtems_fatal_error_occurred' with 'status'\n" - " (default is RTEMS_SUCCESSFUL)\n", + "Invoke 'rtems_fatal_error_occurred' with 'status' " + "(default is RTEMS_SUCCESSFUL)\n" + " exit [status]", 0, rtems_monitor_fatal_cmd, RTEMS_SUCCESSFUL, + &rtems_monitor_commands[15], }, { "fatal", - "fatal [status]\n" - " 'exit' with fatal error; default error is RTEMS_TASK_EXITTED\n", + "'exit' with fatal error; default error is RTEMS_TASK_EXITTED\n" + " fatal [status]", 0, rtems_monitor_fatal_cmd, RTEMS_TASK_EXITTED, /* exit value */ + &rtems_monitor_commands[16], }, { "quit", - "quit [status]\n" - " Alias for 'exit'\n", + "Alias for 'exit'\n", 0, rtems_monitor_fatal_cmd, RTEMS_SUCCESSFUL, /* exit value */ + &rtems_monitor_commands[17], }, { "help", - "help [ command [ command ] ]\n" - " provide information about commands\n" - " Default is show basic command summary.\n", + "Provide information about commands. " + "Default is show basic command summary.\n" + "help [ command [ command ] ]", 0, rtems_monitor_help_cmd, (unsigned32) rtems_monitor_commands, + &rtems_monitor_commands[18], }, #ifdef CPU_INVOKE_DEBUGGER { "debugger", - "debugger\n" - " Enter the debugger, if possible.\n" - " A continue from the debugger will return to the monitor.\n", + "Enter the debugger, if possible. " + "A continue from the debugger will return to the monitor.\n", 0, rtems_monitor_debugger_cmd, 0, + &rtems_monitor_commands[19], }, #endif - { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, &rtems_registered_commands }, }; @@ -418,6 +407,56 @@ done: return; } +/* + * User registered commands. + */ + +int +rtems_monitor_insert_cmd ( + rtems_monitor_command_entry_t *command +) +{ + rtems_monitor_command_entry_t *p = rtems_registered_commands.next; + + command->next = 0; + + if (rtems_registered_commands.next) + { + for (; p->next; p = p->next) + { + if (STREQ(command->command, p->command)) + return 0; + } + p->next = command; + } + else + rtems_registered_commands.next = command; + + return 1; +} + +int +rtems_monitor_erase_cmd ( + rtems_monitor_command_entry_t *command +) +{ + rtems_monitor_command_entry_t *p; + rtems_monitor_command_entry_t **p_prev = &rtems_registered_commands.next; + + if (rtems_registered_commands.next) + { + for (p = rtems_registered_commands.next; p->next; p = p->next) + { + if (STREQ(command->command, p->command)) + { + *p_prev = p->next; + return 1; + } + p_prev = &p->next; + } + } + return 0; +} /* * Main monitor command loop @@ -435,7 +474,39 @@ rtems_monitor_task( int argc; char *argv[64]; boolean verbose = FALSE; + struct termios term; + /* + * Make the stdin stream characte not line based. + */ + + if (tcgetattr (STDIN_FILENO, &term) < 0) + { + printf("rtems-monitor: cannot get terminal attributes.\n"); + } + else + { + /* + * No echo, no canonical processing. + */ + + term.c_lflag &= ~(ECHO | ICANON | IEXTEN); + + /* + * No sigint on BREAK, CR-to-NL off, input parity off, + * don't strip 8th bit on input, output flow control off + */ + + term.c_lflag &= ~(INPCK | ISTRIP | IXON); + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + + if (tcsetattr (STDIN_FILENO, TCSANOW, &term) < 0) + { + printf("cannot set terminal attributes\n"); + } + } + if (monitor_flags & RTEMS_MONITOR_SUSPEND) (void) rtems_monitor_suspend(RTEMS_NO_TIMEOUT); @@ -453,7 +524,11 @@ rtems_monitor_task( if ((command = rtems_monitor_command_lookup(rtems_monitor_commands, argc, argv)) == 0) + { + /* no command */ + printf("Unrecognised command; try 'help'\n"); continue; + } command->command_function(argc, argv, command->command_arg, verbose); diff --git a/c/src/libmisc/monitor/monitor.h b/c/src/libmisc/monitor/monitor.h index a9584808f3..ef0e099ac7 100644 --- a/c/src/libmisc/monitor/monitor.h +++ b/c/src/libmisc/monitor/monitor.h @@ -294,9 +294,9 @@ struct rtems_monitor_command_entry_s { char *usage; /* usage string for the command */ unsigned32 arguments_required; /* # of required args */ rtems_monitor_command_function_t command_function; - /* Some argument for the command */ - unsigned32 command_arg; + unsigned32 command_arg; + struct rtems_monitor_command_entry_s *next; }; typedef void *(*rtems_monitor_object_next_fn)(void *, void *, rtems_id *); @@ -325,6 +325,9 @@ void rtems_monitor_continue_cmd(int, char **, unsigned32, boolean); void rtems_monitor_debugger_cmd(int, char **, unsigned32, boolean); void rtems_monitor_node_cmd(int, char **, unsigned32, boolean); void rtems_monitor_symbols_loadup(void); +int rtems_monitor_insert_cmd(rtems_monitor_command_entry_t *); +int rtems_monitor_erase_cmd(rtems_monitor_command_entry_t *); + void rtems_monitor_task(rtems_task_argument); /* server.c */ -- cgit v1.2.3