00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 #ifdef _MSC_VER
00017         #pragma warning( disable : 4786 ) // 'identifier' : identifier was truncated to 'number' characters in the debug information
00018 
00019 
00020         #pragma warning( disable : 4251 ) // 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
00021 #endif
00022 #ifdef __INTEL_COMPILER
00023         #pragma warning( disable : 985  ) // == C4786
00024 #endif
00025 #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
00026 
00027 #endif
00028 
00029 #include "FSM.h"
00030 #include "FiniteStateMachine-config.h"
00031 #include "FSMErrorCodes.h"
00032 
00033 #ifdef HAVE_LIBIWRAPPER
00034 #       include <ilibrary.h>
00035 #else
00036 #       ifdef WIN32
00037 #               include <windows.h>
00038 #       else
00039 #               include <dlfcn.h>
00040 #       endif
00041 #endif
00042 
00043 namespace FSM {
00044         #ifdef HAVE_LIBIWRAPPER
00045                 using iLIB::iLibrary;
00046         #endif
00047 
00049 
00051 
00052 :m_InitialState("")
00053 ,m_CurrentState(NULL)
00054 ,m_Running(false)
00055 {
00056         RegisterBaseTypes();
00057 }
00058 
00060 
00062 
00063 {
00064         if (m_Running) Stop();
00065         Clear();
00066 }
00067 
00069 
00071 
00072 {
00073         CFSMState *State = NULL;
00074 
00075         State = (CFSMState *)Create(className);
00076         if(State)
00077         {
00078                 State->SetName(stateName);
00079 
00080                 const pair<State_Map::iterator,bool>result = m_States.insert(State_Map::value_type(stateName, State));
00081                 if(result.second == false)
00082                 {
00083                         iThrow(WARNING(FSM_STATE_DEFINED_TWICE), stateName);
00084                 }
00085         }
00086         return State;
00087 }
00088 
00089 CFSMState*      CFiniteStateMachine::GetState(const char *stateName) const
00090 {
00091         CFSMState* res = NULL;
00092         if (stateName)
00093         {
00094                 State_Map::const_iterator i = m_States.find(stateName);
00095                 if(!(i==m_States.end()))
00096                 {
00097                         res = (*i).second;
00098                 } else {
00099                         iThrow(CRITICAL(FSM_STATE_NOT_FOUND), stateName);
00100                 }
00101         } else
00102         {
00103                         iThrow(CRITICAL(FSM_STATE_NOT_FOUND), "");
00104         }
00105         return res;
00106 }
00107 
00108 bool CFiniteStateMachine::DeleteState(CFSMState *state)
00109 {
00110         bool res = false;
00111 
00112         State_Map::iterator i = m_States.begin();
00113         while( !( i == m_States.end() ) )
00114         {
00115                 if ( (*i).second == state )
00116                 {
00117                         if(!(m_Running && m_CurrentState==state))
00118                         {
00119                                 state->DeleteThis();
00120                                 m_States.erase(i);
00121                                 res = true;
00122                         } else {
00123                                 iThrow(CRITICAL(FSM_CANNOT_DELETE_CURRENT), state->GetName());
00124                         }
00125                         break;
00126                 }
00127                 ++i;
00128         }
00129         if (res==false)
00130         {
00131                 iThrow(CRITICAL(FSM_STATE_NOT_FOUND), state->GetName());
00132         }
00133         return res;
00134 }
00135 
00136 bool CFiniteStateMachine::DeleteState(const char *stateName)
00137 {
00138         bool res = false;
00139         CFSMState* state = GetState(stateName);
00140         if (state)
00141         {
00142                 res = DeleteState(state);
00143         } else
00144         {
00145                 iRethrow();
00146         }
00147         return res;
00148 }
00149 
00150 State_Map::const_iterator CFiniteStateMachine::GetStatesBegin() const
00151 {
00152         return m_States.begin();
00153 }
00154 
00155 State_Map::const_iterator CFiniteStateMachine::GetStatesEnd() const
00156 {
00157         return m_States.end();
00158 }
00159 
00161 
00163 
00164 {
00165         CFSMTransition* res = NULL;
00166         CFSMState* state = GetState(stateName);
00167         if (state)
00168         {
00169                 res = state->AddTransition(onEvent, className);
00170                 if (!res)
00171                 {
00172                         iRethrow();
00173                 }
00174         } else {
00175                 iRethrow();
00176         }
00177         return res;
00178 }
00179 
00180 CFSMTransition* CFiniteStateMachine::AddSimpleTransition(const char *stateName, const char *toStateName, const char* onEvent)
00181 {
00182         CFSMTransition* res = NULL;
00183         CFSMState* state = GetState(stateName);
00184         if (state)
00185         {
00186                 res = state->AddSimpleTransition(toStateName, onEvent);
00187                 if (!res)
00188                 {
00189                         iRethrow();
00190                 }
00191         } else {
00192                 iRethrow();
00193         }
00194         return res;
00195 }
00196 
00197 
00198 
00199 
00200 
00201 
00202 
00203 
00204 
00205 
00206 
00207 
00208 
00209 
00210 
00211 
00212 
00213 
00214 
00215 
00216 
00217 
00218 
00219 
00220 
00221 
00222 
00223 
00224 
00225 
00226 
00227 
00228 
00229 
00230 
00231 
00232 
00233 
00234 
00235 
00236 
00237 
00238 
00239 
00240 
00241 
00242 
00243 
00244 bool CFiniteStateMachine::DeleteTransition(const char* fromState, int index)
00245 {
00246         bool res = false;
00247         CFSMState* state = NULL;
00248         CFSMTransition* trans = NULL;
00249         if (fromState)
00250         {
00251                 state = GetState(fromState);
00252                 if (state)
00253                 {
00254                         trans = state->GetTransition(index);
00255                         if (!trans)     iRethrow();
00256                 } else 
00257                 {
00258                         iRethrow();
00259                 }
00260         } else
00261         {
00262                 iThrow(CRITICAL(FSM_STATE_NOT_FOUND), "");
00263         }
00264 
00265         if (trans)
00266         {
00267                 res = state->DeleteTransition(trans);
00268                 if (!res)
00269                 {
00270                         iRethrow();
00271                 }
00272         } else {
00273                 iRethrow();
00274         }
00275         return res;
00276 }
00277 
00279 
00281 
00282 {
00283         CFSMState *state = GetState(stateName);
00284         if (!state)
00285         {
00286                 iRethrow();
00287                 return NULL;
00288         }
00289 
00290         CFSMTransition *transition = state->GetTransition(index);
00291         if (!transition)
00292         {
00293                 iRethrow();
00294                 return NULL;
00295         }
00296 
00297         CFSMCondition *condition = transition->AddCondition(className);
00298         if (!condition)
00299         {
00300                 iRethrow();
00301         }
00302 
00303         return condition;
00304 }
00305 
00307 
00309 
00310 {
00311         CFSMAction* res = NULL;
00312         CFSMState* state = GetState(stateName);
00313         if (state)
00314         {
00315                 res = state->AddEnterAction(className);
00316                 if (!res)
00317                 {
00318                         iRethrow();
00319                 }
00320         } else {
00321                 iRethrow();
00322         }
00323         return res;
00324 }
00325 
00326 CFSMAction* CFiniteStateMachine::AddLeaveAction(const char *stateName, const char *className)
00327 {
00328         CFSMAction* res = NULL;
00329         CFSMState* state = GetState(stateName);
00330         if (state)
00331         {
00332                 res = state->AddLeaveAction(className);
00333                 if (!res)
00334                 {
00335                         iRethrow();
00336                 }
00337         } else {
00338                 iRethrow();
00339         }
00340         return res;
00341 }
00342 
00343 CFSMAction* CFiniteStateMachine::AddAction(const char *stateName, int index, const char *className)
00344 {
00345         CFSMState *state = GetState(stateName);
00346         if (!state)
00347         {
00348                 iRethrow();
00349                 return NULL;
00350         }
00351 
00352         CFSMTransition *transition = state->GetTransition(index);
00353         if (!transition)
00354         {
00355                 iRethrow();
00356                 return NULL;
00357         }
00358 
00359         CFSMAction *action = transition->AddAction(className);
00360         if (!action)
00361         {
00362                 iRethrow();
00363         }
00364 
00365         return action;
00366 }
00367 
00369 
00371 
00372 {
00373         VM_VT v(varName, initValue);
00374         const pair<Var_Map::iterator,bool>result = m_Variables.insert(v);
00375         if(result.second == false)
00376         {
00377                 iThrow(WARNING(FSM_VARAIBLE_DEFINED_TWICE), varName);
00378         }
00379         return result.second;
00380 }
00381 
00382 bool CFiniteStateMachine::DeleteVariable(const char* varName)
00383 {
00384         bool res = false;
00385 
00386         Var_Map::iterator i = m_Variables.find(varName);
00387         if(!(i==m_Variables.end()))
00388         {
00389                 m_Variables.erase(i);
00390                 res = true;
00391         } else
00392         {
00393                 iThrow(CRITICAL(FSM_VARIABLE_NOT_FOUND), varName);
00394         }
00395         return res;
00396 }
00397 
00398 bool CFiniteStateMachine::SetVariable(const char *varName, const int value)
00399 {
00400         bool res = false;
00401         Var_Map::iterator i = m_Variables.find(varName);
00402         if(!(i==m_Variables.end()))
00403         {
00404                 (*i).second = value;
00405                 res = true;
00406         } else {
00407                 iThrow(CRITICAL(FSM_VARIABLE_NOT_FOUND), varName);
00408         }
00409         return res;
00410 }
00411 
00412 bool CFiniteStateMachine::GetVariable(const char *varName, int &value) const
00413 {
00414         bool res = false;
00415         Var_Map::const_iterator i = m_Variables.find(varName);
00416         if(!(i==m_Variables.end()))
00417         {
00418                 value = (*i).second;
00419                 res = true;
00420         } else {
00421                 iThrow(CRITICAL(FSM_VARIABLE_NOT_FOUND), varName);
00422         }
00423         return res;
00424 }
00425 
00426 Var_Map::const_iterator CFiniteStateMachine::GetVarsBegin() const
00427 {
00428         return m_Variables.begin();
00429 }
00430 
00431 Var_Map::const_iterator CFiniteStateMachine::GetVarsEnd() const
00432 {
00433         return m_Variables.end();
00434 }
00435 
00437 
00439 
00440 {
00441         bool res = false;
00442         if(m_Running)
00443         {
00444                 iThrow(WARNING(FSM_INITIAL_AFTER_START));
00445         } else
00446         {
00447                 m_InitialState = stateName;
00448                 res = true;
00449         }
00450         return res;
00451 }
00452 
00453 const char* CFiniteStateMachine::GetInitialState() const
00454 {
00455         return m_InitialState.c_str();
00456 }
00457 
00458 bool CFiniteStateMachine::Start(const char *stateName)
00459 {
00460         if(!m_Running)
00461         {
00462                 if(stateName!=NULL)
00463                 {
00464                         m_InitialState = stateName;
00465                 }
00466                 m_CurrentState = GetState(m_InitialState.c_str());
00467                 if (!m_CurrentState)
00468                 {
00469                         iRethrow();
00470                 } else
00471                 {
00472                         m_CurrentState->Activate();
00473                         m_Running=true;
00474                 }
00475         } else
00476         {
00477                 iThrow(CRITICAL(FSM_ALREADY_STARTED));
00478         }
00479         return m_Running;
00480 }
00481 
00482 void CFiniteStateMachine::Stop()
00483 {
00484         if (m_Running)
00485         {
00486                 m_CurrentState->Deactivate();
00487                 m_CurrentState=NULL;
00488                 m_Running = false;
00489         }
00490 }
00491 
00492 bool CFiniteStateMachine::ProcessEvent(const char *Event, void *a, void *b, bool *consumed)
00493 {
00494         bool res = false;
00495         if(m_Running)
00496         {
00497                 CFSMTransition* trans = NULL;
00498                 if (m_CurrentState->GetTransition(&trans, Event, a, b))
00499                 {
00500                         if (trans)
00501                         {
00502                                 if(consumed)
00503                                 {
00504                                         *consumed = true;
00505                                 }
00506                                 if(! (res = trans->Execute(Event, a, b)))
00507                                 {
00508                                         iRethrow();
00509                                 }
00510                         } else
00511                         {
00512                                 if (consumed)
00513                                 {
00514                                         *consumed = false;
00515                                 }
00516                                 res = true;
00517                         }
00518                 } else
00519                 {
00520                         iRethrow();
00521                 }
00522         } else
00523         {
00524                 iThrow(CRITICAL(FSM_NOT_STARTED));
00525         }
00526         return res;
00527 }
00528 
00529 CFSMState *CFiniteStateMachine::GetCurrentState() const
00530 {
00531         return m_CurrentState;
00532 }
00533 
00534 bool CFiniteStateMachine::Clear()
00535 {
00536         bool res = false;
00537         if (!m_Running)
00538         {
00539                 
00540                 State_Map::iterator s = m_States.begin();
00541                 if(!(s==m_States.end()))
00542                 {
00543                         delete (*s).second;
00544                         (*s).second = NULL;
00545                         m_States.erase(s);
00546                         s = m_States.begin(); 
00547 
00548                 }
00549 
00550                 
00551                 Var_Map::iterator v = m_Variables.begin();
00552                 if(!(v==m_Variables.end()))
00553                 {
00554                         (*v).second = 0;
00555                         m_Variables.erase(v);
00556                         v = m_Variables.begin();
00557                 }
00558 
00559                 m_InitialState = "";
00560                 res = true;
00561         } else
00562         {
00563                 iThrow(CRITICAL(FSM_CLEAR_STARTED));
00564         }
00565         return res;
00566 }
00567 
00569 
00571 
00572 void CFiniteStateMachine::RegisterBaseTypes()
00573 {
00574         Register("State", CFSMState::Create);
00575         Register("SimpleTransition", CFSMSimpleTransition::Create);
00576         Register("PushTransition", CFSMPushTransition::Create);
00577         Register("PopTransition", CFSMPopTransition::Create);
00578         Register("TestVariable", CFSMConditionTestVariable::Create);
00579         Register("SetVariable", CFSMActionSetVariable::Create);
00580         Register("IncrVariable", CFSMActionIncrVariable::Create);
00581 }
00582 
00583 bool CFiniteStateMachine::SwitchToState(CFSMState* newState)
00584 {       
00585         bool res = true;
00586         if (newState)
00587         {
00588                 if (newState != m_CurrentState)
00589                 {
00590                         if (m_CurrentState) res = m_CurrentState->Deactivate();
00591                         if (res)
00592                         {
00593                                 m_CurrentState=newState;
00594                                 res = m_CurrentState->Activate();
00595                                 if (res)
00596                                 {
00597                                         res = ProcessEvent("UPDATE");
00598                                         if (!res)
00599                                         {
00600                                                 iRethrow();
00601                                         }
00602                                 } else
00603                                 {
00604                                         iRethrow();
00605                                 }
00606                         } else
00607                         {
00608                                 iRethrow();
00609                         }
00610                 }
00611         } else 
00612         {
00613                 iThrow(CRITICAL(FSM_STATE_NOT_FOUND), "NULL");
00614         }
00615         return res;
00616 }
00617 
00618 bool CFiniteStateMachine::PushState(CFSMState* newState)
00619 {       
00620         bool res = SwitchToState(newState);
00621         if (res)
00622         {
00623                 
00624         } else
00625         {
00626                 iRethrow();
00627         }
00628         return res;
00629 }
00630 
00631 bool CFiniteStateMachine::PopState()
00632 {       
00633         bool res = false;
00634         CFSMState *newState = NULL;
00635 
00636         
00637 
00638         SwitchToState(newState);
00639         if( !res )
00640         {
00641                 iRethrow();
00642         }
00643         return res;
00644 }
00645 
00647 
00649 
00650 {
00651         
00652         if (FSMObjectCreationMethods.find(className)!=FSMObjectCreationMethods.end())
00653         {
00654                 iThrow(WARNING(FSM_CLASS_REGISTERED_TWICE), className);
00655                 return;
00656         }
00657         FSMObjectCreationMethods.insert(pair<const string,FSMObjectCreateMethod>(className,create));
00658 }
00659 
00661 
00663 
00664 {
00665         if (className==NULL || className[0]=='\0')
00666         {
00667                 iThrow(WARNING(FSM_CANNOT_CREATE_CLASS), "");
00668                 return NULL;
00669         }
00670 
00671         FSMObjectCreate_Map::iterator item = FSMObjectCreationMethods.find(className);
00672         if (item==FSMObjectCreationMethods.end())
00673         {
00674 #ifndef _WIN32_WCE
00675                 if(!LoadClass(className))
00676                 {
00677                         iRethrow();
00678                         return NULL;
00679                 }
00680 
00681                 item = FSMObjectCreationMethods.find(className);
00682                 if (item==FSMObjectCreationMethods.end())
00683                 {
00684                         iThrow(WARNING(FSM_CANNOT_CREATE_CLASS), className);
00685                         return NULL;
00686                 }
00687 #else
00688                 iThrow(WARNING(FSM_CANNOT_CREATE_CLASS), className);
00689                 return NULL;
00690 #endif
00691         }
00692 
00693         FSMObjectCreateMethod create = (*item).second;
00694         CFSMObject *obj = create();
00695         obj->SetFSM(this);
00696         obj->SetClassName(className);
00697         return (obj);
00698 }
00699 
00700 #ifndef _WIN32_WCE
00701 
00702 
00704 
00705 {
00706         string libName("");
00707 
00708 #       ifdef WIN32
00709         libName += className;
00710         libName += ".dll";
00711 #       else 
00712         libName += "lib";
00713         libName += className;
00714         libName += ".so";
00715 #       endif
00716 
00717 #       ifdef HAVE_LIBIWRAPPER
00718         iLibrary* lib = iLibrary::Load(libName.c_str());
00719 #       else
00720 #               ifdef WIN32
00721                 HINSTANCE lib = LoadLibrary(libName.c_str());
00722 #               else
00723                 void *lib = dlopen(libName.c_str(), RTLD_NOW);
00724 #               endif
00725 #       endif
00726 
00727         if (lib==NULL)
00728         {
00729                 return false;
00730         }
00731 
00732         InitClassF InitClass;
00733 #       ifdef HAVE_LIBIWRAPPER
00734                 InitClass = (InitClassF)lib->GetProc("InitClass");
00735 #       else
00736 #               ifdef WIN32
00737                 InitClass = (InitClassF)GetProcAddress(lib, "InitClass");
00738 #               else
00739                 InitClass = (InitClassF)dlsym(lib, "InitClass");
00740 #               endif
00741 #       endif
00742 
00743         if (!InitClass)
00744         {
00745                 iHandleLastError();
00746                 return false;
00747         }
00748 
00749         (*InitClass)(this);
00750 
00751         
00752 
00753         return true;
00754 }
00755 #endif
00756 
00757 
00759 }; 
00760