Introduce dynamically registered shell command sets
Commands are part of a single array, which means that their definition is static. However, different apps in the same source tree may reasonably want to add to the command set (perhaps even shadow existing commands), which would make for awkward code. Instead, allow dynamic registration/deregistration of command sets at runtime. This keeps the data overhead low (two pointers per enabled command set).
This commit is contained in:
parent
1a95aad7a7
commit
45b0241f94
@ -45,6 +45,7 @@
|
|||||||
#include "contiki.h"
|
#include "contiki.h"
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
#include "shell-commands.h"
|
#include "shell-commands.h"
|
||||||
|
#include "lib/list.h"
|
||||||
#include "sys/log.h"
|
#include "sys/log.h"
|
||||||
#include "dev/watchdog.h"
|
#include "dev/watchdog.h"
|
||||||
#include "net/ipv6/uip.h"
|
#include "net/ipv6/uip.h"
|
||||||
@ -76,7 +77,8 @@ static uint16_t curr_ping_datalen;
|
|||||||
#if TSCH_WITH_SIXTOP
|
#if TSCH_WITH_SIXTOP
|
||||||
static shell_command_6top_sub_cmd_t sixtop_sub_cmd = NULL;
|
static shell_command_6top_sub_cmd_t sixtop_sub_cmd = NULL;
|
||||||
#endif /* TSCH_WITH_SIXTOP */
|
#endif /* TSCH_WITH_SIXTOP */
|
||||||
|
static struct shell_command_set_t builtin_shell_command_set;
|
||||||
|
LIST(shell_command_sets);
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static const char *
|
static const char *
|
||||||
ds6_nbr_state_to_str(uint8_t state)
|
ds6_nbr_state_to_str(uint8_t state)
|
||||||
@ -345,15 +347,16 @@ PT_THREAD(cmd_log(struct pt *pt, shell_output_func output, char *args))
|
|||||||
static
|
static
|
||||||
PT_THREAD(cmd_help(struct pt *pt, shell_output_func output, char *args))
|
PT_THREAD(cmd_help(struct pt *pt, shell_output_func output, char *args))
|
||||||
{
|
{
|
||||||
const struct shell_command_t *cmd_ptr;
|
struct shell_command_set_t *set;
|
||||||
|
const struct shell_command_t *cmd;
|
||||||
PT_BEGIN(pt);
|
PT_BEGIN(pt);
|
||||||
|
|
||||||
SHELL_OUTPUT(output, "Available commands:\n");
|
SHELL_OUTPUT(output, "Available commands:\n");
|
||||||
cmd_ptr = shell_commands;
|
/* Note: we explicitly don't expend any code space to deal with shadowing */
|
||||||
while(cmd_ptr->name != NULL) {
|
for(set = list_head(shell_command_sets); set != NULL; set = list_item_next(set)) {
|
||||||
SHELL_OUTPUT(output, "%s\n", cmd_ptr->help);
|
for(cmd = set->commands; cmd->name != NULL; ++cmd) {
|
||||||
cmd_ptr++;
|
SHELL_OUTPUT(output, "%s\n", cmd->help);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PT_END(pt);
|
PT_END(pt);
|
||||||
@ -729,12 +732,48 @@ PT_THREAD(cmd_6top(struct pt *pt, shell_output_func output, char *args))
|
|||||||
void
|
void
|
||||||
shell_commands_init(void)
|
shell_commands_init(void)
|
||||||
{
|
{
|
||||||
|
list_init(shell_command_sets);
|
||||||
|
list_add(shell_command_sets, &builtin_shell_command_set);
|
||||||
/* Set up Ping Reply callback */
|
/* Set up Ping Reply callback */
|
||||||
uip_icmp6_echo_reply_callback_add(&echo_reply_notification,
|
uip_icmp6_echo_reply_callback_add(&echo_reply_notification,
|
||||||
echo_reply_handler);
|
echo_reply_handler);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
const struct shell_command_t shell_commands[] = {
|
void
|
||||||
|
shell_command_set_register(struct shell_command_set_t *set)
|
||||||
|
{
|
||||||
|
list_push(shell_command_sets, set);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
shell_command_set_deregister(struct shell_command_set_t *set)
|
||||||
|
{
|
||||||
|
if(!list_contains(shell_command_sets, set)) {
|
||||||
|
return !0;
|
||||||
|
}
|
||||||
|
list_remove(shell_command_sets, set);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
const struct shell_command_t *
|
||||||
|
shell_command_lookup(const char *name)
|
||||||
|
{
|
||||||
|
struct shell_command_set_t *set;
|
||||||
|
const struct shell_command_t *cmd;
|
||||||
|
|
||||||
|
for(set = list_head(shell_command_sets);
|
||||||
|
set != NULL;
|
||||||
|
set = list_item_next(set)) {
|
||||||
|
for(cmd = set->commands; cmd->name != NULL; ++cmd) {
|
||||||
|
if(!strcmp(cmd->name, name)) {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
const struct shell_command_t builtin_shell_commands[] = {
|
||||||
{ "help", cmd_help, "'> help': Shows this help" },
|
{ "help", cmd_help, "'> help': Shows this help" },
|
||||||
{ "reboot", cmd_reboot, "'> reboot': Reboot the board by watchdog_reboot()" },
|
{ "reboot", cmd_reboot, "'> reboot': Reboot the board by watchdog_reboot()" },
|
||||||
{ "ip-addr", cmd_ipaddr, "'> ip-addr': Shows all IPv6 addresses" },
|
{ "ip-addr", cmd_ipaddr, "'> ip-addr': Shows all IPv6 addresses" },
|
||||||
@ -765,4 +804,8 @@ const struct shell_command_t shell_commands[] = {
|
|||||||
{ NULL, NULL, NULL },
|
{ NULL, NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct shell_command_set_t builtin_shell_command_set = {
|
||||||
|
.next = NULL,
|
||||||
|
.commands = builtin_shell_commands,
|
||||||
|
};
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -53,8 +53,14 @@ struct shell_command_t {
|
|||||||
const char *help;
|
const char *help;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The set of supported commands */
|
struct shell_command_set_t {
|
||||||
extern const struct shell_command_t shell_commands[];
|
struct shell_command_set_t *next;
|
||||||
|
const struct shell_command_t *const commands;
|
||||||
|
};
|
||||||
|
|
||||||
|
void shell_command_set_register(struct shell_command_set_t *);
|
||||||
|
int shell_command_set_deregister(struct shell_command_set_t *);
|
||||||
|
const struct shell_command_t *shell_command_lookup(const char *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes Shell-commands module
|
* Initializes Shell-commands module
|
||||||
|
@ -89,7 +89,7 @@ output_prompt(shell_output_func output)
|
|||||||
PT_THREAD(shell_input(struct pt *pt, shell_output_func output, const char *cmd))
|
PT_THREAD(shell_input(struct pt *pt, shell_output_func output, const char *cmd))
|
||||||
{
|
{
|
||||||
static char *args;
|
static char *args;
|
||||||
static const struct shell_command_t *cmd_ptr;
|
static const struct shell_command_t *cmd_descr = NULL;
|
||||||
|
|
||||||
PT_BEGIN(pt);
|
PT_BEGIN(pt);
|
||||||
|
|
||||||
@ -105,20 +105,14 @@ PT_THREAD(shell_input(struct pt *pt, shell_output_func output, const char *cmd))
|
|||||||
args++;
|
args++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lookup for command */
|
cmd_descr = shell_command_lookup(cmd);
|
||||||
cmd_ptr = shell_commands;
|
if(cmd_descr != NULL) {
|
||||||
while(cmd_ptr->name != NULL) {
|
|
||||||
if(strcmp(cmd, cmd_ptr->name) == 0) {
|
|
||||||
static struct pt cmd_pt;
|
static struct pt cmd_pt;
|
||||||
PT_SPAWN(pt, &cmd_pt, cmd_ptr->func(&cmd_pt, output, args));
|
PT_SPAWN(pt, &cmd_pt, cmd_descr->func(&cmd_pt, output, args));
|
||||||
goto done;
|
} else {
|
||||||
}
|
|
||||||
cmd_ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHELL_OUTPUT(output, "Command not found. Type 'help' for a list of commands\n");
|
SHELL_OUTPUT(output, "Command not found. Type 'help' for a list of commands\n");
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
|
||||||
output_prompt(output);
|
output_prompt(output);
|
||||||
PT_END(pt);
|
PT_END(pt);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user