This library is designed to create and run state graphs. It supports hierarchical states and parallel states execution.

Revision:
0:f4fdca2c4c67
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/StateMachineLib/ParallelStateMachine.h	Tue Oct 03 08:29:22 2017 +0000
@@ -0,0 +1,165 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright Rottor SAS 2017
+// All rigths reserved.
+//
+// File Name : ParallelStateMachine.h
+// Authors : Martin Matignon
+//
+// If you find any bug or if you have any question please contact
+// Martin Matignon <martin.matignon@rottor.fr>
+// Nicolas Forestier <nicolas.forestier@rottor.fr>
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __SM_PARALLEL_STATE_MACHINE_H__
+#define __SM_PARALLEL_STATE_MACHINE_H__
+
+#include "StateMachine.h"
+
+/** A class for storing and calling a pointer to a static or member function
+ */
+class OutcomesResolver {
+ 
+public:
+ 
+    /** Constructor
+     */
+    OutcomesResolver():
+      _function(0),
+      _object(0)
+    {
+        /* Empty */
+    }
+ 
+    /** Attach a static function
+     */
+    void attachOutcomesResolver(const char* (*function)(const char**, int) = 0) {
+        _function = function;
+        _object = 0;
+    }
+    
+    /** Attach a member function
+     * 
+     *  @param object The object pointer to invoke the member function on (i.e. the this pointer)
+     *  @param function The address of member function to attach 
+     */
+    template<typename T>
+    void attachOutcomesResolver(T *object, const char* (T::*member)(const char**, int)) {
+        _object = static_cast<void*>(object);
+        memcpy(_member, (char*)&member, sizeof(member));
+        _membercaller = &OutcomesResolver::membercaller<T>;
+        _function = 0;
+    }
+ 
+    /** Call the attached static or member function
+     */        
+    const char* callOutcomesResolver(const char** outcomes, int nb_outcomes) {
+        if (_function) {
+            return _function(outcomes, nb_outcomes);
+        } else if (_object) {
+            return  _membercaller(_object, _member, outcomes, nb_outcomes);
+        }
+        return NULL;
+    }
+        
+private:
+ 
+    template<typename T>
+    static const char* membercaller(void *object,
+                                    char *member,
+                                    const char** outcomes,
+                                    int nb_outcomes) {    
+        T* o = static_cast<T*>(object);
+        const char* (T::*m)(const char**, int);
+        memcpy((char*)&m, member, sizeof(m));
+        return (o->*m)(outcomes, nb_outcomes);
+    }
+    
+    /** Static function pointer - 0 if none attached
+     */
+    const char* (*_function)(const char**, int);
+    
+    /** Object this pointer - 0 if none attached
+     */
+    void *_object;
+    
+    /** Raw member function pointer storage - converted back by registered _membercaller
+     */
+    char _member[16];
+    
+    /** Registered membercaller function to convert back and call _member on _object
+     */
+    const char* (*_membercaller)(void*, char*, const char**, int);
+    
+};
+
+/** A class to store and execute parallel states
+ */
+class ParallelStateMachine : public StateMachine,
+                             public OutcomesResolver {
+  
+public:
+
+    ParallelStateMachine(const char* uuid, UserData *ud = new UserData()): 
+       StateMachine(uuid, ud) 
+    {
+        attachOutcomesResolver(this, &ParallelStateMachine::defaultOutcomesResolver);
+    }
+    
+    virtual void onEntry(){};
+    
+    virtual const char* onExecute(){
+        
+        int nbStates = this->getNumberStates();
+        State *stateList[nbStates];
+        Thread thread[nbStates];
+        const char* outcomes[nbStates];
+        
+        StateMachine::StateItem_t* states = getStatesList();
+        
+        for (int i=0; i < nbStates; i++)
+        {
+            stateList[i] = states->state;
+            stateList[i]->onEntry();
+            thread[i].start(callback(stateList[i], &State::_onParallelExecute));
+            states = states->next;
+        }
+        
+        for (int i=0; i < nbStates; i++){
+            thread[i].join();
+            stateList[i]->onExit();
+        }
+        
+        for (int i=0; i < nbStates; i++){
+            outcomes[i] = stateList[i]->getOutcome();
+            if (strcmp(outcomes[i], PREEMPTED) == 0){
+                return PREEMPTED;
+            }
+        }
+        
+        // Resolve the states outcomes
+        const char* out = callOutcomesResolver(outcomes, nbStates);
+        if (out != NULL) {
+            return out;
+        }
+        
+        return ABORTED;
+    }
+            
+    virtual void onExit(){}
+    
+    const char* defaultOutcomesResolver(const char** outcomes, int nb_outcomes){
+        
+        // Check if all outcomes are succeded else return aborted
+        for(int i = 0; i < nb_outcomes; i++){
+            
+            if (strcmp(outcomes[i], SUCCEDED) != 0){
+                return ABORTED;
+            }
+        }
+        
+        return SUCCEDED;
+    }
+};
+
+#endif /* #ifndef __SM_PARALLEL_STATE_MACHINE_H__*/
\ No newline at end of file