Session 14: The Shell

Document created by Gabriela Godinez Employee on Jun 30, 2016Last modified by Gabriela Godinez Employee on Jun 30, 2016
Version 2Show Document
  • View in full screen mode

This video presentation is the fourteenth installment of the Essentials of MQX RTOS Application Development training course. In this session, you will be introduced to the Shell.

This training was created by Embedded Access Inc., a Freescale sponsored training provider and proven partner.

Session 14 Course LineLab Outline
  • Overview of the Shell
  • Uses for the Shell
  • Commands included with the Shell
  • Accessing help for a command and the list of commands
  • Creating a set of custom commands
  • Example of a custom set of commands
  • Code Walkthrough
  • Example of using the shell with the HVAC Demo App
  • Create a new Command List for the Shell to use
  • Add new commands to the Command List
  • Create a new shell function to handle the printing of health logs
  • Create a new shell function to handle the CAN task functions

 

First, watch the video for Session 14: Shell.

Then, follow through with the interactive lab assignment below.

SESSION 14: LAB ASSIGNMENT

INTRODUCTION

In this lab we will be replacing the character based interface in the UI Task with an interface that is based on the shell. Other than the support for the help functions that will now be in place there is no new functionality added to our application as a result of this lab, but if you haven't worked with the shell before it will be very useful to see how easy it is to add into your application. Almost any embedded application has a need for a text based interface, even if it's just for testing or product maintenance, and knowing how to implement one that can be easily maintained and is scalable is very helpful.

OBJECTIVE

The objective of this lab is simply to learn how to use the shell to add a text based interface to your application.

ASSIGNMENT

ADDING THE SHELL TO THE APPLICATION

    1. Since the UI Task will be using the shell library, "shell.h" should be included at the top of UiTask.c.
    2. As we are adding a new library to our project there may be an automatic warning icon from CodeWarrior showing up beside the '#include "shell.c" ' entry. This is because the shell library needs to be added into the project properties. Open the 'Project Properties' dialog box for your project (Right click, properties) and expand the 'C/C++ Build' list. Select the 'Settings' item. Under the category of 'ARM Ltd Windows GCC C Compiler' chose the 'Directories' item. Click on the green + icon to add a new entry and enter the location of the shell library. Unless you have moved it, it should be located at: "${MQX_ROOT_DIR}/lib/twrk70f120m.cw 10gcc/debug/shell". Note that you can first open an entry for a similar library such as the PSP to copy its location and paste it into the new entry (replacing 'psp' with 'shell') to avoid the chance of making a typing mistake. Click 'OK'. Select the 'Miscellaneous' item under the 'ARM Ltd Windows GCC C Linker' category and add the shell.a library. Copy the 'psp' entry, create a new entry, paste the psp string and replace 'psp' for 'shell' in TWO places. The warning beside the '#include "shell.h" ' line should be gone now, or if not, the project should compile okay at least.
    3. In order to set up a timer we'll need a structure to be declared in the Health Task of type LWTIMER_PERIOD_STRUCT and another one of type LWTIMER_STRUCT.
    4. In the initialization section of the Health Task create the periodic queue with the _lwtimer_create_periodic_queue() function that has a period of 1 second and no wait time. Note that for this BSP of MQX the define BSP_ALARM_FREQUENCY is set to 200 ticks and each tick is 5 msec, so it represents 1 second. Then add a timer to the queue using the _lwtimer_add_timer_to_queue() function. You do not need an offset and the timer should call a 'health_timer' ISR function that will be defined later. The parameter to pass is the Health Task Queue ID. Note that the 'my_qid' variable isn't valid until after the _msgq_open() function so these new lines should go after the _msgq_open() call.
    5. As you learnt in the course you will need a list of commands that are of type SHELL_COMMAND_STRUCT, so create this at the top of UiTask.c. You can start by adding in some of the built in commands like 'help' to print out the help data and the '?' command to get the list of commands. Don't forget to terminate the list with a NULL entry.
      cheat.png
      Cheat 14-1.png

UPDATING THE INTERFACE CODE

  1. Currently the user interface code in the while(1) loop is strictly character based and is of no use to us now. This all needs to be removed, but it is suggested that you move this code instead of deleting it so you can reference it in the next step.
  2. The two main sets of commands that the UI managed was related to the CAN tasks (to create, destroy, abort, and restart CAN Tasks) and the printing of Health Logs which was just added in the lab for the previous session. Now we are going to replicate this functionality using the shell, and so two shell command functions will be created. At the top of UiTask.c create two function prototypes for shell commands, one for a function called 'Shell_log' and another called 'Shell_can'. These should follow the same format that all shell functions use.
  3. Add a command for each of these to the list of commands that was started in step 5, ie a command called 'can' and a command called 'log'. Note that the list of commands is typically organized in alphabetical order.
    cheat.png
    Cheat 14-2.png
  4. Create the shell_log function in the standard format for a shell command as outlined in the video for this session. This includes checking if the function is being called for a help request (print usage). If it is not a print usage request then process the request with a check for the correct number of arguments. If it is a print usage request, print out the long or short form accordingly. The structure is given in the whiteboard popup.
    whiteboard.png
    Whiteboard 14-1.jpg
  5. Add in the while loop that was used previously (that was removed in step 6 above) that handled the printing of all of the Health Logs that are found on the queue. This is the main function for this command so it should be executed if there was one argument. Also add in appropriate messages to print out when short or long help is requested. Note that the variable of type 'HEALTH_RECORD *' that we had before will be needed.
    cheat.png
    Cheat 14-3.png
  6. Make a copy of the Shell_log function and use that to start the Shell_can function. You will recall that the UI handling of the CAN tasks supported creating, destroying, aborting, and restarting of CAN tasks and so our Shell_can function will need to support this as well. For this, a second argument will be required to indicate which of these functions the user would like to do, and in the case of creating CAN tasks, a third argument is required to indicate how many instances of the CAN task are requested. You will need a series of IF, ELSE IF tests on the second argument (ie argv[1] ) to check if the entered text was "create", "destroy", "abort", or "restart". For this it is recommended to use the case insensitive string compare function shown below, which returns a 0 on a successful compare.
    strcasecmp (argv[1], "string"); 
    Your code should also have error handling for the wrong number of arguments for each of the commands. style="padding-bottom:15px"
  7. The code to create, destroy, abort, or restart the CAN tasks uses an array of CAN Tasks to know which task is active and which ones are not. In order to maintain the contents of this list the declaration of this array needs to be as a static:
    static  _task_id   ids[10] = {0}; 
  8. In the handling of a "create" command you will need to check the third argument to find out how many CAN tasks to create. For this you can use the sscanf() function below that will scan the second arg. This will scan the entry as a decimal and store the result at &numCanTask. It will return the number of arguments scanned which you want to be '1' to make sense. If this function returns something other than 1 then something is wrong and an appropriate message should be printed.
    sscanf(arg[2], "%d",  &numCanTask ) 
    cheat.png
    Cheat 14-4.png
  9. Copy the previous code we had for creating a number of CAN tasks and enter it into the Shell_can function in the appropriate place, ie when the "create" command is entered and the correct number of arguments were used.
    cheat.png
    Cheat 14-5.png
  10. Repeat this process to add in the handling for the "destroy", "abort", and "restart" commands by copying the code we had before.
    cheat.png
    Cheat 14-6.png
  11. Finally, the Ui_task() function needs to be updated to call the shell. No other code is required, it simply has a while(1) loop with a call to the shell to let it handle all of the user interface.
    cheat.png
    Cheat 14-7.png
  12. Compile your code and run it. The log and can commands should all function as they did before, but now the help function is in place. Running CAN tasks print out a message every second to let you know that they are still running. If this interferes with your use of the UI, the time delay in the Can_task() function can be increased to something like 5 seconds.
    results.png
    Results 14-1.png

Need more help? The full source code for this lab can be found in the 'Lab Source Code' folder here.

Attachments

    Outcomes