Application example

Script for Generating Source Code Tables

The following Python script, Widget.py, will generate the declarations and tables for the example in the rest of this section, but the code examples that follow have not been generated using this facility.

import sys
sys.path.append("..\\exec")  # for ExecStuff, assuming exec is in this directory
from ExecStuff import *
 
############# Complete set of definitions for exec, etc. ######################
 
Definition = {
    'Event Queues' : (('BACKGND_QUEUE', 128),  ('LOW_QUEUE', 32), 
                      ('INTERMED_QUEUE', 32), ('TOP_QUEUE', 8) ),
 
    'State Tables' : ( 
        ( 'smSingleTransition',
         ('SM_SINGLE_STATE',                  'STATE1'),
#          ========================================================================
        (('EV_STATUS_REQUEST', 'BACKGND_QUEUE'),
                                             ('STATE1', 0, 'HandleStatusRequest')),
        (('EV_SCAN_TRIGGER',   'TOP_QUEUE'), ('STATE1', 0, 'ScanInputs'))
        ),
 
        ( 'smWidgetTransition',
         ('SM_WIDGET_SEQUENCER', 'WIDGET_IDLE', 'ENTERING_SLOT', 'LEAVING_SLOT', 
                                 'ENTERING_TRAY', 'AWAITING_REMOVAL', 'FAULTY'),
#          =====================================================================
               (('EV_DOOR_READY',     'INTERMED_QUEUE'), 
                       ('ENTERING_SLOT',  0, 'DispenseWidget'), # WIDGET_IDLE
                       ('ENTERING_SLOT',  0, None),             # ENTERING_SLOT
                       ('LEAVING_SLOT',   0, None),             # LEAVING_SLOT
                       ('ENTERING_TRAY',  0, None),             # ENTERING_TRAY
                       ('ENTERING_SLOT',  0, 'DispenseWidget'), # AWAITING_REMOVAL
                       ('FAULTY',         0, None)),            # FAULTY
 
               (('EV_WIDGET_IN_SLOT', 'INTERMED_QUEUE'),
                       ('FAULTY',         1, 'LogWidgetFault'), # WIDGET_IDLE
                       ('LEAVING_SLOT',   0, None),             # ENTERING_SLOT
                       ('LEAVING_SLOT',   0, None),             # LEAVING_SLOT
                       ('FAULTY',         3, 'LogWidgetFault'), # ENTERING_TRAY
                       ('FAULTY',         3, 'LogWidgetFault'), # AWAITING_REMOVAL
                       ('FAULTY',         0, None)),            # FAULTY
               (('EV_SLOT_CLEAR',     'INTERMED_QUEUE'),
                       ('WIDGET_IDLE',    0, None),             # WIDGET_IDLE
                       ('ENTERING_SLOT',  0, None),             # ENTERING_SLOT
                       ('ENTERING_TRAY',  0, 'HandleWidget'),   # LEAVING_SLOT
                       ('ENTERING_TRAY',  0, None),             # ENTERING_TRAY
                       ('AWAITING_REMOVAL',0,None),             # AWAITING_REMOVAL
                       ('FAULTY',         0, None)),            # FAULTY
               (('EV_WIDGET_IN_TRAY', 'INTERMED_QUEUE'),
                       ('FAULTY',         2, 'LogWidgetFault'), # WIDGET_IDLE
                       ('FAULTY',         2, 'LogWidgetFault'), # ENTERING_SLOT
                       ('AWAITING_REMOVAL',0,'StopWidget'),     # LEAVING_SLOT
                       ('AWAITING_REMOVAL',0,'StopWidget'),     # ENTERING_TRAY
                       ('AWAITING_REMOVAL',0,None),             # AWAITING_REMOVAL
                       ('FAULTY',         0, None)),            # FAULTY
               (('EV_TRAY_CLEAR',     'INTERMED_QUEUE'),
                       ('WIDGET_IDLE',    0, None),             # WIDGET_IDLE
                       ('ENTERING_SLOT',  0, None),             # ENTERING_SLOT
                       ('LEAVING_SLOT',   0, None),             # LEAVING_SLOT
                       ('WIDGET_IDLE',    0, 'RecordWidget'),   # ENTERING_TRAY
                       ('WIDGET_IDLE',    0, 'RecordWidget' ),  # AWAITING_REMOVAL
                       ('FAULTY',         0, None)),            # FAULTY
               (('EV_WIDGET_TIMEOUT', 'INTERMED_QUEUE'),
                       ('WIDGET_IDLE',    0, None),             # WIDGET_IDLE
                       ('FAULTY',        10, 'LogWidgetFault'), # ENTERING_SLOT
                       ('FAULTY',        10, 'LogWidgetFault'), # LEAVING_SLOT
                       ('FAULTY',        10, 'LogWidgetFault'), # ENTERING_TRAY
                       ('WIDGET_IDLE',    0, 'RecordWidget'),   # AWAITING_REMOVAL
                       ('WIDGET_IDLE',    0, None))             # FAULTY
        ),
 
        ( 'smDoorTransition',
         ('SM_DOOR_CONTROL', 'DOOR_CLOSED', 'DOOR_OPENING',
                             'DOOR_OPEN', 'DOOR_CLOSING'),
#          ===================================================================
               (('EV_BUTTON_PUSHED', 'LOW_QUEUE'),
                       ('DOOR_OPENING',   0, 'OpenDoor'),       # DOOR_CLOSED
                       ('DOOR_OPENING',   0, None),             # DOOR_OPENING
                       ('DOOR_OPEN',      0, None),             # DOOR_OPEN
                       ('DOOR_OPENING',   0, 'OpenDoor')),      # FAULTY
               (('EV_DOOR_OPEN',     'LOW_QUEUE'),
                       ('DOOR_CLOSED',    0, None),             # DOOR_CLOSED
                       ('DOOR_OPEN',      0, 'TriggerWidget'),  # DOOR_OPENING
                       ('DOOR_OPEN',      0, None),             # DOOR_OPEN
                       ('DOOR_CLOSING',   0, None)),            # FAULTY
               (('EV_DOOR_CLOSED',   'LOW_QUEUE'),
                       ('DOOR_CLOSED',    0, None),             # DOOR_CLOSED
                       ('DOOR_OPENING',   0, None),             # DOOR_OPENING
                       ('DOOR_OPEN',      0, None),             # DOOR_OPEN
                       ('DOOR_CLOSING',   0, None)),            # FAULTY
               (('EV_DOOR_TIMEOUT',  'LOW_QUEUE'),
                       ('DOOR_CLOSED',    0, None),             # DOOR_CLOSED
                       ('DOOR_CLOSING',   0, 'CloseDoor'),      # DOOR_OPENING
                       ('DOOR_CLOSING',   0, 'CloseDoor'),      # DOOR_OPEN
                       ('DOOR_CLOSING',   0, None))             # FAULTY
        ),
    ),
 
    'Timers' : ('WIDGET_TIMER', 'DOOR_TIMER'),
 
    'Comms' : (('boolean', 'byte', 'sbyte', 'word', 'sword', 'lword', 'slword'),
 
               (('StatusDef', 'StatusDefDescriptor', 1),
                ('byte', 'ID', 1),
                ('lword', 'Flags', 2),
                ('DateTimeDef', 'Timestamp', 1)),
 
               (('DateTimeDef', None, 0),
                ('byte', 'Hour', 1),
                ('byte', 'Minute', 1),
                ('byte', 'Second', 1),
                ('byte', 'Day', 1),
                ('byte', 'Month', 1),
                ('word', 'Year', 1))             
              ),
 
    'Source Files' : ('Widget.h', 'Widget_d.h', 'Widget00.c', 'Widget01.c', 
                                  'Widget02.c', 'Widget03.c', 'Widget04.c')
}
 
###############################################################################
 
genFiles( genStateTables (Definition['Event Queues'], Definition['State Tables']) +
          genTimers (Definition['Timers']) +
          genCommsStructures (Definition['Comms']),
          Definition['Source Files'])
 
genStabReport( Definition['State Tables'], 'WidgetStates')
 
print 'Source code update complete.'

Application Definition Header File Data

The following is a section from Widget_d.h (which included by Exec.h for use in the executive and the application, by defining the constant APP_HEADER to be “Widget_d.h” in the compile options – this typically appears as APP_HEADER=”\”Widget_d.h\”” in the command line):

#ifdef __C166__
#include "C167Dep.h"
#else
#include "WinDep.h"
#endif
 
//{{EXEC_DEFINE() – if used, this would go here and be filled with the following:
//}}
 
/*********************  Queues  **********************************************/
 
#define BACKGND_QSIZE   128
#define LOW_QSIZE        32
#define INTERMED_QSIZE   32
#define TOP_QSIZE         8
#define TOTAL_QSIZE    (BACKGND_QSIZE + LOW_QSIZE + INTERMED_QSIZE + TOP_QSIZE)
 
#define BACKGND_QUEUE     0
#define LOW_QUEUE         1
#define INTERMED_QUEUE    2
#define TOP_QUEUE         3
#define TOTAL_QUEUES      4
 
/*********************  Events  **********************************************/
 
#define NON_EVENT                0
#define EV_STATUS_REQUEST        1
#define EV_SCAN_TRIGGER          2
#define EV_DOOR_READY            3
#define EV_WIDGET_IN_SLOT        4
#define EV_SLOT_CLEAR            5
#define EV_WIDGET_IN_TRAY        6
#define EV_TRAY_CLEAR            7
#define EV_WIDGET_TIMEOUT        8
#define EV_BUTTON_PUSHED         9
#define EV_DOOR_OPEN            10
#define EV_DOOR_CLOSED          11
#define EV_DOOR_TIMEOUT         12
 
#define TOTAL_EVENTS            12
 
/*********************  State Machines  **************************************/
 
#define SM_SINGLE_STATE          0
#define SM_WIDGET_SEQUENCER      1
#define SM_DOOR_CONTROL          2
 
#define STATE_MACHINES           3
 
#define SINGLE_EVENTS            2
#define WIDGET_STATES            6
#define WIDGET_EVENTS            6
#define DOOR_STATES              4
#define DOOR_EVENTS              4
 
/*********************  Timers  **********************************************/
 
//{{EXEC_TIMERS() – if used, this would go here and be filled with the following:
//}}
 
#define WIDGET_TIMER             0
#define DOOR_TIMER               1
 
#define TOTAL_TIMERS             2
 
#define WIDGET_TIME              2000
#define DOOR_TIME                 500

Application Main Header File Data

The following is a section from Widget.h:

extern VCONST struct execInputEventDef InputEvents;
 
//{{EXEC_DECLARE() – if used, this would go here and be filled with:
//}}
 
extern VCONST struct execStateTransitionDef smSingleTransition[SINGLE_EVENTS];
extern VCONST struct execStateTransitionDef 
                            smWidgetTransition[WIDGET_STATES*WIDGET_EVENTS];
extern VCONST struct execStateTransitionDef 
                            smDoorTransition[DOOR_STATES*DOOR_EVENTS];

Application-Provided Data Structures

The following is a section from Widget00.c (module 00 contains the definition tables by convention):

#include "Exec.h"
 
//{{EXEC_DEFINITION() – if used, this would go here and be filled with:
//}}
 
// Event queue definitions
// -----------------------
VCONST struct execQueueDef execQueue[TOTAL_QUEUES] =
{
    {BACKGND_QSIZE ,&execEventQueue[0]},
    {LOW_QSIZE,&execEventQueue[BACKGND_QSIZE]},
    {INTERMED_QSIZE,&execEventQueue[BACKGND_QSIZE+LOW_QSIZE]},
    {TOP_QSIZE,&execEventQueue[BACKGND_QSIZE+LOW_QSIZE+INTERMED_QSIZE]}
};
 
// State machine definitions
// -------------------------
VCONST struct execStateMachineDef execStateMachine[STATE_MACHINES] =
{
    {1,                SINGLE_EVENTS,    smSingleTransition},
    {WIDGET_STATES,    WIDGET_EVENTS,    smWidgetTransition},
    {DOOR_STATES,      DOOR_EVENTS,      smDoorTransition}
};                  
 
// Event definitions
// -----------------
VCONST struct execEventDef execEvent[TOTAL_EVENTS+1] =
{
    {0,              0, 0 },                    // NON_EVENT
    {BACKGND_QUEUE,  0, SM_SINGLE_STATE},       // EV_STATUS_REQUEST
    {TOP_QUEUE,      1, SM_SINGLE_STATE},       // EV_SCAN_TRIGGER
    {INTERMED_QUEUE, 0, SM_WIDGET_SEQUENCER},   // EV_DOOR_READY
    {INTERMED_QUEUE, 1, SM_WIDGET_SEQUENCER},   // EV_WIDGET_IN_SLOT
    {INTERMED_QUEUE, 2, SM_WIDGET_SEQUENCER},   // EV_SLOT_CLEAR
    {INTERMED_QUEUE, 3, SM_WIDGET_SEQUENCER},   // EV_WIDGET_IN_TRAY
    {INTERMED_QUEUE, 4, SM_WIDGET_SEQUENCER},   // EV_TRAY_CLEAR
    {INTERMED_QUEUE, 5, SM_WIDGET_SEQUENCER},   // EV_WIDGET_TIMEOUT
    {LOW_QUEUE,      0, SM_DOOR_CONTROL},       // EV_BUTTON_PUSHED
    {LOW_QUEUE,      1, SM_DOOR_CONTROL},       // EV_DOOR_OPEN
    {LOW_QUEUE,      2, SM_DOOR_CONTROL},       // EV_DOOR_CLOSED
    {LOW_QUEUE,      3, SM_DOOR_CONTROL}        // EV_DOOR_TIMEOUT
};
 
// Input event definitions
// -----------------------
VCONST struct execInputEventDef InputEvents  =
{
    {EV_BUTTON_PUSHED, NON_EVENT,         NON_EVENT,         EV_DOOR_OPEN,
     NON_EVENT,        EV_WIDGET_IN_SLOT, EV_WIDGET_IN_TRAY, NON_EVENT},
 
    {NON_EVENT,        NON_EVENT,         NON_EVENT,         EV_DOOR_CLOSED,
     NON_EVENT,        EV_SLOT_CLEAR,     EV_TRAY_CLEAR,     NON_EVENT},
 
    0x96        // Bit mask; high-going events (above), low-going events
};

Application-Provided Routines

The following is a section from Widget01.c (module 01 contains the application-provided exec. functions by convention):

#include "Exec.h"
 
void execAppInit (void)
{
//  Perform integrity checks
//  ------------------------
    if (execCheckIntegrity (0) != 0)
    {
        IdleMonitorPin = FALSE;        // Signal system as non-starter
        while (1);                     // Halt
    }
    else
        IdleMonitorPin = TRUE;
 
//  Initialise the system
//  ---------------------
    SetupIOandInterrupts();
    execEnableStateMachine (SM_SINGLE_STATE, 1);
    execEnableStateMachine (SM_WIDGET_SEQUENCER, 1);
    execEnableStateMachine (SM_DOOR_CONTROL, 1);
}
 
void execAppIdle(void)
{
    IdleMonitorPin = FALSE;
    execSafeCpuIdle();      // Returns after next interrupt has processed
    IdleMonitorPin = TRUE;
}
 
void execAppTrace (byte BeforeState, byte AfterState, word Event)
{
//  Assumes maximum of 15 states and 64 events
//  ------------------------------------------
    EmitCodeSomewhere ( (word)(((BeforeState&15)<< 10) +
                               ((AfterState&15)<< 6) +
                                Event&63));
}
 
#ifndef _WIN32
 
void TimerInterrupt (void) /* interrupt */
{
    word NextTick, CurrentTick = HwareTimerReg;
 
//  Process the timeout(s)
//  ----------------------
    NextTick = execProcessTimeouts(CurrentTick);
 
//  Set up for next interrupt or disable
//  ------------------------------------
    if (NextTick == CurrentTick)
        HwareTimerEnable = FALSE;          // Disable timer compare
    else
        HwareCompareReg = NextTick;
}
 
word execAppCurrentTick()
{
//  Return current timer tick
//  -------------------------
    return HwareTimerReg;
}
 
void execAppResyncTimer (word TickCount, boolean Enable)
{
    HwareTimerEnable = FALSE;          // Disable timer compare
 
//  Set up for next interrupt
//  -------------------------
    HwareCompareReg = TickCount;
 
//  Enable timer compare if required
//  --------------------------------
    if (Enable);
        HwareTimerEnable = TRUE;        // Enable timer compare
}
 
#else
 
void execAppFinish()
{
}
 
#endif  // _WIN32

State Machines

The following sections are from Widget02.c, Widget03.c, etc., and each contains one state machine each. Module 02 contains the single-state state machine by convention, which is a collection of all of the event handling functions for which state information is irrelevant. Widget02.c:

#include "Exec.h"
 
/*********************  State transition table *******************************/
 
//{{EXEC_SM_DECLARE(SM_SINGLE_STATE) – if used, this would go here, filled with:
//}}
 
//  States
//  ------
#define STATE1  1       // The only valid state
 
//  State transition functions
//  --------------------------
static void HandleStatusRequest(void);
static void ScanInputs(void);
 
//{{EXEC_SM_DEFINE(SM_SINGLE_STATE) – if used, this would go here, filled with:
//}}
 
//  State table
//  -----------
VCONST struct execStateTransitionDef smSingleTransition[SINGLE_EVENTS] = 
{
//  STATE1:
//  ------
    {STATE1,    0, HandleStatusRequest},    // EV_STATUS_REQUEST
    {STATE1,    0, ScanInputs}              // EV_SCAN_TRIGGER
};
 
/*********************  State transition functions ***************************/
 
//  Handle status request
//  ---------------------
static void HandleStatusRequest (void)
{
    ReplyToRequest();
}
 
//  Trigger events based on input pin transitions
//  ---------------------------------------------
static void ScanInputs (void)
{
    static byte OldInputs = 0x0000, ValidatedInputs = 0x0000;
 
    execPostInputEvents (PinPort, &OldInputs, &ValidatedInputs, &InputEvents);
}

Widget03.c; Widget sequencer state machine:

#include "Exec.h"
 
/*********************  State transition table *******************************/
 
//{{EXEC_SM_DECLARE(SM_WIDGET_SEQUENCER) – if used, this would go here, with:
//}}
 
//  States
//  ------
#define WIDGET_IDLE       1
#define ENTERING_SLOT     2
#define LEAVING_SLOT      3
#define ENTERING_TRAY     4
#define AWAITING_REMOVAL  5
#define FAULTY            6
 
 
//  State transition functions
//  --------------------------
static void DispenseWidget(void);
static void HandleWidget(void);
static void StopWidget(void);
static void RecordWidget(void);
static void LogWidgetFault(void);
 
//{{EXEC_SM_DEFINE(SM_WIDGET_SEQUENCER) – if used, this would go here, with:
//}}
 
//  State table
//  -----------
VCONST struct execStateTransitionDef smWidgetTransition[WIDGET_STATES *
                                                        WIDGET_EVENTS] = 
{
//  WIDGET_IDLE:
//  -----------
    {ENTERING_SLOT,  0, DispenseWidget},    // EV_DOOR_READY
    {FAULTY,         1, LogWidgetFault},    // EV_WIDGET_IN_SLOT
    {WIDGET_IDLE,    0, NOFUNC},            // EV_SLOT_CLEAR
    {FAULTY,         2, LogWidgetFault},    // EV_WIDGET_IN_TRAY
    {WIDGET_IDLE,    0, NOFUNC},            // EV_TRAY_CLEAR
    {WIDGET_IDLE,    0, NOFUNC},            // EV_WIDGET_TIMEOUT
 
//  ENTERING_SLOT:
//  -------------
    {ENTERING_SLOT,  0, NOFUNC},            // EV_DOOR_READY
    {LEAVING_SLOT,   0, NOFUNC},            // EV_WIDGET_IN_SLOT
    {ENTERING_SLOT,  0, NOFUNC},            // EV_SLOT_CLEAR
    {FAULTY,         2, LogWidgetFault},    // EV_WIDGET_IN_TRAY
    {ENTERING_SLOT,  0, NOFUNC},            // EV_TRAY_CLEAR
    {FAULTY,        10, LogWidgetFault},    // EV_WIDGET_TIMEOUT
 
//  LEAVING_SLOT:
//  ------------
    {LEAVING_SLOT,   0, NOFUNC},            // EV_DOOR_READY
    {LEAVING_SLOT,   0, NOFUNC},            // EV_WIDGET_IN_SLOT
    {ENTERING_TRAY,  0, HandleWidget},      // EV_SLOT_CLEAR
    {AWAITING_REMOVAL,0,StopWidget},        // EV_WIDGET_IN_TRAY
    {LEAVING_SLOT,   0, NOFUNC},            // EV_TRAY_CLEAR
    {FAULTY,        10, LogWidgetFault},    // EV_WIDGET_TIMEOUT
 
//  ENTERING_TRAY:
//  -------------
    {ENTERING_TRAY,  0, NOFUNC},            // EV_DOOR_READY
    {FAULTY,         3, LogWidgetFault},    // EV_WIDGET_IN_SLOT
    {ENTERING_TRAY,  0, NOFUNC},            // EV_SLOT_CLEAR
    {AWAITING_REMOVAL,0,StopWidget},      // EV_WIDGET_IN_TRAY
    {WIDGET_IDLE,    0, RecordWidget},    // EV_TRAY_CLEAR
    {FAULTY,        10, LogWidgetFault},  // EV_WIDGET_TIMEOUT
 
//  AWAITING_REMOVAL:
//  ----------------
    {ENTERING_SLOT,  0, DispenseWidget},    // EV_DOOR_READY
    {FAULTY,         3, LogWidgetFault},    // EV_WIDGET_IN_SLOT
    {AWAITING_REMOVAL,0,NOFUNC},            // EV_SLOT_CLEAR
    {AWAITING_REMOVAL,0,NOFUNC},            // EV_WIDGET_IN_TRAY
    {WIDGET_IDLE,    0, RecordWidget },     // EV_TRAY_CLEAR
    {WIDGET_IDLE,    0, RecordWidget },     // EV_WIDGET_TIMEOUT
 
//  FAULTY:
//  ------
    {FAULTY,         0, NOFUNC},            // EV_DOOR_READY
    {FAULTY,         0, NOFUNC},            // EV_WIDGET_IN_SLOT
    {FAULTY,         0, NOFUNC},            // EV_SLOT_CLEAR
    {FAULTY,         0, NOFUNC},            // EV_WIDGET_IN_TRAY
    {FAULTY,         0, NOFUNC},            // EV_TRAY_CLEAR
    {WIDGET_IDLE,    0, NOFUNC}             // EV_WIDGET_TIMEOUT
};
 
/*********************  State transition functions ***************************/
 
// Start by turning widget dispenser on
// ------------------------------------
static void DispenseWidget(void)
{
    WidgetDispenser (TRUE);
    execSetTimer (WIDGET_TIMER, WIDGET_TIME, EV_WIDGET_TIMEOUT);
}
 
// Turn widget dispenser off, widget handler on
// --------------------------------------------
static void HandleWidget(void)
{
    WidgetDispenser (FALSE);
    WidgetHandler (TRUE);
    execSetTimer (WIDGET_TIMER, WIDGET_TIME, EV_WIDGET_TIMEOUT);
}
 
// Turn widget handler off
// -----------------------
static void StopWidget(void)
{
    WidgetHandler (FALSE);
    execSetTimer (WIDGET_TIMER, WIDGET_TIME, EV_WIDGET_TIMEOUT);
}
 
// Record the removal of a widget by sending a number
// --------------------------------------------------
static void RecordWidget(void)
{
    EmitCodeSomewhere (0x4000 + execTransitionTag);
    execSetTimer (WIDGET_TIMER, WIDGET_TIME, EV_WIDGET_TIMEOUT);
}
 
// Log fault by sending the fault number somewhere
// -----------------------------------------------
static void LogWidgetFault(void)
{
    EmitCodeSomewhere (0x8000 + execTransitionTag);
}

Widget04.c; Door sequencer state machine:

#include "Exec.h"
 
/*********************  State transition table *******************************/
 
//{{EXEC_SM_DECLARE(SM_DOOR_CONTROL) – if used, this would go here, with:
//}}
 
//  States
//  ------
#define DOOR_CLOSED       1
#define DOOR_OPENING      2
#define DOOR_OPEN         3
#define DOOR_CLOSING      4
 
//  State transition functions
//  --------------------------
static void OpenDoor(void);
static void TriggerWidget(void);
static void CloseDoor(void);
 
//{{EXEC_SM_DEFINE(SM_DOOR_CONTROL) – if used, this would go here, with:
//}}
 
//  State table
//  -----------
VCONST struct execStateTransitionDef smDoorTransition[DOOR_STATES *
                                                      DOOR_EVENTS] = 
{
//  DOOR_CLOSED:
//  -----------
    {DOOR_OPENING,   0, OpenDoor},          // EV_BUTTON_PUSHED
    {DOOR_CLOSED,    0, NOFUNC},            // EV_DOOR_OPEN
    {DOOR_CLOSED,    0, NOFUNC},            // EV_DOOR_CLOSED
    {DOOR_CLOSED,    0, NOFUNC},            // EV_DOOR_TIMEOUT
 
//  DOOR_OPENING:
//  ------------
    {DOOR_OPENING,   0, NOFUNC},            // EV_BUTTON_PUSHED
    {DOOR_OPEN,      0, TriggerWidget},     // EV_DOOR_OPEN
    {DOOR_OPENING,   0, NOFUNC},            // EV_DOOR_CLOSED
    {DOOR_CLOSING,   0, CloseDoor},         // EV_DOOR_TIMEOUT
 
//  DOOR_OPEN:
//  ---------
    {DOOR_OPEN,      0, NOFUNC},            // EV_BUTTON_PUSHED
    {DOOR_OPEN,      0, NOFUNC},            // EV_DOOR_OPEN
    {DOOR_OPEN,      0, NOFUNC},            // EV_DOOR_CLOSED
    {DOOR_CLOSING,   0, CloseDoor},         // EV_DOOR_TIMEOUT
 
//  DOOR_CLOSING:
//  ------------
    {DOOR_OPENING,   0, OpenDoor },         // EV_BUTTON_PUSHED
    {DOOR_CLOSING,   0, NOFUNC},            // EV_DOOR_OPEN
    {DOOR_CLOSING,   0, NOFUNC},            // EV_DOOR_CLOSED
    {DOOR_CLOSING,   0, NOFUNC}             // EV_DOOR_TIMEOUT
};
 
/*********************  State transition functions ***************************/
 
// Activate the door opener to open it
// -----------------------------------
static void OpenDoor(void)
{
    EnergiseDoor (TRUE);
    execSetTimer (DOOR_TIMER, DOOR_TIME, EV_DOOR_TIMEOUT);
}
 
// Start the widget sequencer off
// ------------------------------
static void TriggerWidget(void)
{
    execPostEvent (EV_DOOR_READY);
}
 
// De-activate the door opener to close it
// ---------------------------------------
static void CloseDoor(void)
{
    EnergiseDoor (FALSE);
}