blob: d050adc018b6aa810d18c447f7b9e963a8763718 [file] [log] [blame]
/*
* File: CvStateMachine.cpp
* Author: mony
*
* Created on September 21, 2012, 4:54 PM
*/
#include <string>
#include <list>
#include "CvStateMachine.h"
#include "CvLogger.h"
namespace CvShared
{
////////////////////////////////////////////////////////////////////////////////
CvStateMachine::CvStateMachine( const char* apName ) :
m_name(apName), m_mutex( (CvString("sm-")+apName).c_str() )
{
m_mutex.Create();
}
CvStateMachine::~CvStateMachine( )
{
CMapTransitions::iterator itr = m_mapTransitions.begin();
while ( itr != m_mapTransitions.end() )
{
CMapTransitions::iterator itrTmp = itr;
++itr;
CvSmTransition* pTransition = itrTmp->second;
m_mapTransitions.erase( itrTmp );
if ( pTransition != NULL )
delete pTransition;
}
}
bool CvStateMachine::AddTransition( State_t aState, Event_t aEvent, const CvSmTransition& aTransition )
{
CvMutexLock lock(m_mutex);
if ( m_mapStates.count(aState) < 1 )
{
LogMessage( enLogLevel_Error, "SM [%s]: Cannot add transition - state [%d] not found", m_name.c_str(), aState );
return false;
}
if ( m_mapEvents.count(aEvent) < 1 )
{
LogMessage( enLogLevel_Error, "SM [%s]: Cannot add transition - event [%d] not found", m_name.c_str(), aEvent );
return false;
}
m_mapTransitions[ MakeTransitionKey(aState,aEvent) ] = aTransition.Duplicate();
return true;
}
bool CvStateMachine::Start( State_t aInitialState )
{
CvMutexLock lock(m_mutex);
if ( m_mapStates.count(aInitialState) < 1 )
{
LogMessage( enLogLevel_Error, "SM [%s]: Cannot start - initial state [%d] not found", m_name.c_str(), aInitialState );
return false;
}
m_state = aInitialState;
LogMessage( enLogLevel_Info, "SM [%s] started with initial state [%s]", m_name.c_str(), m_mapStates[m_state].c_str() );
return true;
}
bool CvStateMachine::Signal( Event_t aEvent, void* apData )
{
CvMutexLock lock(m_mutex);
if ( m_mapStates.count(m_state) < 1 )
{
LogMessage( enLogLevel_Error, "SM [%s]: Cannot signal - current state [%d] is not valid. Probably state machine was not started yet",
m_name.c_str(), m_state );
return false;
}
if ( m_mapEvents.count(aEvent) < 1 )
{
LogMessage( enLogLevel_Error, "SM [%s]: Cannot signal - event [%d] not found", m_name.c_str(), aEvent );
return false;
}
CTransitionKey transitionKey = MakeTransitionKey( m_state, aEvent );
if ( m_mapTransitions.count(transitionKey) < 1 )
{
LogMessage( enLogLevel_Error, "SM [%s]: No transition defined for state [%s] and event [%s]",
m_name.c_str(), m_mapStates[m_state].c_str(), m_mapEvents[aEvent].c_str() );
return false;
}
if ( m_mapTransitions[transitionKey] == NULL )
{
LogMessage( enLogLevel_Error, "SM [%s]: Transition for state [%s] and event [%s] is NULL",
m_name.c_str(), m_mapStates[m_state].c_str(), m_mapEvents[aEvent].c_str() );
return false;
}
State_t newState = INVALID_STATE;
bool bOk = m_mapTransitions[transitionKey]->Execute( apData, newState );
if ( bOk )
{
if ( m_mapStates.count( newState ) < 1 )
{
LogMessage( enLogLevel_Error, "SM [%s]: Cannot change state - new state [%d] not found", m_name.c_str(), newState );
return false;
}
LogMessage( enLogLevel_Info, "SM [%s]: State [%s] Event [%s] -> State [%s]",
m_name.c_str(), m_mapStates[m_state].c_str(), m_mapEvents[aEvent].c_str(), m_mapStates[newState].c_str() );
m_state = newState;
}
else
{
if ( newState != INVALID_STATE )
{
if ( m_mapStates.count( newState ) < 1 )
{
LogMessage( enLogLevel_Error, "SM [%s]: Cannot change state - ERROR state [%d] not found", m_name.c_str(), newState );
return false;
}
LogMessage( enLogLevel_Info, "SM [%s]: State [%s] Event [%s] -> ERROR state [%s]",
m_name.c_str(), m_mapStates[m_state].c_str(), m_mapEvents[aEvent].c_str(), m_mapStates[newState].c_str() );
m_state = newState;
}
else
{
LogMessage( enLogLevel_Info, "SM [%s]: State [%s] Event [%s] -> ERROR (stays in current state)",
m_name.c_str(), m_mapStates[m_state].c_str(), m_mapEvents[aEvent].c_str() );
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
CvSmTransitionSimple::CvSmTransitionSimple( const CvSmTransitionSimple& aOther ) :
m_pHandler(aOther.m_pHandler), m_listActions(aOther.m_listActions),
m_newState(aOther.m_newState), m_errorState(aOther.m_errorState),
m_errorAction(aOther.m_errorAction)
{
}
CvSmTransition* CvSmTransitionSimple::Duplicate() const
{
return new CvSmTransitionSimple(*this);
}
bool CvSmTransitionSimple::Execute( void* apData, OUT CvStateMachine::State_t& aNewState )
{
for ( CListActions::iterator itr = m_listActions.begin();
itr != m_listActions.end();
++itr )
{
CvSmEventHandler::Action_t action = *itr;
if ( !(m_pHandler->*action)( apData ) )
{
if ( m_errorAction != NULL )
!(m_pHandler->*m_errorAction)( apData );
aNewState = m_errorState;
return false;
}
}
aNewState = m_newState;
return true;
}
////////////////////////////////////////////////////////////////////////////////
CvSmTransitionConditional::CvSmTransitionConditional( const CvSmTransitionConditional& aOther ) :
m_pHandler(aOther.m_pHandler), m_condition(aOther.m_condition),
m_transitionOnTrue(aOther.m_transitionOnTrue), m_transitionOnFalse(aOther.m_transitionOnFalse)
{
}
CvSmTransition* CvSmTransitionConditional::Duplicate() const
{
return new CvSmTransitionConditional(*this);
}
bool CvSmTransitionConditional::Execute( void* apData, OUT CvStateMachine::State_t& aNewState )
{
if ( (m_pHandler->*m_condition)( apData ) )
return m_transitionOnTrue.Execute( apData, aNewState );
else
return m_transitionOnFalse.Execute( apData, aNewState );
}
} //namespace CvShared