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

StateMachineLib/ParallelStateMachine.h

Committer:
martin13
Date:
2021-02-02
Revision:
4:22b4462fcb26
Parent:
0:f4fdca2c4c67

File content as of revision 4:22b4462fcb26:

////////////////////////////////////////////////////////////////////////////////
// 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__*/