...
From the caller point of view, once the commands have been developed and the initialization performed, all that is needed to do is a call the main µC/Shell execution function:
Code Block |
---|
|
CPU_INT16S Shell_Exec (CPU_CHAR *in,
SHELL_OUT_FNCT out_fnct,
SHELL_CMD_PARAM *pcmd_param,
SHELL_ERR *perr); |
This function parses the ‘ in
’ parameter, a NUL
terminated string containing a complete command line (command name, followed by possible arguments being separated by spaces), just like this one:
Code Block |
---|
|
App_Test -a -b -c readme.txt |
Once parsed, that is once the command name and its arguments have been extracted, µC/Shell looks into its command tables for a command match (in this case App_Test
is the name of the command), and invokes it.
...
µC/Shell commands (i.e., commands placed in a ‘command table’) all have this prototype:
Code Block |
---|
|
CPU_INT16S My_Cmd (CPU_INT16U argc,
CPU_CHAR *argv[],
SHELL_OUT_FNCT out_fnct,
SHELL_CMD_PARAM *pcmd_param); |
where ‘ argc
’ is a count of the arguments supplied and ‘ argv
’, an array of pointers to the strings which are those arguments. As for the return value, it is command specific, and will be used as the return value for the Shell_Exec()
function. However, in case of an error, SHELL_EXEC_ERR
should be returned.
Commands are also defined by the SHELL_CMD_FNCT
data type:s
Code Block |
---|
|
typedef CPU_INT16S (*SHELL_CMD_FNCT)(CPU_INT16U ,
CPU_CHAR **,
SHELL_OUT_FNCT ,
SHELL_CMD_PARAM *); |
As mentioned in the preceding section, each command is responsible for responding to its requester, and this is done with the help of the last parameter: the pointer to the output function. This function has the following prototype:
Code Block |
---|
|
CPU_INT16S My_Out_Fnct (CPU_CHAR *pbuf,
CPU_INT16U buf_len,
void *popt); |
where ‘pbuf
’ is a pointer to a response buffer having a length of ‘buf_len
’. The third parameter, ‘popt
’, is an optional argument used to provide implementation specific information (port number, UART identification, etc.). As for the return value, it is suggested to return the number of data octets transmitted, SHELL_OUT_RTN_CODE_CONN_CLOSED
if the link has been closed, and SHELL_OUT_ERR
for any other error.
The output function is also defined by a data type, SHELL_OUT_FNCT
:
Code Block |
---|
|
typedef CPU_INT16S (*SHELL_OUT_FNCT)(CPU_CHAR *,
CPU_INT16U ,
void * ); |
Finally the ‘ pcmd_param
’ is used to pass additional information to the command. The current implementation has provision for the current working directory, as well as an option parameter used by the output function:
Code Block |
---|
|
typedef struct shell_cmd_param {
void *pcur_working_dir;
void *pout_opt;
CPU_BOOLEAN *psession_active;
} SHELL_CMD_PARAM; |
Note that future implementation could add members to this structure to support more parameters.
...
This section of the manual will give you some examples of the above steps. Note that some sections of the source code have been removed or modified to help focus on the µC/Shell module use.
Anchor |
---|
| Listing - Output function |
---|
| Listing - Output function |
---|
|
Code Block |
---|
language | cpp |
---|
title | Listing - Output function |
---|
linenumbers | true |
---|
|
CPU_INT16S App_TestShellOut (CPU_CHAR *pbuf, (1)
CPU_INT16U buf_len,
void *popt)
{
APP_TRACE_DEBUG((pbuf)); (2)
APP_TRACE_DEBUG((" executed.\n\r"));
return (buf_len); (3)
} |
Panel |
---|
|
(1) Function implementing the ‘output’ facility. This function MUST have the prototype specified in section 2.01. (2) This implementation simply outputs ‘pbuf’, using the trace mechanism (typically the console output). (3) Returns the number of positive data octets transmitted (no error). |
Anchor |
---|
| Listing - Command |
---|
| Listing - Command |
---|
|
Code Block |
---|
language | cpp |
---|
title | Listing - Command |
---|
linenumbers | true |
---|
|
CPU_INT16S App_TestCmd (CPU_INT16U argc, (1)
CPU_CHAR *argv[],
SHELL_OUT_FNCT out_fnct,
SHELL_CMD_PARAM *pcmd_param)
{
CPU_INT16U cmd_namd_len;
CPU_INT16S output;
CPU_INT16S ret_val;
cmd_namd_len = Str_Len(argv[0]);
output = out_fnct(argv[0], (2)
cmd_namd_len,
pcmd_param->pout_opt );
switch (output) {
case SHELL_OUT_RTN_CODE_CONN_CLOSED:
case SHELL_OUT_ERR:
ret_val = SHELL_EXEC_ERR;
break;
default:
ret_val = output;
}
return (ret_val); (3)
} |
Panel |
---|
|
(1) Function implementing a test command. (2) Use the output function to display the command name. (3) The return value is command specific, with the exception of SHELL_EXEC_ERR in case of an error. |
Anchor |
---|
| Listing - Initialization of module |
---|
| Listing - Initialization of module |
---|
|
Code Block |
---|
language | cpp |
---|
title | Listing - Initialization of module |
---|
linenumbers | true |
---|
|
static SHELL_CMD AppShellCmdTbl[] = (1)
{
{"App_test", App_TestCmd},
{0, 0 }
};
void App_InitShell (void)
{
CPU_BOOLEAN success;
SHELL_ERR err;
APP_TRACE_DEBUG(("Initialize Shell ... "));
success = Shell_Init(); (2)
if (success == DEF_OK) {
APP_TRACE_DEBUG(("done.\n\r"));
} else {
APP_TRACE_DEBUG(("failed.\n\r"));
return;
}
APP_TRACE_DEBUG(("Adding Shell command table ... "));
Shell_CmdTblAdd("App", App_ShellAppCmdTbl, &err); (3)
if (err == SHELL_ERR_NONE) {
APP_TRACE_DEBUG(("done.\n\r"));
} else {
APP_TRACE_DEBUG(("failed.\n\r"));
}
} |
Panel |
---|
|
(1) Declare and populate a SHELL_CMD structure table that will hold the ‘App’ shell commands. The first member of this structure is the command name, and the other member a pointer to a function implementing the command itself.This command table MUST have its last entry set to ‘0’. (2) Initializes µC/Shell internal variables. (3) Add the AppShellCmdTbl module command table to the Shell. |
µC/Shell Example Use
Once μC/Shell has been initialized, the only thing left to do it to call the Shell_Exec()
function, like depicted above.
Anchor |
---|
| Listing - Example use |
---|
| Listing - Example use |
---|
|
Code Block |
---|
language | cpp |
---|
title | Listing - Example use |
---|
linenumbers | true |
---|
|
void App_TestShell (void)
{
SHELL_ERR err;
SHELL_CMD_PARAM cmd_param;
#if APP_FS_EN
FS_DIR *pdir;
#endif
APP_TRACE_DEBUG(("Testing Shell, executing command ...\n\r"));
#if APP_FS_EN
pdir = FS_OpenDir("");
cmd_param.pcur_working_dir = (void *)pdir;
#else
cmd_param.pcur_working_dir = (void *)0;
#endif
cmd_param.pout_opt = (void *)0;
Shell_Exec( "App_test -a -b -c", &App_TestShellOut, &err); (1)
switch (err) {
case SHELL_ERR_NONE:
APP_TRACE_DEBUG(("Command executed, no error.\n\r"));
break;
case SHELL_ERR_NULL_PTR:
APP_TRACE_DEBUG(("Error, NULL pointer passed.\n\r"));
break;
case SHELL_ERR_CMD_NOT_FOUND:
APP_TRACE_DEBUG(("Error, command NOT found.\n\r"));
break;
case SHELL_ERR_CMD_SEARCH:
APP_TRACE_DEBUG(("Error, searching command.\n\r"));
break;
case SHELL_ERR_ARG_TBL_FULL:
APP_TRACE_DEBUG(("Error, too many arguments\n\r"));
break;
default:
break;
}
} |
Panel |
---|
|
(1) Invoke the Shell_Exec() function responsible for parsing and calling the specified command. In this case, passing ‘App_Test’ will result in the function App_TestCmd() to be called. |
µC/Shell Module Configuration
...
At initialization time, that is when the Shell_Init()
function is called, two module command pools are being created: the free and the used. Right after initialization, no module command are being used, so all of the SHELL_CFG_CMD_TBL_SIZE
module command are located into the free pool, and the used pool is empty, like displayed below (SHELL_CFG_CMD_TBL_SIZE
set to 3 in this example).
Anchor |
---|
| Figure - Pools after initialization |
---|
| Figure - Pools after initialization |
---|
|
Panel |
---|
borderWidth | 0 |
---|
title | Figure - Pools after initialization |
---|
|
Image Added |
Adding module command tables to the shell with Shell_CmdTblAdd()
results in a free module command being taken from that pool, initialized, and taken into the used pool. Below is a representation of the pools after two module command tables have been inserted.
Anchor |
---|
| Figure - Pools after modules insertion |
---|
| Figure - Pools after modules insertion |
---|
|
Panel |
---|
borderWidth | 0 |
---|
title | Figure - Pools after modules insertion |
---|
|
Image Added |
When the Shell_Exec()
function is being called in order to parse a line and execute a command, the lists of module commands have to be searched to find a match. Since the module command tables are inserted in a way analog to a stack, the search begins with the last addition. For instance, if the ‘OS
’ table has been inserted just after the ‘Net
’ one, command search will always look at the ‘OS’ command table, then proceed with the ‘Net
’ command table if a match has not been found.
...