Table driven Finite State Machine library based on the Harel state machine, supporting actions on transitions, state entry and state exit. Comes with example illustrating use with interrupts and timers. 03/01/2010 - fixed potential memory leak in DebugTrace.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
snatch59
Date:
Sun Jan 03 11:56:03 2010 +0000
Commit message:

Changed in this revision

DebugTrace.cpp Show annotated file Show diff for this revision Revisions of this file
DebugTrace.h Show annotated file Show diff for this revision Revisions of this file
FSM.h Show annotated file Show diff for this revision Revisions of this file
FSMDefs.h Show annotated file Show diff for this revision Revisions of this file
MyInterruptHandler.cpp Show annotated file Show diff for this revision Revisions of this file
MyInterruptHandler.h Show annotated file Show diff for this revision Revisions of this file
State.h Show annotated file Show diff for this revision Revisions of this file
StateTransition.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DebugTrace.cpp	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,143 @@
+/*
+* DebugTrace. Allows dumping debug messages/values to serial or
+* to file.
+*
+* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
+*
+* This file is part of DebugTrace.
+*
+* DebugTrace is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+* 
+* DebugTrace is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DebugTrace.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "DebugTrace.h"
+#include <mbed.h>
+#include <stdarg.h>
+#include <string.h>
+
+Serial logSerial(USBTX, USBRX);
+LocalFileSystem local("local");
+
+const char* FILE_PATH = "/local/";
+const char* EXTN = ".bak";
+
+DebugTrace::DebugTrace(eLog on, eLogTarget mode, const char* fileName, int maxSize) :
+    enabled(on), logMode(mode), maxFileSize(maxSize), currentFileSize(0),
+    logFileStatus(0)
+{
+    // allocate memory for file name strings
+    int str_size = (strlen(fileName) + strlen(FILE_PATH) + strlen(EXTN) + 1) * sizeof(char); 
+    logFile = (char*)malloc(str_size);
+    logFileBackup = (char*)malloc(str_size);
+    
+    // add path to log file name
+    strcpy(logFile, FILE_PATH);
+    strcat(logFile, fileName);
+    
+    // create backup file name
+    strcpy(logFileBackup, logFile);
+    strcpy(logFileBackup, strtok(logFileBackup, "."));
+    strcat(logFileBackup, EXTN);
+}
+ 
+DebugTrace::~DebugTrace()
+{
+    // dust to dust, ashes to ashes
+    if (logFile != NULL) free(logFile);
+    if (logFileBackup != NULL) free(logFileBackup);
+}
+
+void DebugTrace::clear()
+{
+    // don't care about whether these fail
+    remove(logFile);    
+    remove(logFileBackup);
+}
+
+void DebugTrace::backupLog()
+{
+    // delete previous backup file
+    if (remove(logFileBackup))
+    {
+        // standard copy stuff
+        char ch;
+        FILE* to = fopen(logFileBackup, "wb");
+        if (NULL != to)
+        {
+            FILE* from = fopen(logFile, "rb");   
+            if (NULL != from)
+            {
+                while(!feof(from))
+                {
+                    ch = fgetc(from);
+                    if (ferror(from)) break;
+                    
+                    if(!feof(from)) fputc(ch, to);
+                    if (ferror(to)) break;
+                }
+            }
+            
+            if (NULL != from) fclose(from);
+            if (NULL != to) fclose(to);
+        }
+    }
+
+    // now delete the log file, so we are ready to start again
+    // even if backup creation failed - the show must go on!
+    logFileStatus = remove(logFile);
+}
+
+void DebugTrace::traceOut(const char* fmt, ...)
+{
+    if (enabled)
+    {
+        va_list ap;            // argument list pointer
+        va_start(ap, fmt);
+        
+        if (TO_SERIAL == logMode)
+        {
+            vfprintf(logSerial, fmt, ap);
+        }
+        else    // TO_FILE
+        {
+            if (0 == logFileStatus)    // otherwise we failed to remove a full log file
+            {
+                // Write data to file. Note the file size may go over limit
+                // as we check total size afterwards, using the size written to file.
+                // This is not a big issue, as this mechanism is only here
+                // to stop the file growing unchecked. Just remember log file sizes may
+                // be some what over (as apposed to some what under), so don't push it 
+                // with the max file size.
+                FILE* fp = fopen(logFile, "a");
+                if (NULL == fp)
+                {
+                    va_end(ap);
+                    return;
+                }
+                int size_written = vfprintf(fp, fmt, ap);
+                fclose(fp);
+                
+                // check if we are over the max file size
+                // if so backup file and start again
+                currentFileSize += size_written;
+                if (currentFileSize >= maxFileSize)
+                {
+                    backupLog();
+                    currentFileSize = 0;
+                }
+            }
+        }
+        
+        va_end(ap);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DebugTrace.h	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,50 @@
+/*
+* DebugTrace. Allows dumping debug messages/values to serial or
+* to file.
+*
+* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
+*
+* This file is part of DebugTrace.
+*
+* DebugTrace is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+* 
+* DebugTrace is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DebugTrace.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SNATCH59_DEBUGTRACE_H
+#define SNATCH59_DEBUGTRACE_H
+
+enum eLog {OFF, ON};
+enum eLogTarget {TO_SERIAL, TO_FILE};
+
+class DebugTrace
+{
+public:
+    DebugTrace(eLog on, eLogTarget mode, const char* fileName = "log.txt", const int maxSize = 1024);
+    ~DebugTrace();
+   
+    void clear();
+    void traceOut(const char* fmt, ...);
+    
+private:
+    eLog enabled;
+    eLogTarget logMode;
+    int maxFileSize;
+    int currentFileSize;
+    char* logFile;
+    char* logFileBackup;
+    int logFileStatus;            // if things go wrong, don't write any more data to file
+    
+    void backupLog();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FSM.h	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,192 @@
+/*
+* FiniteStateMachine. Table driven Finite State Machine library 
+* based on theHarel state machine, supporting actions on transitions, state
+* entry and state exit.
+*
+* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
+*
+* This file is part of FiniteStateMachine.
+*
+* FiniteStateMachine is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+* 
+* FiniteStateMachine is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DebugTrace.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SNATCH59_FSM_H
+#define SNATCH59_FSM_H
+
+#include <mbed.h>
+#include "FSMDefs.h"
+
+STATE_TEMPLATE_ class State;
+
+TRANS_DEF_TEMPLATE_ 
+struct TransitionDefinition
+{
+    const char* ownerState;
+    int    eventId;
+    StateBehaviour mode;
+    ActionPtrType action;
+    const char* newState;
+};
+
+TRANS_DEF_TEMPLATE_
+class StateDefinition
+{
+public:
+    const char* stateName;
+    ActionPtrType stateEntryAction;
+    ActionPtrType stateExitAction;
+};
+
+#include "State.h"
+
+FSM_TEMPLATE_ 
+class FiniteStateMachine
+{
+public:
+    FiniteStateMachine();
+    ~FiniteStateMachine();
+    
+    void initialize(StateObjectType* owner, 
+                    const STATE_DEFINITION_* states, const int total_states, 
+                    const TRANSITION_DEFINITION_* transitions, const int total_transitions,
+                    const char* this_state);
+    void traverse(const int new_event);
+    void forceToState(const char* stat_name);
+    bool isState(const char* this_state) const;
+    const char* getCurrentStateName() const;
+
+private:
+    void addStates(const STATE_DEFINITION_* states, const int total_states, 
+                          const TRANSITION_DEFINITION_* &transitions, const int total_transitions);
+    void executeTraversal(const int event);
+
+    // Data Members
+    STATE_* currentState;          
+    int totalStates;            
+    StateObjectType* itsStateObject;      
+    STATE_* itsStates[maxStates];   
+};
+
+FSM_TEMPLATE_
+inline const char* FINITE_STATE_MACHINE_::getCurrentStateName() const
+{
+    return (currentState->getName());
+}
+
+FSM_TEMPLATE_
+inline bool FINITE_STATE_MACHINE_::isState(const char* this_state) const
+{
+    if (0 == strcmp(currentState->getName(), this_state))    return true;
+    
+    return false;
+}
+
+FSM_TEMPLATE_
+FINITE_STATE_MACHINE_::FiniteStateMachine() : totalStates(0), currentState(NULL)
+{
+}
+
+FSM_TEMPLATE_
+FINITE_STATE_MACHINE_::~FiniteStateMachine()
+{
+    if (itsStates != NULL)
+    {
+        // delete all its States
+        for (int i = 0; i < totalStates; i++)
+        {
+            delete itsStates[i];
+        }
+    }
+}
+
+FSM_TEMPLATE_
+void FINITE_STATE_MACHINE_::initialize(StateObjectType* owner, 
+                                       const STATE_DEFINITION_* states, const int total_states,
+                                       const TRANSITION_DEFINITION_* transitions, const int total_transitions,
+                                       const char* this_state)
+{
+    itsStateObject = owner;
+
+    for (int k = 0; k < total_states; k++)
+    {
+        addStates(states, total_states, transitions, total_transitions);
+    }
+
+    forceToState(this_state);
+}
+
+FSM_TEMPLATE_
+void FINITE_STATE_MACHINE_::traverse(const int new_event)
+{
+    if (0 == totalStates)
+    {
+        return;
+    }
+
+    STATE_TRANSITION_* associated_transition = NULL;  
+    STATE_* new_state = currentState->match(new_event, associated_transition);
+        
+    if (new_state != NULL && associated_transition != NULL)
+    {
+        StateBehaviour behaviour = associated_transition->getStateBehaviour();  
+
+        if (actions == behaviour)
+        {
+            currentState->doExitAction(itsStateObject);
+        }
+    
+        currentState = new_state;
+
+        associated_transition->doAction(itsStateObject);
+
+        if (actions == behaviour)
+        {
+            new_state->doEntryAction(itsStateObject);
+        }
+    }
+}
+
+FSM_TEMPLATE_
+void FINITE_STATE_MACHINE_::forceToState(const char* state_name)
+{
+    for (int i = 0; i < totalStates; i++)
+    {
+        if (0 == strcmp(itsStates[i]->getName(), state_name))
+        {
+            currentState = itsStates[i];
+            break;
+        }
+    } 
+}
+
+FSM_TEMPLATE_
+void FINITE_STATE_MACHINE_::addStates(const STATE_DEFINITION_* states, const int total_states,
+                                      const TRANSITION_DEFINITION_* &transitions, const int total_transitions)
+{
+    for (int i = 0; i < total_states; i++)
+    {
+            
+            itsStates[i] = new STATE_(states[i].stateName, 
+                                      states[i].stateEntryAction, 
+                                      states[i].stateExitAction);
+    }
+    totalStates = total_states;
+
+    for (int i = 0; i < total_states; i++)
+    {
+        itsStates[i]->addTransitions(transitions, total_transitions, itsStates, total_states);
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FSMDefs.h	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,39 @@
+/*
+* FiniteStateMachine. Table driven Finite State Machine library 
+* based on theHarel state machine, supporting actions on transitions, state
+* entry and state exit.
+*
+* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
+*
+* This file is part of FiniteStateMachine.
+*
+* FiniteStateMachine is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+* 
+* FiniteStateMachine is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DebugTrace.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SNATCH59_FSMDEFS_H
+#define SNATCH59_FSMDEFS_H
+
+#define FSM_TEMPLATE_        template<class StateObjectType, class ActionPtrType, int maxStates>
+#define STATE_TEMPLATE_        template<class StateObjectType, class ActionPtrType>
+#define TRANS_DEF_TEMPLATE_    template<class ActionPtrType>
+
+#define FINITE_STATE_MACHINE_    FiniteStateMachine<StateObjectType, ActionPtrType, maxStates>
+#define STATE_                    State<StateObjectType, ActionPtrType>
+#define STATE_TRANSITION_        StateTransition<StateObjectType, ActionPtrType>
+#define TRANSITION_DEFINITION_    TransitionDefinition<ActionPtrType>
+#define STATE_DEFINITION_        StateDefinition<ActionPtrType>
+
+enum StateBehaviour {actions, noactions};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyInterruptHandler.cpp	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,106 @@
+/*
+* FiniteStateMachine. Table driven Finite State Machine library 
+* based on theHarel state machine, supporting actions on transitions, state
+* entry and state exit.
+*
+* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
+*
+* This file is part of FiniteStateMachine.
+*
+* FiniteStateMachine is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+* 
+* FiniteStateMachine is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DebugTrace.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <mbed.h>
+#include "MyInterruptHandler.h"
+#include "FSMDefs.h"
+#include "FSM.h"
+#include "DebugTrace.h"
+
+DebugTrace pc(ON, TO_SERIAL);
+
+typedef void (MyInterruptHandler::* clientActionPtr)( );
+
+// states
+const char* S_START     = "Start";
+const char* S_LED_SEQ1  = "LedSeq1";
+const char* S_LED_SEQ2  = "LedSeq2";
+
+const StateDefinition<clientActionPtr> states[] = 
+   {// state,        entry action,                         exit action
+       S_START,       NULL,                                NULL,
+       S_LED_SEQ1,    &MyInterruptHandler::ledSequence1,   NULL,
+       S_LED_SEQ2,    &MyInterruptHandler::ledSequence2,   NULL
+   };
+const int total_states = sizeof(states)/sizeof(StateDefinition<clientActionPtr>);
+
+// transitions
+const TransitionDefinition<clientActionPtr> transitions[] = 
+   {// start state,     event,          type        transition action,    end state
+       S_START,         (int)intr1,     actions,    NULL,                 S_LED_SEQ1,
+       S_LED_SEQ1,      (int)intr2,     actions,    NULL,                 S_LED_SEQ2,
+       S_LED_SEQ2,      (int)intr1,     actions,    NULL,                 S_LED_SEQ1,
+       S_LED_SEQ1,      (int)tickr1,    actions,    NULL,                 S_LED_SEQ1,
+       S_LED_SEQ2,      (int)tickr1,    actions,    NULL,                 S_LED_SEQ2,
+   };
+const int total_transitions = sizeof(transitions)/sizeof(TransitionDefinition<clientActionPtr>);
+
+// declare a state machine
+static FiniteStateMachine<MyInterruptHandler, clientActionPtr, total_states> itsStateMachine;
+
+// put LEDs on a bus for convenience
+BusOut leds(LED1, LED2, LED3, LED4);
+
+
+MyInterruptHandler::MyInterruptHandler() : interrupt1(p5), interrupt2(p6)
+{
+    // init state machine
+    itsStateMachine.initialize(this, states, total_states, transitions, total_transitions, S_START);
+    
+    // attach callbacks for interrupts and timer
+    interrupt1.rise(this, &MyInterruptHandler::intrhandler1);
+    interrupt2.rise(this, &MyInterruptHandler::intrhandler2);
+    ticker1.attach(this, &MyInterruptHandler::tickerhandler1, 0.5);
+}
+
+void MyInterruptHandler::processEvent(clientEvent event_id)
+{
+    itsStateMachine.traverse((int)event_id);
+}
+
+void MyInterruptHandler::intrhandler1()
+{
+    processEvent(intr1);
+}
+
+void MyInterruptHandler::intrhandler2()
+{
+    processEvent(intr2);
+}
+
+void MyInterruptHandler::tickerhandler1()
+{
+    processEvent(tickr1);
+}
+
+void MyInterruptHandler::ledSequence1()
+{
+    pc.traceOut("ledSequence1\r\n");
+    (0x00 == leds || 0x08 == leds) ? leds = 1 : leds = leds << 1;
+}
+
+void MyInterruptHandler::ledSequence2()
+{
+    pc.traceOut("ledSequence2\r\n");
+    (0x00 == leds || 0x01 == leds) ? leds = 8 : leds = leds >> 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyInterruptHandler.h	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,52 @@
+/*
+* FiniteStateMachine. Table driven Finite State Machine library 
+* based on theHarel state machine, supporting actions on transitions, state
+* entry and state exit.
+*
+* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
+*
+* This file is part of FiniteStateMachine.
+*
+* FiniteStateMachine is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+* 
+* FiniteStateMachine is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DebugTrace.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SNATCH59_MYINTERRUPTHANDLER_H
+#define SNATCH59_MYINTERRUPTHANDLER_H
+
+// event names
+enum clientEvent {intr1, intr2, tickr1};
+
+class MyInterruptHandler
+{
+public:
+    MyInterruptHandler();
+
+    void processEvent(clientEvent eventId);
+    
+    // interrupt & timer handlers
+    void intrhandler1();
+    void intrhandler2();
+    void tickerhandler1();
+
+    // state or transition actions
+    void ledSequence1();
+    void ledSequence2();
+    
+private:
+    InterruptIn interrupt1;
+    InterruptIn interrupt2;
+    Ticker ticker1;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/State.h	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,162 @@
+/*
+* FiniteStateMachine. Table driven Finite State Machine library 
+* based on theHarel state machine, supporting actions on transitions, state
+* entry and state exit.
+*
+* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
+*
+* This file is part of FiniteStateMachine.
+*
+* FiniteStateMachine is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+* 
+* FiniteStateMachine is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DebugTrace.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SNATCH59_STATE_H
+#define SNATCH59_STATE_H
+
+#include <mbed.h> 
+#include "FSMDefs.h"
+#include "FSM.h"
+
+STATE_TEMPLATE_ class StateTransition;
+
+#include "StateTransition.h"
+
+STATE_TEMPLATE_
+class State
+{
+    
+public:
+    State(const char* state_name, ActionPtrType entry_action_ptr, ActionPtrType exit_action_ptr);
+    ~State( );
+    
+    STATE_*    match(const int event_id, STATE_TRANSITION_* &transition) const;
+    void addTransitions(const TRANSITION_DEFINITION_* &transitions, const int total_transitions,
+                        STATE_** states, const int total_states);
+    void doEntryAction(StateObjectType* &its_state_object);
+    void doExitAction(StateObjectType* &its_state_object);
+    const char*    getName( ) const;
+    
+private:
+    const char*    name;
+    int totalTransitions;
+    ActionPtrType entryAction;
+    ActionPtrType exitAction;
+    STATE_TRANSITION_**    itsTransitions;
+};
+
+STATE_TEMPLATE_
+inline const char* STATE_::getName() const
+{
+    return name;
+}
+
+STATE_TEMPLATE_
+STATE_::State(const char* state_name, ActionPtrType entry_action_ptr, ActionPtrType exit_action_ptr) : 
+    name(state_name), entryAction(entry_action_ptr), 
+    exitAction(exit_action_ptr), totalTransitions(0)
+{
+}
+
+STATE_TEMPLATE_
+STATE_::~State( )
+{
+    if (itsTransitions != NULL)
+    {
+        for (int i = 0; i < totalTransitions; i++)
+        {
+            delete itsTransitions[i];
+        }
+    
+        // dust to dust, ashes to ashes
+        free(itsTransitions);
+    }
+}
+
+STATE_TEMPLATE_
+void STATE_::addTransitions(const TRANSITION_DEFINITION_* &transitions, const int total_transitions, 
+                            STATE_** states, const int total_states)
+{
+    int tcount = 0;
+    for (int i = 0; i < total_transitions; i++)
+    {
+        TRANSITION_DEFINITION_ tdef = transitions[i];
+        if (0 == strcmp(name, tdef.ownerState))
+        {
+            tcount++;
+        }
+    }
+
+    itsTransitions = (STATE_TRANSITION_**)malloc(sizeof(STATE_TRANSITION_*)*tcount);
+
+    for (int i = 0; i < total_transitions; i++)
+    {
+        TRANSITION_DEFINITION_ tdef = transitions[i];
+        if (0 == strcmp(name, tdef.ownerState))
+        {
+            STATE_* new_state_ptr = NULL;
+            for (int k = 0; k < total_states; k++)
+            {
+                if (0 == strcmp(states[k]->getName(), tdef.newState))
+                {
+                    new_state_ptr = states[k];
+                    break;
+                }
+            }
+
+            itsTransitions[totalTransitions++] = 
+                    new STATE_TRANSITION_(tdef.eventId, tdef.action, new_state_ptr, tdef.mode);        
+        }
+    }
+}
+
+STATE_TEMPLATE_
+STATE_* STATE_::match(const int event_id, STATE_TRANSITION_* &transition) const
+{
+    if (0 == totalTransitions)
+    {
+        return NULL;
+    }
+
+    STATE_* new_state = NULL;
+    
+    int i = 0;
+    do
+    {
+        new_state = itsTransitions[i]->match(event_id);
+        transition = itsTransitions[i++];
+    }
+    while (NULL == new_state && i < totalTransitions);
+    
+    return new_state;
+}
+
+STATE_TEMPLATE_
+void STATE_::doEntryAction(StateObjectType* &its_state_object)
+{
+      if (entryAction != NULL)        
+      {
+        (its_state_object->*entryAction)( );
+    }
+}
+
+STATE_TEMPLATE_
+void STATE_::doExitAction(StateObjectType* &its_state_object)
+{
+      if (exitAction != NULL)
+      {
+        (its_state_object->*exitAction)( );
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/StateTransition.h	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,81 @@
+/*
+* FiniteStateMachine. Table driven Finite State Machine library 
+* based on theHarel state machine, supporting actions on transitions, state
+* entry and state exit.
+*
+* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
+*
+* This file is part of FiniteStateMachine.
+*
+* FiniteStateMachine is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+* 
+* FiniteStateMachine is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DebugTrace.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SNATCH59_STATETRANSITION_H
+#define SNATCH59_STATETRANSITION_H
+
+#include <mbed.h> 
+#include "FSMDefs.h"
+
+STATE_TEMPLATE_ class State;
+
+#include "State.h"
+ 
+STATE_TEMPLATE_
+class StateTransition
+{
+    
+public:
+    StateTransition(int event_id, ActionPtrType action, STATE_* state_ptr, StateBehaviour behaviour);
+    
+    STATE_* match(const int event_id) const;
+    void doAction(StateObjectType* &its_state_object) const;
+    StateBehaviour getStateBehaviour() const;
+    
+private:
+    int eventId;
+    ActionPtrType action;
+    STATE_* newState;
+    StateBehaviour mode;
+};
+
+STATE_TEMPLATE_
+inline STATE_* STATE_TRANSITION_::match(const int event_id) const
+{
+    if (eventId == event_id)    return newState;
+    
+    return NULL;
+}
+
+STATE_TEMPLATE_
+inline StateBehaviour STATE_TRANSITION_::getStateBehaviour() const
+{
+    return mode;
+}
+
+STATE_TEMPLATE_
+STATE_TRANSITION_::StateTransition(int event_id, ActionPtrType action_ptr, STATE_* state_ptr, StateBehaviour behaviour) : 
+    eventId(event_id), action(action_ptr), newState(state_ptr), mode(behaviour)
+{
+}
+
+STATE_TEMPLATE_
+void STATE_TRANSITION_::doAction(StateObjectType* &its_state_object) const
+{
+    if (action != NULL)
+    {
+        (its_state_object->*action)( );
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,36 @@
+/*
+* FiniteStateMachine. Table driven Finite State Machine library 
+* based on theHarel state machine, supporting actions on transitions, state
+* entry and state exit.
+*
+* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
+*
+* This file is part of FiniteStateMachine.
+*
+* FiniteStateMachine is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+* 
+* FiniteStateMachine is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DebugTrace.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <mbed.h>
+#include "MyInterruptHandler.h"
+
+int main() 
+{
+    MyInterruptHandler client;
+
+    while (true)
+    {
+        wait(5);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Jan 03 11:56:03 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0