Diagnostic Program Menu State Machine

By Dan Peirce B.Sc.
<link back to  Robot Diagnostic Page >

April 27, 2010 --- (rev May 14, 2010) (rev Oct. 26, 2010)

State transition diagram

The state transition diagram for the menu system of the Robot Diagnositc Program (with version 2.0 of the brainboard) is shown below. To avoid having the diagram get too complex it has been separated into a sequence of diagrams. This page has been modified to reflect version 4.002 of the diagnostic program.

The ovals represent states of the menu system for the diagnostic program.

The lines with arrow heads represent a transition from one state to another and the reason for the transition. In most cases the reason is a key press. In most cases a new menu will be printed when the transition is made. For many keypresses the menu system stays in the same state but something else happens (could be text displayed in hyperterminal an/or an input/output change). There is not enough room on the diagram to list out the input output changes so I will make tables of lists of these changes. Rather than using hyperterminal it is also possible to use a GUI in Perl/tk and use mouse button clicks rather than keyboard enteries. Some screen shots of the GUI window are shown just to give a idea of what that option looks like.

The program has been changed to accommodate two independent jog sequences. The jog sequences differ from other pre-existing states in that they run an ongoing sequence of changes in motor direction until stopped and send a message with a jog count for each cycle in the sequence. Each jog sequence justified a new module so any changes in that jog sequence could be made independent of the other jog sequence. In the menu system the jog sequences can be thought of as sub-states of Motor Menu 1. Within the actual program structure the menu system has in fact become the default state of a more encompassing state machine. The jog sequences are not primarily driven by the menu system but by timing considerations. The new encompassing state machine is comprised of the following states:
 

jog1
jog2
process_command (default state)
stop_state

Menu system (state machine)

When the robot is reset (by a power up or by the PICkit2) the menu state machine starts in the state "Top Level Menu". A key press of  an "M" (either case) causes a transition to the state "Motor Menu 1". A new menu is displayed so that from that state one can choose which motor to control (left or right). If "L" is choosen the menu system will transition to the "Left Motor" state. A new menu is displayed showing the possible actions at this point. None of the transistions to this point have included a change in input or output (apart from the USART). The printf() statements that comprise the actual messages displayed can be seen at  menu.c .
The C functions that correspond to all the states in the state diagram given above are in the file  process_command.c . There is a one to one corespondence between the states in the menu system and the following functions:
List State Table
enum commands get_command_char1( unsigned char data ); Top Level Menu
enum commands get_command_Mchar2( unsigned char data ); 
enum commands get_command_MLchar3( unsigned char data ) ; 
enum commands get_command_MRchar3( unsigned char data ); 
enum commands get_command_MLchar3_rev( unsigned char data ) ; 
enum commands get_command_MRchar3_rev( unsigned char data );
Motor Menu 1 
Left Motor 
Right Motor 
rev Left Motor 
rev Right Motor
enum commands get_command_Schar2( unsigned char data ); 
enum commands get_threshold( unsigned char data ); 
enum commands get_threshold_next( unsigned char data ); 
enum commands automatic_threshold( unsigned char data ); 
enum commands automatic_threshold_gap_right( unsigned char data ); 
enum commands automatic_threshold_gap_cright( unsigned char data ); 
enum commands automatic_threshold_gap_cleft( unsigned char data ); 
enum commands automatic_threshold_gap_left( unsigned char data );
Sensor Menu 1 
promps for new threshold
(sub-state)
takes sensor readings as robot manually moved
(sub_states)
Each of those functions is passed a character. In most cases the character is a character receieved from the PC (via the USART). In the case of the automatic_threshold** functions they are simply passed a null character that is ignored. That is because the transition out of those functions is primarily based on sensor input and not on keyboard input. A flag variable auto_mode is used to keep track if the system is in automatic threshold mode. This can be thought of as a parallel state variable which indicates if the current state is one of the automatic_theshold** states or not.

Each of those functions returns a value of type enum commands. The command will be either null (a zero) or a value from the list give in  command_list.h . The commands are used to set the speed and direction of one of the motors or to get a signal ADC value from one of the sensors. The list is in an enum declaration and can be easily expanded.

get_command variable (is a fuction pointer)

A variable called get_command is used to keep track of the current state of the menu system. Since there is a one to one corraspondance between states and functions used to implement states the variable get_command contains the address of the function that will be called. This means that get_command is a pointer to functions. It is very easy to use! To change the state a simple assignement statement is used like:
get_command = get_command_char1;
When it is time to call the function pointed to by get_command any of the following can be used:
get_command(data_rec);
or
command = get_command(data_rec);
or
get_command(0);
The function call with a function pointer syntax looks just like a normal function call. The pointer name is used in place of a fuction name.
The declaration of the function pointer looks like this:
static enum commands (*get_command)(unsigned char data) = get_command_char1; // example of a
                                                            // pointer to a function
enum commands process_command(void)
{
    enum commands command=null;
    unsigned char data_rec = '\0' ;

    if( auto_mode ) get_command(0);  // in this case is using sensors to find threshold
    else
    {
        if (DataRdyUSART( )) data_rec = ReadUSART ();
        if ( data_rec != '\0' ) command = get_command(data_rec);
        else command = null;
    }
    return (command); 

Note that the automatic  threshold feature was an afterthought and not part of the original concept.