|
|
@@ -0,0 +1,444 @@
|
|
|
+<class name="FSASimulator_Simulation">
|
|
|
+ <relationships>
|
|
|
+ <association name="parent" class="FSASimulator_Coordinator" min="1" max="1" />
|
|
|
+ <association name="child_simulator" class="FSASimulator_BigStep" min="0" max="1" />
|
|
|
+ </relationships>
|
|
|
+ <method name="FSASimulator_Simulation">
|
|
|
+ <parameter name="model"/>
|
|
|
+ <parameter name="events"/>
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ self.model = model
|
|
|
+ self.eventList = events
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="initialize">
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ self.clock = 0
|
|
|
+ self.elapsed = 0
|
|
|
+ self.delta = 1.0 * 1000.0 # in miliseconds for real-time simulation
|
|
|
+ self.timeNext = self.delta
|
|
|
+ self.state = self.model.initialState
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="endCondition">
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ return self.state and self.state.final
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="finalize">
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ print 'Simulation finalized.'
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="initializeDebugger">
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ self.breakpoints = []
|
|
|
+ self.triggered_bp = None
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="waitTime">
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ # First, we convert from wall-clock time to simulated time.
|
|
|
+ # This means the elapsed time in wall-clock time needs to be scaled according to the realtime scale (for example, if the realtime scale is 2, an elapsed time of 1 second in wall-clock time is equal to an elapsed time of 2 seconds in simulated time).
|
|
|
+ simulated_diff = (accurate_time.time() - self.realtime_start_time) * self.realtime_scale
|
|
|
+ # timeNext and simulated_diff are both in simulated time: so now scale back to wall-clock time by dividing.
|
|
|
+ # This function returns an amount of miliseconds.
|
|
|
+ return ((self.timeNext - simulated_diff) / self.realtime_scale)
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="syncSimulatedTime">
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ diff = accurate_time.time() - self.realtime_start_time
|
|
|
+ self.clock = diff * self.realtime_scale
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="addBreakpoint">
|
|
|
+ <parameter name="name" />
|
|
|
+ <parameter name="function" />
|
|
|
+ <parameter name="enabled" default="true" />
|
|
|
+ <parameter name="disable_on_trigger" default="true" />
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ if len([bp for bp in self.breakpoints if bp.name == name]) > 0:
|
|
|
+ return -1
|
|
|
+ self.breakpoints.append(Breakpoint(name, function, enabled, disable_on_trigger))
|
|
|
+ return 0
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="delBreakpoint">
|
|
|
+ <parameter name="name" />
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ if len([bp for bp in self.breakpoints if bp.name == name]) == 0:
|
|
|
+ return -1
|
|
|
+ self.breakpoints = [bp for bp in self.breakpoints if bp.name != name]
|
|
|
+ return 0
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="toggleBreakpoint">
|
|
|
+ <parameter name="name" />
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ if len([bp for bp in self.breakpoints if bp.name == name]) == 0:
|
|
|
+ return -1
|
|
|
+ for bp in self.breakpoints:
|
|
|
+ if bp.name == name:
|
|
|
+ bp.enabled = enabled
|
|
|
+ break
|
|
|
+ return 0
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="breakpointTriggers">
|
|
|
+ <parameter name="is_realtime_simulation" />
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ self.triggered_bp = None
|
|
|
+ for bp in self.breakpoints:
|
|
|
+ if not bp.enabled:
|
|
|
+ continue
|
|
|
+ # include the function in the scope...
|
|
|
+ exec(bp.function)
|
|
|
+ # ... and execute it, note that the breakpoint thus has to start with "def breakpoint("
|
|
|
+ # note that we pass self.timeNext instead of self.simulated_time in the case of as-fast-as-possible simulation (or stepping)
|
|
|
+ # this is to make sure that the simulation is stopped BEFORE the specified time is reached, and not AFTER (because we don't necessarily implement 'step back')
|
|
|
+ # in case of realtime simulation, we do pass the current simulated time, since we can stop at (more or less) exactly the right time
|
|
|
+ if breakpoint({'clock': (self.clock if is_realtime_simulation else self.timeNext) / 1000.0, 'state': self.state}):
|
|
|
+ # triggered!
|
|
|
+ self.triggered_bp = bp.name
|
|
|
+ if bp.disable_on_trigger:
|
|
|
+ bp.enabled = False
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ # not triggered, so continue
|
|
|
+ continue
|
|
|
+ return False
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <method name="godEvent">
|
|
|
+ <parameter name="new_state" />
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ filtered_states = [s for s in self.model.states if s.name == new_state]
|
|
|
+ if not len(filtered_states) == 1:
|
|
|
+ return -1
|
|
|
+ self.state = filtered_states[0]
|
|
|
+ return 0
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+ <scxml initial="Main" final="Stopped">
|
|
|
+ <parallel id="Main">
|
|
|
+ <state id="ModeSelector" initial="Paused">
|
|
|
+ <state id="Paused">
|
|
|
+ <transition target="../Running/SmallStep" event="SmallStep.Execute">
|
|
|
+ <raise event="SmallStep.Execute" scope="narrow" target="'child_simulator'" />
|
|
|
+ </transition>
|
|
|
+ <transition target="../Running/BigStep" event="BigStep.Execute">
|
|
|
+ <raise event="BigStep.Execute" scope="narrow" target="'child_simulator'" />
|
|
|
+ </transition>
|
|
|
+ <transition target="../Running/Continuous" event="Simulation.Execute" />
|
|
|
+ <transition target="../Running/Realtime" event="Simulation.ExecuteRealtime">
|
|
|
+ <parameter name="realtime_scale" default="1.0" />
|
|
|
+ <script>
|
|
|
+ self.realtime_scale = float(realtime_scale)
|
|
|
+ # If the simulation was paused, we need to reset the start time of the simulation.
|
|
|
+ # The start time of the simulation is equal to the point in wall-clock time where simulated time is 0.
|
|
|
+ # If the simulation was paused, we have to recompute this point in time: it is the difference of the wall-clock time and the simulated time.
|
|
|
+ # If the scale was changed after the pause, this point of course moves backwards (for scales smaller than 1) or forwards (for scales larger than 1)
|
|
|
+ self.realtime_start_time = accurate_time.time() - (self.clock / self.realtime_scale)
|
|
|
+ </script>
|
|
|
+ </transition>
|
|
|
+ <transition target="." event="BigStep.Finished">
|
|
|
+ <parameter name="clock" />
|
|
|
+ <parameter name="timeNext" />
|
|
|
+ <parameter name="elapsed" />
|
|
|
+ <parameter name="eventList" />
|
|
|
+ <parameter name="state" />
|
|
|
+ <raise event="BigStep.Finished" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="clock" />
|
|
|
+ <parameter expr="timeNext" />
|
|
|
+ <parameter expr="elapsed" />
|
|
|
+ <parameter expr="eventList" />
|
|
|
+ <parameter expr="state" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="Running" initial="Continuous">
|
|
|
+ <state id="Continuous">
|
|
|
+ <transition target="../../Paused" event="Simulation.Pause" />
|
|
|
+ </state>
|
|
|
+ <state id="Realtime">
|
|
|
+ <transition target="../../Paused" event="Simulation.Pause" />
|
|
|
+ <transition target="." event="BigStep.Finished">
|
|
|
+ <parameter name="clock" />
|
|
|
+ <parameter name="timeNext" />
|
|
|
+ <parameter name="elapsed" />
|
|
|
+ <parameter name="eventList" />
|
|
|
+ <parameter name="state" />
|
|
|
+ <raise event="BigStep.Finished" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="clock" />
|
|
|
+ <parameter expr="timeNext" />
|
|
|
+ <parameter expr="elapsed" />
|
|
|
+ <parameter expr="eventList" />
|
|
|
+ <parameter expr="state" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="BigStep">
|
|
|
+ <transition target="../../Paused" event="BigStep.Finished">
|
|
|
+ <parameter name="clock" />
|
|
|
+ <parameter name="timeNext" />
|
|
|
+ <parameter name="elapsed" />
|
|
|
+ <parameter name="eventList" />
|
|
|
+ <parameter name="state" />
|
|
|
+ <raise event="BigStep.Finished" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="clock" />
|
|
|
+ <parameter expr="timeNext" />
|
|
|
+ <parameter expr="elapsed" />
|
|
|
+ <parameter expr="eventList" />
|
|
|
+ <parameter expr="state" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="SmallStep">
|
|
|
+ <transition target="../../Paused" event="SmallStep.Finished">
|
|
|
+ <parameter name="selectedTransition" />
|
|
|
+ <parameter name="currentEvent" />
|
|
|
+ <parameter name="eventList" />
|
|
|
+ <parameter name="elapsed" />
|
|
|
+ <parameter name="state" />
|
|
|
+ <raise event="SmallStep.Finished" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="selectedTransition" />
|
|
|
+ <parameter expr="currentEvent" />
|
|
|
+ <parameter expr="eventList" />
|
|
|
+ <parameter expr="elapsed" />
|
|
|
+ <parameter expr="state" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <transition target="../Paused" event="Simulation.Finished" />
|
|
|
+ <transition target="../Paused" cond="self.breakpointTriggers(INSTATE('Realtime'))">
|
|
|
+ <raise event="Breakpoint.Triggered" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="self.triggered_bp" />
|
|
|
+ <parameter expr="self.clock" />
|
|
|
+ <parameter expr="self.state" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ </state>
|
|
|
+ <state id="ChildState" initial="Uninitialized">
|
|
|
+ <state id="Uninitialized">
|
|
|
+ <transition event="BigStep.Initialized" target="../Initialized" />
|
|
|
+ </state>
|
|
|
+ <state id="Initialized">
|
|
|
+ <transition target="../Uninitialized" event="BigStep.Finished">
|
|
|
+ <raise event="delete_instance" scope="cd">
|
|
|
+ <parameter expr="'child_simulator'" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ </state>
|
|
|
+ <state id="Initializer" initial="Waiting">
|
|
|
+ <state id="Waiting">
|
|
|
+ <transition target="../CreatingChildSimulator" cond="INSTATE('../../ModeSelector/Running') and INSTATE('../../ChildState/Uninitialized') and not self.endCondition()">
|
|
|
+ <raise event="create_instance" scope="cd">
|
|
|
+ <parameter expr="'child_simulator'" />
|
|
|
+ <parameter expr="'FSASimulator_BigStep'" />
|
|
|
+ <parameter expr="self.model" />
|
|
|
+ <parameter expr="self.state" />
|
|
|
+ <parameter expr="self.clock" />
|
|
|
+ <parameter expr="self.elapsed" />
|
|
|
+ <parameter expr="self.eventList" />
|
|
|
+ <parameter expr="self.timeNext" />
|
|
|
+ <parameter expr="self.delta" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="CreatingChildSimulator">
|
|
|
+ <transition target="../StartingChildSimulator" event="instance_created">
|
|
|
+ <raise event="start_instance" scope="cd">
|
|
|
+ <parameter expr="'child_simulator'" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="StartingChildSimulator">
|
|
|
+ <transition target="../Running" event="BigStep.Initialized" />
|
|
|
+ </state>
|
|
|
+ <state id="Running">
|
|
|
+ <transition target="../SettleBeforeWaiting" event="BigStep.Finished" />
|
|
|
+ </state>
|
|
|
+ <state id="SettleBeforeWaiting">
|
|
|
+ <transition target="../Waiting" after="self.sccd_yield()" />
|
|
|
+ </state>
|
|
|
+ </state>
|
|
|
+ <state id="SimulationFlow" initial="Started">
|
|
|
+ <state id="Started">
|
|
|
+ <transition target="../Initialized">
|
|
|
+ <script>
|
|
|
+ <![CDATA[
|
|
|
+ self.initialize()
|
|
|
+ ]]>
|
|
|
+ </script>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="Initialized">
|
|
|
+ <transition target="../InitializeDebugger" />
|
|
|
+ </state>
|
|
|
+ <state id="InitializeDebugger">
|
|
|
+ <transition target="../Waiting">
|
|
|
+ <script>
|
|
|
+ <![CDATA[
|
|
|
+ self.initializeDebugger()
|
|
|
+ ]]>
|
|
|
+ </script>
|
|
|
+ <raise event="Simulation.Initialized" scope="narrow" target="'parent'" />
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="Waiting">
|
|
|
+ <transition target="../CheckTermination" cond="INSTATE('../../ModeSelector/Running')" />
|
|
|
+ </state>
|
|
|
+ <state id="SettleBeforeCheckTermination">
|
|
|
+ <transition target="../CheckTermination" after="self.sccd_yield()" />
|
|
|
+ <transition target="../CheckTermination" cond="INSTATE('../../ModeSelector/Paused')">
|
|
|
+ <raise event="Simulation.Paused" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="self.clock" />
|
|
|
+ <parameter expr="self.state" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="CheckTermination">
|
|
|
+ <transition target="../Executing" cond="(INSTATE('../../ModeSelector/Running/Continuous') or INSTATE('../../ModeSelector/Running/BigStep')) and INSTATE('../../ChildState/Initialized') and not self.endCondition()">
|
|
|
+ <raise event="BigStep.Execute" scope="narrow" target="'child_simulator'" />
|
|
|
+ </transition>
|
|
|
+ <transition target="../Executing" cond="INSTATE('../../ModeSelector/Running/SmallStep') and INSTATE('../../ChildState/Initialized') and not self.endCondition()">
|
|
|
+ <raise event="SmallStep.Execute" scope="narrow" target="'child_simulator'" />
|
|
|
+ </transition>
|
|
|
+ <transition target="../WaitingRealtime" cond="INSTATE('../../ModeSelector/Running/Realtime') and INSTATE('../../ChildState/Initialized') and not self.endCondition()" />
|
|
|
+ <transition target="../Stopped" cond="self.endCondition()">
|
|
|
+ <script>
|
|
|
+ <![CDATA[
|
|
|
+ # print '>>> simulation executed <<<'
|
|
|
+ self.finalize()
|
|
|
+ ]]>
|
|
|
+ </script>
|
|
|
+ <raise event="Simulation.Finished" />
|
|
|
+ <raise event="Simulation.Finished" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="self.clock" />
|
|
|
+ <parameter expr="self.state" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="WaitingRealtime">
|
|
|
+ <!-- We schedule to go back to the check_termination state after the smallest possible delay (to accomodate for pauses). -->
|
|
|
+ <transition target="../CheckTermination" after="self.sccd_yield()" cond="INSTATE('../../ModeSelector/Running')">
|
|
|
+ <!-- We set the simulation time to the correct value. -->
|
|
|
+ <script>
|
|
|
+ self.syncSimulatedTime()
|
|
|
+ </script>
|
|
|
+ </transition>
|
|
|
+ <transition target="../CheckTermination" cond="INSTATE('../../ModeSelector/Paused') and (not ((self.waitTime() / 1000.0) <= self.sccd_yield()))">
|
|
|
+ <raise event="Simulation.Paused" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="self.clock" />
|
|
|
+ <parameter expr="self.state" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ <!-- We execute a step when the wait time is smaller than the smallest possible delay. -->
|
|
|
+ <transition target="../Executing" cond="self.waitTime() / 1000.0 <= self.sccd_yield()">
|
|
|
+ <raise event="BigStep.Execute" scope="narrow" target="'child_simulator'" />
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="Executing">
|
|
|
+ <transition target="../SettleBeforeCheckTermination" event="BigStep.Finished">
|
|
|
+ <parameter name="clock" />
|
|
|
+ <parameter name="timeNext" />
|
|
|
+ <parameter name="elapsed" />
|
|
|
+ <parameter name="eventList" />
|
|
|
+ <parameter name="state" />
|
|
|
+ <script>
|
|
|
+ <![CDATA[
|
|
|
+ self.clock = clock
|
|
|
+ self.timeNext = timeNext
|
|
|
+ self.elapsed = elapsed
|
|
|
+ self.eventList = eventList
|
|
|
+ self.state = state
|
|
|
+ ]]>
|
|
|
+ </script>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ <state id="Stopped" />
|
|
|
+ </state>
|
|
|
+ <state id="GodEventManager" initial="Listening">
|
|
|
+ <state id="Listening">
|
|
|
+ <transition target="." event="Simulation.GodEvent" cond="INSTATE('../../ModeSelector/Paused')">
|
|
|
+ <parameter name="block_name" />
|
|
|
+ <parameter name="new_val" />
|
|
|
+ <script>
|
|
|
+ result = self.godEvent(block_name, new_val)
|
|
|
+ </script>
|
|
|
+ <raise event="Simulation.GodEventResult" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="result" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ </state>
|
|
|
+ <state id="BreakpointManager" initial="Listening">
|
|
|
+ <state id="Listening">
|
|
|
+ <transition target="." event="Breakpoint.Add">
|
|
|
+ <parameter name="name"/>
|
|
|
+ <parameter name="function"/>
|
|
|
+ <parameter name="enabled"/>
|
|
|
+ <parameter name="disable_on_trigger"/>
|
|
|
+ <script>
|
|
|
+ result = self.addBreakpoint(name, function, bool(enabled), bool(disable_on_trigger))
|
|
|
+ </script>
|
|
|
+ <raise event="Breakpoint.AddResult" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="result" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ <transition target="." event="Breakpoint.Del">
|
|
|
+ <parameter name="name"/>
|
|
|
+ <script>
|
|
|
+ result = self.delBreakpoint(name)
|
|
|
+ </script>
|
|
|
+ <raise event="Breakpoint.DelResult" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="result" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ <transition target="." event="Breakpoint.Toggle">
|
|
|
+ <parameter name="name"/>
|
|
|
+ <script>
|
|
|
+ result = self.toggleBreakpoint(name)
|
|
|
+ </script>
|
|
|
+ <raise event="Breakpoint.ToggleResult" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="result" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ <transition target="." event="Breakpoint.List">
|
|
|
+ <raise event="Breakpoint.ListResult" scope="narrow" target="'parent'">
|
|
|
+ <parameter expr="[bp.name for bp in self.breakpoints]" />
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ </state>
|
|
|
+ </parallel>
|
|
|
+ <state id="Stopped" />
|
|
|
+ </scxml>
|
|
|
+</class>
|