Skip to end of metadata
Go to start of metadata

Executing a Command

Modules in need of a shell facility (such as TELNETs) interact with it using an application callback function. From the caller's point of view, once the commands have been developed and the initialization performed, all that is needed is to call the Shell execution function: Shell_Exec().

This function parses the in parameter, which is a null-terminated string containing a complete command line (command name, followed by possible arguments separated by spaces). For example:

"App_Test –a –b –c readme.txt"

Once the command name and its arguments have been extracted, Shell searches in 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() requires the in parameter to be a modifiable string, not a const one. The function also has an 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 TELNETs, then TELNETs has to provide the details of the response; if called by a UART, the UART should handle the response. Finally, the p_cmd_param is a pointer to a structure containing additional parameters for the command to use. The example below shows how to call this function.

void  Ex_CommonShellExec (void)
{
    CPU_INT16S       ret_val;
    SHELL_CMD_PARAM  cmd_param;
    CPU_CHAR         cmd_buf[25u];
    RTOS_ERR         err;
 
 
    Str_Copy(cmd_buf, "help");                         /* String passed to Shell_Exec must not be const.       */
 
                                                       /* Call Shell_Exec() with:                              */
    ret_val = Shell_Exec(cmd_buf,                      /*      string containing the cmd to exec,              */
                         Ex_CommonShellExecOutFnct,    /*      function to use to output,                      */
                         &cmd_param,                   /*      a cmd param structure that could be used by cmd.*/
                         &err);
    APP_RTOS_ASSERT_CRITICAL(err.Code == RTOS_ERR_NONE, ;);
    APP_RTOS_ASSERT_CRITICAL(ret_val == SHELL_EXEC_ERR_NONE, ;);
}
Listing - Executing a command via Shell_Exec()

Commands, Callbacks and Data Types

Shell Commands Function

Shell commands (that is, commands added to the shell module) are of the following prototype:

CPU_INT16S  MyShellCmd (CPU_INT16U        argc,
                        CPU_CHAR         *argv[],
                        SHELL_OUT_FNCT    out_fnct,
                        SHELL_CMD_PARAM  *p_cmd_param);
Listing - Shell Command Example

Based on the SHELL_CMD_FNCT type:

typedef  CPU_INT16S  (*SHELL_CMD_FNCT)(CPU_INT16U        argc,
                                       CPU_CHAR         *argv[],
                                       SHELL_OUT_FNCT    out_fnct,
                                       SHELL_CMD_PARAM  *p_cmd_param);
Listing - Shell Commands Type

Where:

  • argc is a count of the arguments supplied.
  • argv is an array of pointers to the strings which are those arguments.
  • out_fnct is a function pointer that outputs any information requested.
  • p_cmd_param passes additional information to the command.
  • The return value is command-specific and will be returned by the Shell_Exec() call for this command. However, in case of an error, SHELL_EXEC_ERR should be returned.

Output Function

Each command is responsible for responding to its requester using the pointer to the output function parameter. This function uses the following prototype:

CPU_INT16S  MyShellOutFnct (CPU_CHAR    *p_buf,
                            CPU_INT16U   buf_len,
                            void        *p_opt);
Listing - Shell Out Function Example

Based on the SHELL_OUT_FNCT type:

typedef  CPU_INT16S  (*SHELL_OUT_FNCT)(CPU_CHAR    *p_buf,
                                       CPU_INT16U   buf_len,
                                       void        *p_opt);
Listing - Shell Commands Type

Where:

  • p_buf is a pointer to a response buffer
  • buf_len is the length of the response buffer
  • p_opt is an optional argument used to provide implementation specific information (port number, UART identification, etc.)

The return value should be:

  • The number of data octets transmitted, if NO error occurred
  • SHELL_OUT_RTN_CODE_CONN_CLOSED if the link has been closed
  • SHELL_OUT_ERR for any other error

The example below shows what could be a valid out_fnct:

static  CPU_INT16S  Ex_CommonShellExecOutFnct (CPU_CHAR    *p_buf,
                                               CPU_INT16U   buf_len,
                                               void        *p_opt)
{
    CPU_INT16U  tx_len = buf_len;
 
 
    PP_UNUSED_PARAM(p_opt);                                /* Supplemental options not used in this command.  */
 
    while (tx_len != 0u) {
        putchar(*p_buf);                                   /* Any putchar-like function could be used, here.  */
        tx_len--;
        p_buf++;
    }
 
    return (buf_len);                                      /* Return nbr of tx'd characters.                  */
}
 
#endif  /* RTOS_MODULE_COMMON_SHELL_AVAIL */
Listing - Example of an out_fnct

Adding a Command Table to Shell

To add a new command to Shell, follow these steps:

  1. Make sure an output function of the proper type (SHELL_OUT_FNCT) can be used by future shell commands. This output function can be as simple as the one provided in the example above, or more complex if outputting is done via UART or TELNETs.
  2. Write functions with the proper signature. The correct prototype is defined by the SHELL_CMD_FNCT type, as described above. Any data that needs to be outputted should be outputted via the out_fnct. The samples below provide example functions that implement a wrapper for LIB's random number generator (RNG).
static  CPU_INT16S  Ex_CommonShellRNG_Help (CPU_INT16U        argc,
                                            CPU_CHAR         *p_argv[],
                                            SHELL_OUT_FNCT    out_fnct,
                                            SHELL_CMD_PARAM  *p_cmd_param)
{
    SHELL_CMD   *p_shell_cmd;
    CPU_INT16S   ret_val;


    PP_UNUSED_PARAM(argc);
    PP_UNUSED_PARAM(p_argv);

                                                                /* Iterate over all commands in cmd tbl.       */
    p_shell_cmd = Ex_CommonShellCmdAddCmdTbl;
    while (p_shell_cmd->Fnct != 0) {
                                                                /* Output each cmd's name.                     */
        ret_val = out_fnct((CPU_CHAR *)p_shell_cmd->Name, Str_Len(p_shell_cmd->Name), p_cmd_param->OutputOptPtr);
        if ((ret_val == SHELL_OUT_RTN_CODE_CONN_CLOSED) ||
            (ret_val == SHELL_OUT_ERR)) {
            return (SHELL_EXEC_ERR);
        }

                                                                /* Output new line.                            */
        ret_val = out_fnct((CPU_CHAR *)STR_NEW_LINE, STR_NEW_LINE_LEN, p_cmd_param->OutputOptPtr);
        if ((ret_val == SHELL_OUT_RTN_CODE_CONN_CLOSED) ||
            (ret_val == SHELL_OUT_ERR)) {
            return (SHELL_EXEC_ERR);
        }

        p_shell_cmd++;
    }

    return (SHELL_EXEC_ERR_NONE);
}
Listing - Shell commands functions

static  CPU_INT16S  Ex_CommonShellRNG_Seed (CPU_INT16U        argc,
                                            CPU_CHAR         *p_argv[],
                                            SHELL_OUT_FNCT    out_fnct,
                                            SHELL_CMD_PARAM  *p_cmd_param)
{
    CPU_INT16S  result_h;
    CPU_INT16S  result_help;
    RAND_NBR    seed;


    if (argc != 2) {                                        /* If not enough or too much args, display help. */
        (void)out_fnct((CPU_CHAR *)EX_COMMON_SHELL_RNG_SEED_INVALID_ARG, 
                                   Str_Len(EX_COMMON_SHELL_RNG_SEED_INVALID_ARG), 
                                   p_cmd_param->OutputOptPtr);

        (void)out_fnct((CPU_CHAR *)STR_NEW_LINE,
                                   STR_NEW_LINE_LEN,
                                   p_cmd_param->OutputOptPtr);

        (void)out_fnct((CPU_CHAR *)EX_COMMON_SHELL_RNG_SEED_HELP,
                                   Str_Len(EX_COMMON_SHELL_RNG_SEED_HELP),
                                   p_cmd_param->OutputOptPtr);

        (void)out_fnct((CPU_CHAR *)STR_NEW_LINE,
                                   STR_NEW_LINE_LEN,
                                   p_cmd_param->OutputOptPtr);

        return (SHELL_EXEC_ERR_NONE);
    }

    result_h = Str_Cmp(p_argv[1u], "-h");
    result_help = Str_Cmp(p_argv[1u], "--help");
    if ((result_h    == 0) ||
        (result_help == 0)) {                               /* Display help.                                 */
        (void)out_fnct((CPU_CHAR *)EX_COMMON_SHELL_RNG_SEED_HELP,
                                   Str_Len(EX_COMMON_SHELL_RNG_SEED_HELP),
                                   p_cmd_param->OutputOptPtr);

        (void)out_fnct((CPU_CHAR *)STR_NEW_LINE,
                                   STR_NEW_LINE_LEN,
                                   p_cmd_param->OutputOptPtr);

        return (SHELL_EXEC_ERR_NONE);
    }

                                                            /* Convert string number to int.                 */
    seed = (RAND_NBR)Str_ParseNbr_Int32U((const  CPU_CHAR *)p_argv[1u],
                                         DEF_NULL,
                                         10u);

    Math_RandSetSeed(seed);

    return (SHELL_EXEC_ERR_NONE);
} 
Listing - Shell commands functions

static  CPU_INT16S  Ex_CommonShellRNG_Get  (CPU_INT16U        argc,
                                            CPU_CHAR         *p_argv[],
                                            SHELL_OUT_FNCT    out_fnct,
                                            SHELL_CMD_PARAM  *p_cmd_param)
{
    RAND_NBR    rand;
    CPU_INT16S  ret_val;
    CPU_CHAR    rand_str_buf[DEF_INT_32U_NBR_DIG_MAX + 1u];


    PP_UNUSED_PARAM(argc);
    PP_UNUSED_PARAM(p_argv);

    rand = Math_Rand();                                         /* Obtain random nbr from LIB Math module.  */

                                                                /* Convert int decimal number to str.       */
    (void)Str_FmtNbr_Int32U(rand,
                            DEF_INT_32U_NBR_DIG_MAX,
                            DEF_NBR_BASE_DEC,
                            '\0',
                            DEF_NO,
                            DEF_YES,
                            &rand_str_buf[0u]);

                                                                /* Output random number obtained.           */
    ret_val = out_fnct(&rand_str_buf[0u], Str_Len(&rand_str_buf[0u]), p_cmd_param->OutputOptPtr);
    if ((ret_val == SHELL_OUT_RTN_CODE_CONN_CLOSED) ||
        (ret_val == SHELL_OUT_ERR)) {
        return (SHELL_EXEC_ERR);
    }

                                                               /* Output new line.                          */
    ret_val = out_fnct((CPU_CHAR *)STR_NEW_LINE, STR_NEW_LINE_LEN, p_cmd_param->OutputOptPtr);
    if ((ret_val == SHELL_OUT_RTN_CODE_CONN_CLOSED) ||
        (ret_val == SHELL_OUT_ERR)) {
        return (SHELL_EXEC_ERR);
    }

    return (SHELL_EXEC_ERR_NONE);
}

#endif  /* RTOS_MODULE_COMMON_SHELL_AVAIL */
Listing - Shell commands functions

  1. Once these functions have been correctly implemented and validated, build a Shell command table. This table associates a name to the functions created above. This table must be NULL-terminated by adding an empty entry at the end of the table. The example below shows how this is done for the three RNG functions.

    static  SHELL_CMD  Ex_CommonShellCmdAddCmdTbl[] =
    {
        {EX_COMMON_SHELL_CMD_NAME_HELP, Ex_CommonShellRNG_Help},    /* Associate cmd str with cmd fnct.           */
        {EX_COMMON_SHELL_CMD_NAME_SET,  Ex_CommonShellRNG_Seed},
        {EX_COMMON_SHELL_CMD_NAME_GET,  Ex_CommonShellRNG_Get},
        {0,                 0}                                      /* Tbl is NULL-terminated to indicate end.    */
    };
    Listing - Shell commands table

  2. Before these commands can be called via Shell_Exec(), call Shell_CmdTblAdd()  to register them to Shell. The example below illustrates how this is done.

     void  Ex_CommonShellCmdAdd (void)
    {
        RTOS_ERR  err;
     
     
                                                            /* Add cmds in Cmd Tbl to Shell's available cmds. */
        Shell_CmdTblAdd((CPU_CHAR *)EX_COMMON_SHELL_CMD_TBL_NAME,
                        Ex_CommonShellCmdAddCmdTbl,
                        &err);
        APP_RTOS_ASSERT_CRITICAL(err.Code == RTOS_ERR_NONE, ;);
    }
    Listing - Shell commands table

The table name should be the same as the commands' prefix, which is rng, in our case.

At this point, the commands are ready to be used, just like any other Shell command.

Removing a Command Table From the Shell Module

To remove a command table from the Shell module, call the Shell_CmdTblRem() function with the command table name that must be removed.

  • No labels