diff options
author | Randall Spangler <rspangler@chromium.org> | 2011-12-07 18:51:09 +0000 |
---|---|---|
committer | Vincent Palatin <vpalatin@chromium.org> | 2011-12-07 19:10:02 +0000 |
commit | bdf7da5b082f6d18dd27f1e5d8cca0b12154a28c (patch) | |
tree | 6f14312a6cc70d056efc2bede8728c0868266719 /common/console.c | |
parent | abe5786058f4b60dc6d30e7d7c964aae850caa1f (diff) | |
download | chrome-ec-bdf7da5b082f6d18dd27f1e5d8cca0b12154a28c.tar.gz |
Initial sources import 1/3
source files mainly done by Randall.
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Change-Id: Iaff83a842b17f3350fb6f2a3f1597ad4c29bd12a
Diffstat (limited to 'common/console.c')
-rw-r--r-- | common/console.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/common/console.c b/common/console.c new file mode 100644 index 0000000000..bc558f5cf4 --- /dev/null +++ b/common/console.c @@ -0,0 +1,207 @@ +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Console module for Chrome EC */ + +#include "console.h" +#include "task.h" +#include "uart.h" +#include "registers.h" +#include "util.h" + +#define MAX_COMMAND_GROUPS 20 +#define MAX_ARGS_PER_COMMAND 10 + +#define PROMPT "> " + +static const struct console_group *group_list[MAX_COMMAND_GROUPS]; +static int group_count = 0; + + +void console_has_input(void) +{ + /* Wake up the console task */ + task_send_msg(TASK_ID_CONSOLE, TASK_ID_CONSOLE, 0); +} + + +int console_register_commands(const struct console_group *group) +{ + if (group_count >= MAX_COMMAND_GROUPS) + return EC_ERROR_OVERFLOW; + + group_list[group_count++] = group; + return EC_SUCCESS; +} + + +/* Splits a line of input into words. Stores the count of words in + * <argc>. Stores pointers to the words in <argv>, which must be at + * least <max_argc> long. If more than <max_argc> words are found, + * discards the excess and returns EC_ERROR_OVERFLOW. */ +int split_words(char *input, int max_argc, int *argc, char **argv) +{ + char *c; + int in_word = 0; + + /* Parse input into words */ + *argc = 0; + for (c = input; *c; c++) { + if (isspace(*c)) { + if (in_word) { + /* Ending a word */ + *c = '\0'; + ++*argc; + in_word = 0; + } + } else if (*c == '#') { + /* After the hash sign is comment, ignored. + * TODO: Need more logic to suuport escaping. */ + break; + } else { + if (!in_word) { + /* Starting a new word */ + if (*argc >= max_argc) + return EC_ERROR_OVERFLOW; + + argv[*argc] = c; + in_word = 1; + } + } + } + return EC_SUCCESS; +} + + +/* Finds a command by name. Returns the command structure, or NULL if + * no match found. */ +const struct console_command *find_command(char *name) +{ + const struct console_command *cmd; + int c, g; + + /* Find the command in the command groups */ + for (g = 0; g < group_count; g++) { + cmd = group_list[g]->commands; + for (c = group_list[g]->command_count; c > 0; c--, cmd++) { + if (!strcasecmp(name, cmd->name)) + return cmd; + } + } + + return NULL; +} + + +/* Handles a line of input containing a single command. + * + * Modifies the input string during parsing. */ +static int handle_command(char *input) +{ + const struct console_command *cmd; + char *argv[MAX_ARGS_PER_COMMAND]; + int argc = 0; + + /* Split input into words. Ignore words past our limit. */ + split_words(input, MAX_ARGS_PER_COMMAND, &argc, argv); + + /* If no command, nothing to do */ + if (!argc) + return EC_SUCCESS; + + cmd = find_command(argv[0]); + if (cmd) + return cmd->handler(argc, argv); + + uart_printf("Command '%s' not found.\n", argv[0]); + return EC_ERROR_UNKNOWN; +} + + +static char last_input[80]; +static char input_buf[80]; + +/* handle a console command */ +void console_process(void) +{ + int rv; + + /* Process all the pending commands. Need to do this all at once + * since our interrupt may have been triggered multiple times. */ + /* TODO: Go to sleep briefly between commands to give lower + * priority tasks a chance to run? */ + while (uart_peek('\n') >= 0) { + uart_gets(input_buf, sizeof(input_buf)); + + /* "." repeats the last command, if any */ + if (!strcasecmp(input_buf, ".\n")) + strzcpy(input_buf, last_input, sizeof(input_buf)); + else if (!isspace(*input_buf)) + strzcpy(last_input, input_buf, sizeof(last_input)); + + rv = handle_command(input_buf); + if (rv != EC_SUCCESS) + uart_printf("Command returned error %d\n", rv); + uart_puts(PROMPT); + } +} + +void console_task(void) +{ + console_init(); + + while (1) { + console_process(); + /* wait for the next command message */ + task_wait_msg(-1); + } +} + +/*****************************************************************************/ +/* Console commands */ + +/* Command handler - prints help. */ +static int command_help(int argc, char **argv) +{ + const struct console_command *cmd; + int c, g; + + uart_puts("Known commands:\n"); + + for (g = 0; g < group_count; g++) { + cmd = group_list[g]->commands; + uart_printf("Group %s:\n", group_list[g]->group_name); + for (c = group_list[g]->command_count; c > 0; c--, cmd++) + uart_printf(" %s\n", cmd->name); + /* Generates enough output to overflow the buffer */ + uart_flush_output(); + } + + uart_puts("'.' repeats the last command.\n"); + + return EC_SUCCESS; +} + +static const struct console_command console_commands[] = { + {"help", command_help}, + {"?", command_help}, +}; +static const struct console_group command_group = { + "Console", console_commands, ARRAY_SIZE(console_commands) +}; + +/*****************************************************************************/ +/* Initialization */ + +int console_init(void) +{ + *last_input = '\0'; + *input_buf = '\0'; + uart_set_console_mode(1); + uart_printf("Console is enabled; type HELP for help.\n"); + uart_puts(PROMPT); + /* Register our internal commands */ + return console_register_commands(&command_group); +} |