27 #include <IceUtil/Time.h>
43 using namespace StateUtilFunctions;
46 #define MAX_USER_CODE_DURATION 100 //milliseconds
60 cimpl->transitionFunctions =
source.cimpl->transitionFunctions;
61 cimpl->localProfilers =
source.cimpl->localProfilers;
62 cimpl->profilersDisabled =
source.cimpl->profilersDisabled;
68 if (
cimpl->__runningTask)
70 cimpl->__runningTask->stop();
74 std::unique_lock lock(
cimpl->__finishedMutex);
75 cimpl->__finished =
true;
78 cimpl->__finishedCondition.notify_all();
84 std::unique_lock lock(
cimpl->__finishedMutex);
85 return cimpl->__finished;
93 std::unique_lock lock(
cimpl->__finishedMutex);
97 throw LocalException(
"You can only wait for toplevel states to finish!");
100 while (!
cimpl->__finished)
104 cimpl->__finishedCondition.wait(lock);
108 if (
cimpl->__finishedCondition.wait_for(lock, std::chrono::milliseconds(timeoutMs)) ==
109 std::cv_status::timeout)
111 throw LocalException(
"Statechart did not finish in time");
133 for (
auto& state : subStateList)
139 if (remote->getState() < eManagedIceObjectStarted)
141 ARMARX_INFO <<
"Waiting for remote state " << remote->getGlobalHierarchyString();
142 objectScheduler->waitForDependencies();
146 ARMARX_VERBOSE <<
"starting state " << stateName <<
" with parameters:\n"
151 if (tempInputParameters.size() > 0)
154 ->mapFromOutput(
"*",
"*")
155 ->_addSourceDictionary(eOutput, tempInputParameters)
156 ->setTargetDictToGreedy(greedyInputDictionary)
157 ->_applyMapping(inputParameters);
169 impl->triggeredEndstateEvent = ev;
170 ARMARX_DEBUG <<
"Substate finished with event " << ev->eventName;
179 STATEINFO <<
"Statemachine finished with event '" << ev->eventName <<
"' in state '"
181 <<
"The resulting output dictionary:\n"
207 const TransitionIceBase& t,
216 ARMARX_DEBUG <<
"Set parameters of parent " << stateName <<
" during transition: "
218 StringVariantContainerBaseMap srcSetOutputParams;
226 [&](
const ParameterMappingIceBasePtr& icepm,
StateParameterMap& targetMap,
bool greedy)
229 PMPtr pm = PMPtr::dynamicCast(icepm);
233 pm->setTargetDictToGreedy(greedy);
236 pm->_addSourceDictionary(eParent, parentSetInputParams)
237 ->_addSourceDictionary(eOutput, srcSetOutputParams)
238 ->_addSourceDictionary(eEvent, event->properties)
239 ->_applyMapping(targetMap);
242 applyMapping(t.mappingToParentStatesLocal, localParameters,
false);
243 applyMapping(t.mappingToParentStatesOutput, outputParameters,
false);
244 applyMapping(t.mappingToNextStatesInput,
245 StateBasePtr::dynamicCast(t.destinationState)->inputParameters,
246 StateBasePtr::dynamicCast(t.destinationState)->greedyInputDictionary);
248 std::string paramCheckOutput;
251 auto it =
cimpl->transitionFunctions.find(transitionId);
252 if (it !=
cimpl->transitionFunctions.end())
257 StateIceBasePtr::dynamicCast(t.destinationState),
258 StateIceBasePtr::dynamicCast(t.sourceState));
266 error.
infos.push_back(StateBasePtr::dynamicCast(t.destinationState)->stateName);
267 error.
infos.push_back(paramCheckOutput);
285 ARMARX_WARNING <<
"Could not execute transition!\nReturned reason: " +
289 <<
"\t- The input parameters of the destination state were not fully "
290 "set.\n\tDestination state: '"
291 << transitionError.
infos.at(0) <<
"'\n"
292 << transitionError.
infos.at(1);
298 ARMARX_WARNING <<
"Could not execute transition!\nReturned reason: " +
302 <<
"\t- The state '" << stateName <<
"' does not expect the event '"
303 <<
event->eventName <<
"' while in substate '"
304 << StateBasePtr::dynamicCast(activeSubstate)->stateName <<
"'.\n"
311 ARMARX_WARNING <<
"Could not execute transition!\nReturned reason: " +
323 STATEINFO <<
"TRANSITION due to Event '" <<
event->eventName <<
"' (EventReceiver: '"
324 <<
event->eventReceiverName <<
"')..." <<
flush;
325 boost::recursive_mutex::scoped_lock lock(
impl->__processEventMutex);
334 !StateIceBasePtr::dynamicCast(activeSubstate)->unbreakable &&
337 ARMARX_WARNING <<
"a parent state has events to process. this event will be skipped"
349 event, StateIceBasePtr::dynamicCast(activeSubstate), t, transitionError))
354 if (src && src->__hasSubstates() && src->__hasActiveSubstate())
356 ARMARX_INFO <<
"<<<< Trying to break substates of " << src->stateName <<
flush;
359 if (src->__breakActiveSubstate(event))
366 cimpl->__unbreakableBuffer.push(event);
369 ARMARX_INFO <<
"got event while in unbreakable substate: parent stateName:"
370 << stateName <<
flush;
383 t.sourceState = activeSubstate;
387 activeSubstate =
nullptr;
388 bool destinationStateInitialized =
389 StateBasePtr::dynamicCast(t.destinationState)->waitForInitialization();
391 << StateBasePtr::dynamicCast(t.destinationState)->stateName;
396 activeSubstate = t.destinationState;
397 if (t.sourceState && activeSubstate && !
cimpl->profilersDisabled)
401 localProfiler->logStatechartTransition(
403 StateIceBasePtr::dynamicCast(t.sourceState),
404 StateIceBasePtr::dynamicCast(t.destinationState),
406 localProfiler->logStatechartTransitionWithParameters(t);
411 StateControllerPtr::dynamicCast(t.destinationState)->_baseOnEnter();
414 if (src && src->unbreakable && src->eventsDelayed)
420 if (StateIceBasePtr::dynamicCast(t.destinationState)->unbreakable)
422 StateIceBasePtr::dynamicCast(t.destinationState)->eventsDelayed =
true;
447 <<
"The state '" << stateName
448 <<
"' does not have an activeSubstate and therefore cannot process any events."
455 const StateIceBasePtr& sourceState,
456 TransitionIceBase& resultTransition,
466 int selectedTransitionIndex = -1;
468 for (
unsigned int i = 0; i < transitions.size(); i++)
471 const TransitionIceBase& transition = transitions.at(i);
473 if ((transition.sourceState == sourceState || transition.fromAll)
474 && transition.evt->eventName == event->eventName
475 && (sourceState->stateName == event->eventReceiverName ||
479 selectedTransitionIndex = i;
485 if (selectedTransitionIndex == -1)
491 const TransitionIceBase& transition = transitions.at(selectedTransitionIndex);
493 resultTransition = transition;
501 const StateIceBasePtr& sourceState,
502 const StateIceBasePtr& destinationState)
const
507 if ((transition.sourceState != sourceState && !transition.fromAll)
508 || transition.evt->eventName != event->eventName
509 || (sourceState && sourceState->stateName != event->eventReceiverName &&
518 if (transition.sourceState && transition.fromAll)
526 PMPtr transitionMapping = PMPtr::dynamicCast(transition.mappingToNextStatesInput);
529 if (transitionMapping && sourceState)
532 const StringVariantContainerBaseMap parentSetInputParams =
534 const StringVariantContainerBaseMap srcSetOutputParams =
536 transitionMapping->setTargetDictToGreedy(
537 StateBasePtr::dynamicCast(transition.destinationState)->greedyInputDictionary);
540 transitionMapping->_addSourceDictionary(eParent, parentSetInputParams)
541 ->_addSourceDictionary(eOutput, srcSetOutputParams)
542 ->_addSourceDictionary(eEvent, event->properties)
543 ->_applyMapping(inputCopy);
544 std::string paramCheckOutput;
549 error.
infos.push_back(destinationState->stateName +
": " + paramCheckOutput);
561 return cimpl->__unbreakableBuffer.size();
568 cimpl->__eventBufferedDueToUnbreakableState = eventBuffered;
570 for (
unsigned int i = 0; i < subStateList.size(); ++i)
575 if (state->__getUnbreakableBufferSize() >
578 eventBuffered =
true;
581 StateControllerPtr::dynamicCast(subStateList.at(i))
582 ->__notifyEventBufferedDueToUnbreakableState(eventBuffered);
592 if (!ptr &&
impl->__parentState)
596 armarx::StateIceBase* base = newParentAsController.get();
597 *base = *
impl->__parentState;
598 ARMARX_WARNING <<
"Had to call factory manually for StateIceBase in "
599 <<
impl->__parentState->globalStateIdentifier;
600 return newParentAsController;
611 boost::recursive_mutex::scoped_lock lock(
impl->__processEventMutex);
615 result = StateControllerPtr::dynamicCast(activeSubstate)->_baseOnBreak(event);
619 activeSubstate =
nullptr;
633 <<
" in unbreakableBuffer - eventprocessorstate:" << stateName
634 <<
" - activeState: " << StateBasePtr::dynamicCast(activeSubstate)->stateName
636 impl->__eventUnbreakableBufferMutex.lock();
638 cimpl->__unbreakableBuffer.pop();
639 impl->__eventUnbreakableBufferMutex.unlock();
651 StateControllerPtr::dynamicCast(
__getParentState())->__processBufferedEvents();
659 for (
unsigned int i = 0; i < subStateList.size(); ++i)
661 RemoteStatePtr remoteStatePtr = RemoteStatePtr::dynamicCast(subStateList.at(i));
666 ARMARX_INFO <<
"Waiting for RemoteState " << remoteStatePtr->getName();
668 while (!(remoteStatePtr->getState() >= eManagedIceObjectStarted))
673 ARMARX_INFO <<
"RemoteState " << remoteStatePtr->getName() <<
"started.";
682 for (
unsigned int i = 0; i < transitions.size(); ++i)
685 if (transitions[i].evt->eventName == transition.evt->eventName &&
686 (transition.fromAll || transitions[i].sourceState == transition.sourceState) &&
687 transitions[i].destinationState == transition.destinationState)
708 if (
cimpl->__runningTask)
713 if (
cimpl->__runningTask->isRunning())
715 ARMARX_VERBOSE <<
"Waiting for running task of " << stateName <<
" to finish";
718 cimpl->__runningTask->stop();
720 catch (IceUtil::ThreadSyscallException& e)
725 eventsDelayed =
false;
728 ARMARX_DEBUG <<
"Resetting local and output parameters of state " << stateName;
733 std::string paramCheckOutput;
737 throw LocalException(
"Not all required inputparameters of the state '" + stateName +
738 "' are set:\n" + paramCheckOutput);
742 impl->cancelEnteringSubstates =
false;
744 impl->triggeredEndstateEvent =
nullptr;
746 impl->visitCounter++;
749 <<
"' (id: " <<
impl->localUniqueId <<
")" <<
flush;
756 if (!
cimpl->profilersDisabled)
760 localProfiler->logEvent(Profiler::Profiler::EventType::eFunctionStart,
774 ARMARX_ERROR <<
"onEnter() of State " << globalStateIdentifier <<
" of class "
775 << stateClassName <<
" failed. Ignoring substates and sending Failure.\n"
785 if (!
cimpl->profilersDisabled)
794 IceUtil::Time duration = IceUtil::Time::now() - executionStart;
798 ARMARX_WARNING <<
"onEnter() of state '" + stateName +
"' took more than "
800 <<
" ms (In fact: " << duration.toMilliSeconds()
801 <<
" ms). The onEnter() method should not calculate complex operations."
810 if (!
impl->cancelEnteringSubstates)
814 impl->cancelEnteringSubstates =
false;
826 if (initialStateMapping)
828 PMPtr mapping = ParameterMappingPtr::dynamicCast(initialStateMapping);
829 mapping->_addSourceDictionary(eParent, combinedMap)
830 ->setTargetDictToGreedy(
831 StateBasePtr::dynamicCast(initState)->greedyInputDictionary)
832 ->_applyMapping(StateBasePtr::dynamicCast(initState)->inputParameters);
835 activeSubstate = initState;
837 if (!
cimpl->profilersDisabled && activeSubstate)
841 localProfiler->logStatechartTransition(
844 StateIceBasePtr::dynamicCast(activeSubstate),
845 "InitialTransition");
848 t.sourceState =
nullptr;
849 t.destinationState = activeSubstate;
850 EventBasePtr e(
new EventBase());
851 e->eventName =
"InitialTransition";
853 localProfiler->logStatechartTransitionWithParameters(t);
856 StateControllerPtr::dynamicCast(initState)->_baseOnEnter();
862 STATEINFO <<
"Entering substates of " << stateName <<
" has been canceled";
876 if (!
impl->__useRunFunction)
882 if (!
impl->__parentState ||
impl->__parentState->activeSubstate.get() ==
this)
886 cimpl->__runningTask->start();
907 <<
"run() of State " << globalStateIdentifier <<
" of class " << stateClassName
908 <<
" failed for unhandled reason. Ignoring substates and sending Failure\n"
925 impl->cancelEnteringSubstates =
true;
927 if (
cimpl->__runningTask)
929 cimpl->__runningTask->stop(
false);
941 "baseOnExit was called before substates were finished - baseOnBreak must be called "
942 "instead. ActiveSubstate: " +
943 StateBasePtr::dynamicCast(activeSubstate)->stateName);
957 if (!
cimpl->profilersDisabled)
961 localProfiler->logEvent(Profiler::Profiler::EventType::eFunctionReturn,
973 ARMARX_ERROR <<
"onExit() of State " << globalStateIdentifier <<
" of class "
974 << stateClassName <<
" failed\n"
978 IceUtil::Time duration = IceUtil::Time::now() - executionStart;
987 ARMARX_WARNING <<
"onExit() of state '" + stateName +
"' took more than "
989 <<
" ms). The onEnter() method should not calculate complex operations."
993 std::string paramCheckOutput;
997 throw LocalException(
"Not all required Outputparameters of state '" + stateName +
998 "' are set:\n" + paramCheckOutput);
1006 std::unique_lock lock(
cimpl->__finishedMutex);
1007 cimpl->__finished =
true;
1008 cimpl->__finishedCondition.notify_all();
1018 if (
cimpl->__runningTask)
1020 cimpl->__runningTask->stop(
false);
1034 eventsDelayed =
true;
1040 if (StateBasePtr::dynamicCast(activeSubstate)->unbreakable)
1043 StateBasePtr::dynamicCast(activeSubstate)->eventsDelayed =
true;
1056 <<
"' (id: " <<
impl->localUniqueId <<
")" <<
flush;
1058 if (
cimpl->__runningTask)
1060 cimpl->__runningTask->stop(
false);
1070 if (!
cimpl->profilersDisabled)
1073 localProfiler->logEvent(Profiler::Profiler::EventType::eFunctionBreak,
1085 ARMARX_ERROR <<
"onBreak() of State " << globalStateIdentifier <<
" of class "
1086 << stateClassName <<
" failed. Ignoring substates and sending Failure.\n"
1092 IceUtil::Time duration = IceUtil::Time::now() - executionStart;
1096 ARMARX_WARNING <<
"onEnter() of state '" + stateName +
"' took more than "
1098 <<
" ms (In fact: " << duration.toMilliSeconds()
1099 <<
" ms). The onEnter() method should not calculate complex operations."
1112 std::unique_lock lock(
cimpl->__finishedMutex);
1113 cimpl->__finished =
true;
1114 cimpl->__finishedCondition.notify_all();
1124 cimpl->localProfilers.insert(profiler);
1125 if (recursiveLevels < 0)
1129 else if (recursiveLevels == 0)
1133 else if (recursiveLevels > 0)
1138 for (AbstractStateIceBasePtr state : subStateList)
1142 if (stateController)
1144 stateController->addProfilerRecursive(profiler, recursiveLevels);
1153 cimpl->localProfilers.erase(profiler);
1154 if (recursiveLevels < 0)
1158 else if (recursiveLevels == 0)
1162 else if (recursiveLevels > 0)
1167 for (AbstractStateIceBasePtr state : subStateList)
1171 if (stateController)
1173 stateController->addProfilerRecursive(profiler, recursiveLevels);
1182 if (!
cimpl->__runningTask)
1187 return cimpl->__runningTask->isStopped();
1193 if (!
cimpl->__runningTask)
1197 return cimpl->__runningTask->isFinished();
1204 if (
cimpl->__runningTask)
1206 cimpl->__runningTask->join();
1213 cimpl->profilersDisabled = disable;
1220 ARMARX_INFO <<
"Regstering transition code for " << t.evt->eventName;
1230 (t.sourceState ? StateBasePtr::dynamicCast(t.sourceState)->stateName : std::string(
"")));
1235 const std::string sourceStateName)
const
1237 return sourceStateName +
":" + eventName;
1242 const std::string sourceStateName,
1243 TransitionIceBase& transition)
1246 for (
const TransitionIceBase& t : transitions)
1248 if (t.evt->eventName == eventName &&
1249 StateBasePtr::dynamicCast(t.sourceState)->stateName == sourceStateName)
1255 ARMARX_INFO <<
"Could not find transition in " << transitions.size() <<
" transitions";
1273 return !
cimpl->__eventBufferedDueToUnbreakableState;
1280 for (
unsigned int i = 0; i < subStateList.size(); i++)
1282 StateControllerPtr::dynamicCast(subStateList[i])->disableRunFunction();
1286 impl->__useRunFunction =
false;
1288 if (
cimpl->__runningTask &&
cimpl->__runningTask->isRunning())
1290 ARMARX_VERBOSE <<
"State with name '" << stateName <<
"' is waiting for the RunFunction";
1291 cimpl->__runningTask->stop();
1294 cimpl->__runningTask =
nullptr;