Deterministic Real-Time Behavior
Deterministic here does not imply fixed-sequence polling.
Although this is possible too, the RXF uses a different method to achieve a deterministic behavior.
The RXF serves your generated application.
It will provide services like sending and receiving events, handling timeout events and more.
How Events are processed.
When an event is sent, the RXF will store a pointer to that event in a
queue for the appropriate task, where
it will be handled in a FIFO manner. The handling of events is also
done by the RXF. Handling events also means handling expired
timers that are converted to events when they expire.
An event for a specific object will be given to the generated event
handle function of that Objects Class. This function carries out all the
associated actions (On Entry, On Exit, in State, in transitions) and
will return the control to the RXF when finished.
This will guarantee a flawless handling of events in a deterministic
way. Actions can be delayed by other actions but only for a time that
can easily be calculated.
How Time-outs (tm(xx) ) are handled.
When the tm(xx) statement is used in a state-machine,
the user wants a certain delay in the processing of states.
tm(xx) in a transition means: Wait xx milliseconds
and then take this transition (and execute all attached actions).
The timer ticks are processed by a callback function of the RXF, which is called at a regular interval of
MS_PER_TICK ms.
The delay in the tm(Delay) statement
should only be a multiple of MS_PER_TICK. Values that do not mach a multiple of the tick time get
rounded up to the next matching multiple of ticks (e.g. if the tick time is 10ms and tm(1) is typed, the Delay will be 1 Tick (10ms) )
Due
to the fact that the timer is derived from an external tick source, the
granularity of the ticks is the minimum tick value. It is possible
that a timeout request occurs
just before a tick would happen or just after a tick has happened, what
leads to an inaccuracy of timout transitions of 1 tick.
In general a timeout will expire between ( timeout-time - MS_PER_TICK ) and timeout-time, or in other words in worst case 1 Tick (or the time defined in MS_PER_TICK) earlier than expected. If a MINIMUM time for tm(xx) to pass before the transition is taken needs to be guaranteed, the time of one tick ( value of MS_PER_TICK
) needs to be added to the desired time. This is done automatically by
the simplifier for all timeout-transitions of a reactive class, if the
property RXF::Class::TimeoutGuaranteeTime is set to true on this class. If this property should be applied to the whole model, it can also be overridden on project or component level.
It is a common problem for timeouts that they can expire 1 tick earlier than expected. See also:
https://www.ibm.com/support/pages/rhapsody-tm-function-not-precise
https://www.keil.com/support/docs/3766.htm
After the timout has expired, a timeout event is
placed to the event queue.
If a statechart is in the middle of processing an event,
that event needs to complete before the timeout is handled. Also there
can be other events in the queue that are processed first.
This could cause a non-determinable extra delay.
When using the RXF with an
RTOS Adapter, please note:
To
prevent additional delay through suppression of timer management task
by other tasks, the priority of the timer management task should be
configured to be the highest.
The following timeout behavior can be observed with MS_PER_TICK = 10 miliseconds:
[tm(0)] - expires immediately - is put to queue without being scheduled.
[tm(1)] - expires after 0 to 10 ms (at the next tick).
[tm(10)] - expires after 10 to 20 ms. (Same behavieor as tm(1) to tm(9))
[tm(11)] - expires after 10 to 20 ms.
[tm(20)] - expires after 10 to 20 ms.
[tm(100)] - expires after 90 to 100 ms.
[tm(1000)] - expires after 990 to 1000 ms.
And so on.
So the argument in tm(xx) indicates the time ( minus 1 Tick ) to pass before
the transition is taken!
With
RXF::Class::TimeoutGuaranteeTime = true the expected timeout values are:
[tm(0)] - expires at the next tick (0 to 10 ms later).
[tm(1)] - expires after 10 to 20 ms.
[tm(10)] - expires after 10 to 20 ms.
[tm(11)] - expires after 20 to 30 ms.
[tm(20)] - expires after 20 to 30 ms.
[tm(100)] - expires after 100 to 110 ms.
[tm(1000)] - expires after 1000 to 1010 ms.
The RXF prevents invalid values for the delay as far as possible:
- A
delay of 0 (zero) milliseconds (i.e. tm(0) ) will result in a timeout
event that is immediately queued without being scheduled.
- The argument type is unsigned int. For negative values or invalid arguments the compiler should issue a warning.
Run-To-Completion (NULL-Transitions)
In a statechart it is possible to model state transitions that are
directly to be taken, without waiting for an event as a trigger. These
are so called NULL-transitions. The RXF includes a mechanism to detect
endless loops of NULL-transitions (e.g. because of a design error in
modeling a state machine) during runtime. An endless loop is detected,
if more than a defined number of NULL-transitions occur in a row. This
maximum number of directly following NULL-transitions can be configured.
NULL-transitions on Statechart Start Behavior
If the first transition of a statechart is a NULL transition (without trigger) the Framework
handles the transition from the context, that calls the startBehavior() operation.
From this context a runToCompletion() is executed. That means all
following states that are connected with NULL transitions are executed
from this startup context. The user should be aware of this when using
initial NULL transitions.
If a context switch is required before
executing initial behavior, a tm(0) can be used as trigger for a state
containing this behavior. A tm(0) will put a timeout event in the event
queue immediately and thereby trigger a context switch to the execution
context of this statechart.