This library is designed to create and run state graphs. It supports hierarchical states and parallel states execution.
StateMachineLib/source/StateMachine.cpp
- Committer:
- martin13
- Date:
- 2017-10-03
- Revision:
- 0:f4fdca2c4c67
- Child:
- 2:5e2336b52d0a
File content as of revision 0:f4fdca2c4c67:
//////////////////////////////////////////////////////////////////////////////// // Copyright Rottor SAS 2017 // All rigths reserved. // // File Name : StateMachine.cpp // 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> // //////////////////////////////////////////////////////////////////////////////// #include "StateMachine.h" #include "Logger.h" StateMachine::StateItem_t::StateItem_t(State* _state){ state = _state; transitions = new Transitions(); next = NULL; } StateMachine::StateMachine(const char* stateMachineUUID, UserData *ud): State(stateMachineUUID, STATE_MACHINE), m_stateList(NULL), m_nbStates(0), m_currentItem(NULL), m_initalStateUUID(NULL), m_targetStateUUID(NULL), m_userData(ud) { /* Empty */ } void StateMachine::setInitialState(State* state){ m_initalStateUUID = state->getUUID(); m_targetStateUUID = m_initalStateUUID; } void StateMachine::connect(State* state, const char* outcome, State* target){ StateItem_t *item = getItemByUUID(state->getUUID()); Transitions::Transition_t* newT = new Transitions::Transition_t(outcome, target, NULL); item->transitions->addTransition(newT); } void StateMachine::remap(State* state, const char* outcome, State* target){ StateItem_t *item = getItemByUUID(state->getUUID()); if (item != NULL){ Transitions::Transition_t* trans = item->transitions->getTransition(outcome); if (trans != NULL){ trans->target = target; trans->_exit_ = NULL; } } } void StateMachine::connect(State* state, const char* outcome, const char* _exit){ StateItem_t *item = getItemByUUID(state->getUUID()); Transitions::Transition_t* newT = new Transitions::Transition_t(outcome, NULL, _exit); item->transitions->addTransition(newT); } void StateMachine::remap(State* state, const char* outcome, const char* _exit){ StateItem_t *item = getItemByUUID(state->getUUID()); if (item != NULL){ Transitions::Transition_t* trans = item->transitions->getTransition(outcome); if (trans != NULL){ trans->target = NULL; trans->_exit_ = _exit; } } } void StateMachine::_addState(State *state){ StateItem_t *newItem = new StateItem_t(state); if(m_stateList == NULL){ m_stateList = newItem; } else { StateItem_t *temp = m_stateList; while(temp->next != NULL) { temp = temp->next; } temp->next = newItem; } m_nbStates++; } void StateMachine::onEntry(){ /* Empty */ }; const char* StateMachine::onExecute(){ Logger::debug("IN STATE(%s)",m_targetStateUUID); // Find the target item state m_currentItem = getItemByUUID(m_targetStateUUID); // Target state execution m_currentItem->state->onEntry(); const char *outcome = m_currentItem->state->onExecute(); m_currentItem->state->onExit(); // Check if state is not preempted if (isPreempted() || strcmp(outcome, PREEMPTED) == 0) { Logger::debug("{ STATE(%s) : { STATE(%s) : { OUTCOME(PREEMPTED) : EXIT(PREEMPTED) } } }", getUUID(), m_currentItem->state->getUUID()); return PREEMPTED; } // Find transition attached to outcome Transitions::Transition_t* transition = m_currentItem->transitions->getTransition(outcome); if (transition != NULL) { if (transition->target == NULL) { if(transition->_exit_ != NULL) { if (strcmp(outcome, transition->outcome) == 0) { Logger::debug("{ STATE(%s) : { STATE(%s) : { OUTCOME(%s) : EXIT(%s) } } }", getUUID(), m_currentItem->state->getUUID(), outcome, transition->_exit_); // Capture the inital target state uuid m_targetStateUUID = m_initalStateUUID; // Exit state machine with _exit_ outcome return transition->_exit_; } } else{ Logger::err("NO EXIT OUTCOME FOUND FROM STATE(%s)"); } } else{ // Capture the next target state uuid m_targetStateUUID = transition->target->getUUID(); Logger::debug("{ STATE(%s) : { STATE(%s) : { OUTCOME(%s) : STATE(%s) } } }", getUUID(), m_currentItem->state->getUUID(), outcome, m_targetStateUUID); // Recall execution with the next target state return this->onExecute(); } } Logger::err("{ STATE(%s) : { STATE(%s) : { OUTCOME(%s) : STATE(NULL) } } } !!! OUTCOME \"%s::%s\" NO MAPPED !!!", getUUID(), m_currentItem->state->getUUID(), outcome, m_currentItem->state->getUUID(), outcome); // Capture the inital target state uuid m_targetStateUUID = m_initalStateUUID; // State machine finished return outcome; } void StateMachine::onExit(){ /* Empty */ } const char* StateMachine::execute(){ this->onEntry(); const char* outcome = this->onExecute(); this->onExit(); if (preempt_flag){ preempt_flag = false; } return outcome; } StateMachine::StateItem_t* StateMachine::getStatesList(){ return m_stateList; } int StateMachine::getNumberStates(){ return m_nbStates; } UserData* StateMachine::getUserData(){ return m_userData; } void StateMachine::printGraph(string level){ StateItem_t *item = m_stateList; Logger::debug("%s- STATE MACHINE \"%s\":",level.c_str(),getUUID()); level += " "; while(item != NULL) { if (item->state->getType() == STATE_MACHINE){ ((StateMachine *)item->state)->printGraph(level); } else{ Logger::debug("%s- STATE \"%s\"",level.c_str(), item->state->getUUID()); } if (item->transitions != NULL){ item->transitions->printList(level); } item = item->next; } } StateMachine::StateItem_t* StateMachine::getItemByUUID(const char* uuid){ StateItem_t *list = m_stateList; while(list != NULL) { if (strcmp(list->state->getUUID(), uuid) == 0){ return list; } list = list->next; } return NULL; }