Files
OpenCellular/common/console.c
Randall Spangler 3e14c8f8be Split console output into its own module
No code changes, just rearranging source in preparation for an
experiment to see how much the binary shrinks if we disable the
interactive console.

BUG=none
TEST=none

Change-Id: Ie21f1b3dcd04272e80fd40b2ed54d1eaf7fb1cdf
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/25232
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
2012-06-13 13:17:33 -07:00

231 lines
5.1 KiB
C

/* Copyright (c) 2012 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 "link_defs.h"
#include "task.h"
#include "uart.h"
#include "util.h"
#define MAX_ARGS_PER_COMMAND 10
#define PROMPT "> "
static char input_buf[80]; /* Current console command line */
/* 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. */
static 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;
}
/* Find a command by name. Returns the command structure, or NULL if no match
* found. */
static const struct console_command *find_command(char *name)
{
const struct console_command *cmd, *match = NULL;
int match_length = strlen(name);
for (cmd = __cmds; cmd < __cmds_end; cmd++) {
if (!strncasecmp(name, cmd->name, match_length)) {
if (match)
return NULL;
match = cmd;
}
}
return match;
}
/* Handle 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;
int rv;
/* 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) {
ccprintf("Command '%s' not found or ambiguous.\n", argv[0]);
return EC_ERROR_UNKNOWN;
}
rv = cmd->handler(argc, argv);
if (rv == EC_SUCCESS)
return rv;
/* Print more info for errors */
if (rv == EC_ERROR_INVAL)
ccputs("Command usage/param invalid.\n");
else if (rv == EC_ERROR_PARAM_COUNT)
ccputs("Wrong number of params.\n");
else if (rv >= EC_ERROR_PARAM1 && rv <= EC_ERROR_PARAM9)
ccprintf("Parameter %d invalid.\n", rv - EC_ERROR_PARAM1 + 1);
else if (rv != EC_SUCCESS) {
ccprintf("Command returned error %d\n", rv);
return rv;
}
#ifdef CONFIG_CONSOLE_CMDHELP
if (cmd->argdesc)
ccprintf("Usage: %s %s\n", cmd->name, cmd->argdesc);
#endif
return rv;
}
static int console_init(void)
{
*input_buf = '\0';
uart_set_console_mode(1);
ccprintf("Console is enabled; type HELP for help.\n");
ccputs(PROMPT);
/* TODO: restore channel list from EEPROM */
return EC_SUCCESS;
}
/* handle a console command */
static void console_process(void)
{
/* Process all the pending commands. Need to do this all at once
* since our interrupt may have been triggered multiple times. */
while (uart_peek('\n') >= 0) {
uart_gets(input_buf, sizeof(input_buf));
handle_command(input_buf);
ccputs(PROMPT);
}
}
void console_has_input(void)
{
/* Wake up the console task */
task_wake(TASK_ID_CONSOLE);
}
void console_task(void)
{
console_init();
while (1) {
console_process();
/* Wait for the next command message */
task_wait_event(-1);
}
}
/*****************************************************************************/
/* Console commands */
/* Command handler - prints help. */
static int command_help(int argc, char **argv)
{
const int ncmds = __cmds_end - __cmds;
const int cols = 5; /* printing in five columns */
const int rows = (ncmds + cols - 1) / cols;
int i, j;
#ifdef CONFIG_CONSOLE_CMDHELP
if (argc == 2) {
const struct console_command *cmd;
if (!strcasecmp(argv[1], "list")) {
ccputs("Known commands:\n");
for (i = 0; i < ncmds; i++) {
ccprintf(" %-15s%s\n",
__cmds[i].name, __cmds[i].shorthelp);
cflush();
}
ccputs("HELP CMD = help on CMD.\n");
return EC_SUCCESS;
}
cmd = find_command(argv[1]);
if (!cmd) {
ccprintf("Command '%s' not found or ambiguous.\n",
argv[1]);
return EC_ERROR_UNKNOWN;
}
ccprintf("Usage: %s %s\n", cmd->name,
(cmd->argdesc ? cmd->argdesc : ""));
if (cmd->shorthelp)
ccprintf("%s\n", cmd->shorthelp);
return EC_SUCCESS;
}
#endif
ccputs("Known commands:\n");
for (i = 0; i < rows; i++) {
ccputs(" ");
for (j = 0; j < cols; j++) {
int index = j * rows + i;
if (index >= ncmds)
break;
ccprintf("%-15s", __cmds[index].name);
}
ccputs("\n");
cflush();
}
#ifdef CONFIG_CONSOLE_CMDHELP
ccputs("HELP LIST = more info; ");
ccputs("HELP CMD = help on CMD.\n");
#endif
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(help, command_help,
"[ list | <name> ]",
"Print command help",
NULL);