Before going into an example of µC/Shell usage, a few design concepts have to be explained. Since µC/Shell is not associated with any particular product, modules in need of a shell facility (such as µC/TELNETs) interact with it by means of an application callback function. This way, those modules are able to use or not to use the shell in a totally transparent manner.
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: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: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.
Note that the Shell_Exec()
function also has a ‘out_fnct
’ argument, which is a pointer to a callback that handles the details of responding to the requester. In other words, if called by µC/TELNETs, then µC/TELNETs has to provide the details of the response; if called by a UART, the UART should handle the response. Finally, the ‘pcmd_param
’ is a pointer to a structure containing additional parameters for the command to use.
For more details on this function, please proceed with the next section.
Commands, Callbacks, and Data Types
µC/Shell commands (i.e., commands placed in a ‘command table’) all have this prototype: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 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: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
: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:Note that future implementation could add members to this structure to support more parameters.
µC/Shell Startup Code
We provide you with an example (i.e the application code) use of µC/Shell which is found in app.c
and it was written to provide a startup example on how to use the capabilities of the µC/Shell module. app.c
simply initializes µC/OS?II, µC/TCP-IP and µC/Shell, and creates a few tasks and other kernel objects that will give the user information about the state of the system. Note that you DO NOT need an RTOS like µC/OS?II or a TCP/IP stack like µC/TCP-IP to use µC/Shell.
Before you can use µC/Shell, the following has to be performed:
- Develop/create your command(s)
- Implement output functions (if needed)
- Initialize µC/Shell
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.
µ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.
µC/Shell Module Configuration
The µC/Shell module has to be configured according to your specific needs. A template configuration file (shell_cfg.h
) is included in the module package (see Chapter 1, Directories and Files), and this file should be copied and added to your project. Here is the list of the values and description for each of the configuration variable. However, keep in mind that future releases of this module might include more configuration options.
#define SHELL_CFG_CMD_TBL_SIZE 3
Size of the command module table. Once this table is full, it is not possible to add any more command module table, unless Shell_CmdTblRem()
is called. This should be defined to the total amount of module registering command table in µC/Shell.
#define SHELL_CFG_CMD_ARG_NBR_MAX 5
Maximum number or argument(s) a command may pass on the string holding the complete command.
#define SHELL_CFG_MODULE_CMD_NAME_LEN_MAX 6
Maximum length for module command name, including the termination NUL
character.
µC/Shell Internal Details
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).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.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.
Two searches are necessary to locate a command. First, the correct module command table has to be found based on the command prefix, and then the corresponding command inside that table is looked for. The second search also starts with index ‘0’ of the command table, and increments that index by ‘1’ until a match is found.
As mentionned at the beginning of this chapter, the command name and arguments passed on the command line are separated by space characters. It is the responsibility of the commands to interpret and extract those arguments. For instance, this command:
App_Test –a
would result in ‘-a
’ to be passed as the argument for the ‘App_Test
’ command. If the dash needs to be removed, it has to be performed by the command itself. Note however, that µC/LIB functions are available to assist with that.