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