Shell building C-library for STM32 and MSP430G2553 MCUs
1. Introduction
“libshell” is part of “libemb“. It provides the environment needed to build interactive (remote-) shells. It helps with defining commands and callback handlers as well as with the command and argument parsing. The library is not HW dependend and it has no dependencies to other “libemb” libraries.
For detailed building instructions see instructions for “libemb”
2. Hardware Setup
No special hardware setup is required. You may consider using “libshell” together with “libconio”, in which case you may want to connect a USB-to-serial converter to your MCU (see “libconio” and “libserial” HOWTOs for more details).
3. Including libshell Headers
To use “libshell” functionality add the following include to your sources:
#include <libemb/shell/shell.h>
4. Linking libshell Library
To link against “libshell”, add the following to your linker options:
-lshell
5. Initializing the Hardware
For “libshell”, no hardware initialization is needed.
6. Define Shell Commands
The core of a shell are the commands it provides. Thus, “libshell” offers a simple way to define commands with description and a callback handler for command processing.
1. Shell Command Struct
The struct used to define commands is called “shell_cmds”. Each entry for a new command must be provided with the following attributes:
| Attribute | Description |
| Command name “cmd” | used to identify the command |
| Command description “desc” | used to describe your command e.g. when user requests help |
| Command callback handler “func” | function to execute for that command |
The example below shows the definition of the two shell commands “h” and “argt”:
shell_cmds my_shell_cmds = {
.count = 2,
.cmds = {
{
.cmd = "h",
.desc = "list available commands",
.func = shell_cmd_help,
},
{
.cmd = "argt",
.desc = "print back given arguments",
.func = shell_cmd_argt,
},
},
};
Note: to later on know the total number of commands defined, “count” has to be set to the correct number.
As you can see in the example, the struct does not store information about parameters taken by an argument. Each callback handler is provided with the arguments given to a command, and the handler function itself has then later on to decide what to do if to many, to less or wrong arguments are given.
7. Write a Callback Handler
A callback handler for a shell command must have the following format:
int (*func)(shell_cmd_args *args);
The “shell_cmd_args” parameter represents the arguments given for the command.
The callback handler for our example command “h” could look something like this (we assume it used none of the given arguments):
int shell_cmd_help(shell_cmd_args *args)
{
// OPTIONAL: perform check on given arguments ...
// OPTIONAL: convert arguments (e.g. to integer)
int i;
for(i = 0; i < rshell_cmds.count; i++) {
cio_printf("%s, %s\n\r", rshell_cmds.cmds[i].cmd), rshell_cmds.cmds[i].desc);
}
cio_print((char *)"OK\n\r");
return 0;
}
And the callback handler for our example command “argt” could look something like this (we assume all given arguments are relevant):
int shell_cmd_argt(shell_cmd_args *args)
{
// OPTIONAL: perform check on given arguments ...
int i;
cio_print((char *)"OK\n\rargs given:\n\r");
for(i = 0; i < args->count; i++) {
cio_printf(" - %s\n\r", args->args[i].val);
}
return 0;
}
8. Helper Functions for Argument Processing
To make processing of arguments a little more convinient, the following mathods are provided by “libshell”:
| Method | Description |
| shell_str_len | Return the length of a null terminated string |
| shell_str_cmp | Comapre two strings up to a given length for each |
| shell_parse_int | Parse the integer value from a given string |
1. String Length
To check the length of a string call “shell_str_len” like so:
char *str = "abc"; int l = shell_str_len(str); // l = 3
2. Compare Strings
To compare two strings use “shell_str_cmp”:
char *s1 = "abc"; char *s2 = "abc"; char *s3 = "ABC"; char *s4 = "ABCDE"; int l1 = shell_str_len(s1); int l2 = shell_str_len(s2); int l3 = shell_str_len(s3); int l4 = shell_str_len(s4); int r; r = shell_str_cmp(s1, s2, l1, l2); // r = 0 r = shell_str_cmp(s1, s3, l1, l3); // r = 2 r = shell_str_cmp(s3, s4, l3, l4); // r = 1
To parse the integer value of a string use “shell_parse_int”:
int i = shell_parse_int((char *)"42"); // i = 42
9. Process Shell Commands
Since “libshell” does not know when or from what input to process your commands, the using code has to implement and call “shell_process” on its own. To make this an easy task, the “shell_process_cmds” helper function is provided.
For our example commandes defined in “my_shell_cms” previously, “shell_process_cmds” would be implemented as follows:
int shell_process(char *cmd_line)
{
return shell_process_cmds(&my_shell_cmds, cmd_line);
}
Then, when a new command line arrived from the input of your choice, just call “shell_process” with that command line as input, and “libshell” does the rest for you (check if the command is defined, call the callback function, provide arguments form the commandline to the callback):
char *cmd_line = "argt 1 2 3 4"; // example cmd line int s = shell_process(cmd_line);
The result from “shell_process” should be checked against the following return values:
switch(s)
{
case SHELL_PROCESS_ERR_CMD_UNKN:
// Unknown command
break;
case SHELL_PROCESS_ERR_ARGS_LEN:
// Argument to long
break;
case SHELL_PROCESS_ERR_ARGS_MAX:
// Too many arguments
break;
default:
// OK
break;
}