rasProject_01 / weSweetHome  R. 240
process control       /     RasPi software         by   weinert-automation
Loading...
Searching...
No Matches
weStateM.h File Reference

States and state machines. More...

#include "sysBasic.h"

Data Structures

struct  state_t
 The structure for state machines. More...
 

Macros

#define newFiveBand(N, C, V, T, R, S)
 Define a five band checker. More...
 
#define newFloatHyst(N, C, O, R, S)
 Define a hysteresis (Schmitt trigger, float value) as state machine. More...
 
#define newSeqCont(N, C, n, m, S)
 Define a sequential function chart as state machine. More...
 
#define newSwitchDeb(N, C, S, R)
 Define a switch to be de-bounced as state machine. More...
 
#define newTimer(N, C, S)
 Define a timer as state machine. More...
 

Typedefs

typedef uint8_t(* enterState_t) (state_t *const me, uint32_t controlV)
 A state machine's own function to command entry in active state. More...
 
typedef uint8_t(* enterStateF_t) (state_t *const me, float controlF)
 Substitute or addendum to enterState_t.
 
typedef uint8_t(* enterStateS_t) (state_t *const me, char const *controlS)
 Substitute or addendum to enterState_t.
 
typedef void(* genStateText_t) (char *stateText, state_t const *const me, char const *stamp)
 Generate text for state machine status. More...
 
typedef uint8_t(* leaveState_t) (state_t *const me, uint32_t controlV)
 A state machine's own function to command exit out of active state. More...
 
typedef uint8_t(* leaveStateF_t) (state_t *const me, float controlF)
 Substitute or addendum to leaveState_t.
 
typedef uint8_t(* leaveStateS_t) (state_t *const me, char const *controlS)
 Substitute or addendum to leaveState_t.
 
typedef void(* onStateChange_t) (state_t *const me)
 The applications's call back function for state changes. More...
 
typedef struct state_t state_t
 The structure for state machines.
 
typedef uint8_t(* tickCheckState_t) (state_t *const me, uint32_t controlV)
 A machine's own function to be called to trigger / check state. More...
 
typedef uint8_t(* tickCheckStateF_t) (state_t *const me, float controlF)
 Substitute or addendum to tickCheckState_t.
 
typedef uint8_t(* tickCheckStateN_t) (state_t *const me)
 Substitute or addendum to tickCheckState_t.
 

Functions

uint8_t fiveBandDoEnter (state_t *const me, float analogueVal)
 Five band checker turn / force ON. More...
 
uint8_t fiveBandDoLeave (state_t *const me, float analogueVal)
 Five band checker turn / force OFF. More...
 
uint8_t fiveBandTick (state_t *const me, float controlV)
 Five band checker trigger. More...
 
uint8_t floatHystDoEnter (state_t *const me, float analogueVal)
 Float value hysteresis turn / force ON. More...
 
uint8_t floatHystDoLeave (state_t *const me, float analogueVal)
 Float value hysteresis turn / force OFF. More...
 
uint8_t floatHystTick (state_t *const me, float controlV)
 Float value hysteresis trigger. More...
 
void genStateText (char *stateText, state_t const *const me, char const *stamp)
 Generate text for state machine status. More...
 
void logStateReason (state_t const *const me, char const *stamp, char const *cause)
 Log status text with cause and info. More...
 
void logStateText (state_t const *const me, char const *stamp)
 Log status text. More...
 
uint8_t seqContDoEnter (state_t *const me, char const *startCommand)
 Sequential control entry. More...
 
uint8_t seqContDoLeave (state_t *const me, char const *stopCommand)
 Sequential control leave. More...
 
uint8_t seqContTick (state_t *const me)
 Sequential control tick or check. More...
 
void setGenStateText (state_t *const me, genStateText_t const fun)
 Set the function to generate text for state machine status. More...
 
void startStateText (char *stateText, state_t const *const me, char const *stamp)
 Generate status text standard start. More...
 
uint8_t switchDebDoEnter (state_t *const me, uint32_t controlV)
 Switch de-bounce turn / force ON. More...
 
uint8_t switchDebDoLeave (state_t *const me, uint32_t controlV)
 Switch de-bounce turn / force OFF. More...
 
uint8_t switchDebTick (state_t *const me, uint32_t controlV)
 Switch de-bounce trigger. More...
 
uint8_t switchDebTickAC (state_t *const me, uint32_t controlV)
 Switch de-bounce trigger AC. More...
 
uint8_t timerDoEnter (state_t *const me, uint32_t secFromNow)
 Timer entry. More...
 
uint8_t timerDoLeave (state_t *const me, uint32_t ignored)
 Timer leave, that is stop timer. More...
 
uint8_t timerDoStart (state_t *const me, uint32_t secFromNow)
 Timer unconditional entry and set. More...
 
uint8_t timerDoStart4ever (state_t *const me)
 Timer unconditional entry and set forever or stop it. More...
 
uint8_t timerDoTrigger (state_t *const me, uint32_t secFromNow)
 Timer entry or (pro-longing) re-trigger. More...
 
uint8_t timerEndTrigger (state_t *const me, uint32_t const secUTCend)
 Timer entry or (pro-longing) re-trigger to absolute UTC end. More...
 
uint8_t timerTickCheck (state_t *const me, uint32_t controlV)
 Timer trigger. More...
 

Detailed Description

States and state machines.

Copyright (c) 2018 2024 Albrecht Weinert
weinert-automation.de a-weinert.de
/ / /\
/ /___ / \ |
\ /____\ /____\ | _|__
\ /\ / \ / \| |
\/ \/ \__/ \__/|_

Revision history

Rev. 266 10.10.2024
Rev. 104 05.02.2018 : new
Rev. 154 26.06.2018 : genStateText, logStateText threadsafe; timerEndTrigger
Rev. 175 28.07.2018 : state machine structure made more clear and readable
Rev. 195 01.03.2019 : Five band checker
Rev. 198 04.03.2019 : justLogStateChg added
Rev. 200 16.04.2019 : state expanded, logging improved
Rev. 223 23.06.2020 : switchDebTickAC added
Rev. 266 08.10.2024 : clarifying in comments
uint8_t switchDebTickAC(state_t *const me, uint32_t controlV)
Switch de-bounce trigger AC.
Definition: weStateM.c:451
void genStateText(char *stateText, state_t const *const me, char const *stamp)
Generate text for state machine status.
Definition: weStateM.c:127
uint8_t timerEndTrigger(state_t *const me, uint32_t const secUTCend)
Timer entry or (pro-longing) re-trigger to absolute UTC end.
Definition: weStateM.c:375
void logStateText(state_t const *const me, char const *stamp)
Log status text.
Definition: weStateM.c:193

State machines are implemented in an object oriented way although C is in no way supporting objects. We do this by defining the state in a structure and the behaviour in a set of functions, regarding a defined structure variable plus the functions as an object modelling the state machine in question.
Of course, in C we don't have the object orientation principles, especially no encapsulation. There is no binding of behaviour (functions) to the state (structure variable), which leads to a structure pointer as first parameter of every related function. The only substitute is discipline.

As of Revision 193 there are five types of state machines:

  1. Timer, seconds resolution, UTC stamp (type 0xAD)
  2. switch de-bounce (type 0xDB)
  3. Float value hysteresis (0xFF)
  4. 5 band check ...badLO | critLo | OK | critHi | badHi... (0x5B)
  5. sequential Control in Sequential Function Chart (SFC) mannor (0xFC)

Macro Definition Documentation

◆ newTimer

#define newTimer (   N,
  C,
 
)

Define a timer as state machine.

A state machine of this type "timer" is either running or inactive. It is set active or re-triggered by an amount of seconds from now. The end of the interval is stored as absolute (UTC s) time.

The check/tick function timerTickCheck would, by default be called every second at least near the end of the interval. It might as well be called more seldom if a coarser resolution is applicable and or the the timer end event shall be synchronised with other events, like e.g. second 15 in every second minute.

One strategy would be to have all timers in an array or list and check all timers every second. When this list is kept sorted to active timers with nearest end date first, one can stop checking on the first timer without change to inactive. This sorted list approach is worthwhile with many timers, only.

This macro is the initialisation expression for a timer requiring the unique name and the fitting onStateChange function, only. The other fields are preset as the timer state machine type demands.

Hint: A timer may be made periodic by restarting it accordingly in its onStateChange function.

Parameters
Nname as string literal
ConStateChange function
SgenStateText function (NULL sets default / standard genStateText)

◆ newSwitchDeb

#define newSwitchDeb (   N,
  C,
  S,
 
)

Define a switch to be de-bounced as state machine.

A state machine of this type is to be provided with a switch/button input condition of either ON or OFF sampled at regular time intervals. It is constructed with a positive onThreshold (say 4) and a non-negative lower offThreshold (say 2, e.g.).
An internal counter is incremented by ON input when OFF from 0 to onThreshold. On OFF input and when ON the internal counter is decremented form offThreshold to 0.
As might have become obvious the state machine makes the OFF<->ON when these counters reach onThreshold respectively 0;

This macro is the initialisation expression for a switch de-bounce requiring the unique name and the fitting onStateChange function as well as the (uint8_t) values for the off and on threshold.

Parameters
Nname as string literal
ConStateChange function
SoffThreshold small non-negative integer
RonThreshold small positive integer

◆ newFloatHyst

#define newFloatHyst (   N,
  C,
  O,
  R,
 
)

Define a hysteresis (Schmitt trigger, float value) as state machine.

A state machine of this type is to be provided with an analogue (float) value sampled regularly. It is constructed with an On and an Off threshold value. It must hold onThreshold >= offThreshold; recommended is onThreshold > offThreshold with a significant difference.

The significance of status,subStatus for this state machine is:
0,0 : Off, below
1,0 : On, above
1,1 : On, within from above
0,1 : Off, within from below
0,3 : do not know the level (pre-trigger, reset state)
0,2 : do not know On or Off, within from reset state

As might have become obvious the state machine makes a transition to ON (1,0) when the sampled value becomes > onThreshold and to Off (0,0) when <= offThreshold.

The state change call back function will be called on the following transitions:
To "Off, below" (0,0) from: 1,x and (0,2)
To "On, above" (1,0) from: 0,x and
To "Undefined, between" (0,2) from: reset (0,3)

Note: The call back function might ignore the subStatus; this would take "Undefined, between" as Off and one might see two consecutive transitions to "Off".

This macro is the initialisation expression for a float value hysteresis requiring the unique name and the fitting onStateChange function as well as the (float) values for the off and on threshold.

Parameters
Nname as string literal
ConStateChange function
OoffThreshold valid float (i.e. non NaN)
RonThreshold valid float (R >= S)
SgenStateText function (NULL sets default / standard genStateText)

◆ newFiveBand

#define newFiveBand (   N,
  C,
  V,
  T,
  R,
 
)

Define a five band checker.

A state machine of this type is to be fed with an analogue (float) value sampled regularly. This value is compared to four thresholds or borders separating those five bands:
      ...badLO | critLo | OK | critHi | badHi...
The state machine is to be constructed with four thresholds the un-equality

::threshBadLo &lt; ::threshCritLo &lt; ::threshON &lt; ::threshOFF

must hold for. For VDE-AR-N 4105 e.g. one would take
47.7 49.5 -OK- 50.5 51.5 Hz resp. 184 207 -OK- 253 264 V
as thresholds.

The significance of status values for this state machine are:
2: bad Hi
1: critical Hi
0: OK
5: critical Lo
6: bad Lo
8: unknown / reset
subStatus is used as previous state. Hence 8,8 ist the reset state.

The state change call back function will called on all status transitions. realSecOff will be the time stamp of the last transition into OK (0) and realSecOn of the last transition out of it,

This macro is the initialisation expression for a five band checker requiring the unique name and the fitting onStateChange function as well as legal (float) values for the four thresholds.

Parameters
Nname as string literal
ConStateChange function
VthreshBadLo valid float (i.e. non NaN)
TthreshCritLo
RonThreshold valid float
SoffThreshold (S > R > T > V)

◆ newSeqCont

#define newSeqCont (   N,
  C,
  n,
  m,
 
)

Define a sequential function chart as state machine.

A state machine of this type is simplified two leg sequential function chart with one leg leading via intermediate steps form OFF to ON state and the other leg the other way.

The OFF state is: state_t.status == 0 and state_t.subStatus == 0
Chain to ON is: state_t.status == 0 and state_t.subStatus == 1..n-1
The ON state is: state_t.status == 1 and state_t.subStatus == 0
Chain to OFF is: state_t.status == 1 and state_t.subStatus == 1..m-1

Chain to ON interrupted by seqContDoLeave changes status from 0 to 4.
Chain to OFF interrupted by seqContDoEnter changes status from 1 to 5.

Parameters
Nname as string literal
ConStateChange function
nlength of chain to ON
mlength of chain to OFF
SgenStateText function (NULL sets default / standard genStateText)

Typedef Documentation

◆ enterState_t

typedef uint8_t(* enterState_t) (state_t *const me, uint32_t controlV)

A state machine's own function to command entry in active state.

Note: The enter function put in this function pointer may (and should) be called directly on fitting events. Nevertheless, the function put in this function pointer may be used by others, especially by a check/trigger function. Then, be sure not to have the wrong (default) function here.

Parameters
mepointer to the machine itself; never null
controlVcontrolValue or extra command for the state; the usage and semantic of this parameter depends on the state machine type
Returns
0: OK, state now or already entered respectively on its way else: entering the state not possible or inhibited. Depending on the concrete type the value might give the reason.

◆ leaveState_t

typedef uint8_t(* leaveState_t) (state_t *const me, uint32_t controlV)

A state machine's own function to command exit out of active state.

Note: See note at enterState_t.

Parameters
mepointer to own state; never null
controlVcontrolValue or extra command for the state; the usage and semantic of this parameter depends on the state implemented
Returns
0: OK state is now or was already inactive (or on its way there) else: leaving the state not possible or inhibited. Depending on the concrete type the value might give the reason.

◆ tickCheckState_t

typedef uint8_t(* tickCheckState_t) (state_t *const me, uint32_t controlV)

A machine's own function to be called to trigger / check state.

Note: See note at enterState_t.

Parameters
mepointer to the machine itself; never null never null
controlVadditional control value (float for tickCheckStateF_t)
Returns
0: state or, if applicable, sub-state changed; else: not

◆ onStateChange_t

typedef void(* onStateChange_t) (state_t *const me)

The applications's call back function for state changes.

This function will only be called when (set and) the own state_t.status really changed. Depending on type (see state_t.typ), this function may also be called when the own state_t.subStatus changed.

Parameters
mepointer to the machine itself

◆ genStateText_t

typedef void(* genStateText_t) (char *stateText, state_t const *const me, char const *stamp)

Generate text for state machine status.

This is the minimal common standard for all status machines.

Parameters
stateTexta character array supplied to hold the state text to be generated; minimal length 80.
mepointer to own state; never null!
stamp(time) stamp to be prepended (max. length 23); default " - "

Function Documentation

◆ setGenStateText()

void setGenStateText ( state_t *const  me,
genStateText_t const  fun 
)

Set the function to generate text for state machine status.

Parameters
mepointer to own state machine
funthe new text generator function

◆ startStateText()

void startStateText ( char *  stateText,
state_t const *const  me,
char const *  stamp 
)

Generate status text standard start.

This sets the common standard start of a status text in state text, like:

//0123456789x123456789v123456789t123456789q1
" 2019-04-26 03:08:26.278 # befRiseTimer: "

It ends with a blank at [40] after the colon at [39]. State machine type or instance specific text may be added from [40] or [41] up to (recommended) [76] followed by a terminating 0.

Hint: This function sets a 0 at [41] for robustness, i.e. having stateText always as string.

Parameters
stateTexta character array supplied to hold the state text to be generated; minimal length 80.
mepointer to own state; never null
stamp(time) stamp to be prepended (max. length 23); default " - "

◆ genStateText()

void genStateText ( char *  stateText,
state_t const *const  me,
char const *  stamp 
)

Generate text for state machine status.

This is the minimal common standard for all status machines.

Parameters
stateTexta character array supplied to hold the state text to be generated; minimal length 80.
mepointer to own state; never null!
stamp(time) stamp to be prepended (max. length 23); default " - "

◆ logStateText()

void logStateText ( state_t const *const  me,
char const *  stamp 
)

Log status text.

The status as text will be generated in and then be output to outLog. outLog will be flushed.

Parameters
mepointer to own state; not null
stamp(time) stamp to be prepended (max. length 23); default " - "

◆ logStateReason()

void logStateReason ( state_t const *const  me,
char const *  stamp,
char const *  cause 
)

Log status text with cause and info.

The status as text will be generated and then be output to outLog. outLog will be flushed.
The text will be:
    stamp # state machine name: cause me->infoTxt
me->infoTxt has to be set/ provided by application software and will be output to a maximum / recommended length of 29. A standard format is one field of 7 and two fields of ten characters separated by spaces.

Parameters
mepointer to own state; not null
stamp(time) stamp to be prepended (max. length 23); default " - "
causethe cause of the state change (max. length 6); default me->controlVS

◆ timerTickCheck()

uint8_t timerTickCheck ( state_t *const  me,
uint32_t  controlV 
)

Timer trigger.

Parameters
mepointer to own state; not null
controlVcurrent time stamp; mostly cycTaskEventData_t.realSec resp. getAbsS()
Returns
0: state changed, i.e. timer ended; 2: still running; 4: inactive

◆ timerDoEnter()

uint8_t timerDoEnter ( state_t *const  me,
uint32_t  secFromNow 
)

Timer entry.

This function starts an inactive timer to end secFromNow s. It does nothing on a timer already active resp. running, especially, it does not re-trigger / prolong the timer's time.

This is the function set as (default) state_t.doEnter and not timerDoStart.

Parameters
mepointer to own state; not null
secFromNowtime to run on from now (s)
Returns
0: OK, timer no or already ON

◆ timerDoStart()

uint8_t timerDoStart ( state_t *const  me,
uint32_t  secFromNow 
)

Timer unconditional entry and set.

This function starts an inactive timer. The timer's end time will be set to (now + secFromNow s) no matter the timers previous state. This unconditional changing the end time of a timer already running is the difference to timerDoEnter.

This is not the function set as (default) state_t.doEnter; it is timerDoEnter.

Parameters
mepointer to own state; not null
secFromNowtime to run on from now (s)
Returns
0: now started; 1: was running, probably end time changed

◆ timerDoStart4ever()

uint8_t timerDoStart4ever ( state_t *const  me)

Timer unconditional entry and set forever or stop it.

This function starts an inactive timer. The timer's end time will be set to 2.2.2106 no matter the timers previous state. This date is considered as for ever in our 21st century. This does effectively stop the timer.

This function is intended to start or keep running a timer not to end before its time is to be set (by timerDoStart) to a sensible end time.
One use case is: A timer running forever is in error state.

This function is, of course, faster than timerDoEnter and timerDoStart.

Parameters
mepointer to own state; not null
Returns
0: now started; 1: was running, probably end time changed

◆ timerDoTrigger()

uint8_t timerDoTrigger ( state_t *const  me,
uint32_t  secFromNow 
)

Timer entry or (pro-longing) re-trigger.

This function starts an inactive timer to end secFromNow s. IF the timer is active and if (now + secFromNow) is later than the current end, the timer me's runtime will be prolonged accordingly (timer re-trigger).

Parameters
mepointer to own state; not null
secFromNowtime to run on from now (s)
Returns
0: OK, timer starter or prolonged to new (later) time 1: running timer not prolonged

◆ timerEndTrigger()

uint8_t timerEndTrigger ( state_t *const  me,
uint32_t const  secUTCend 
)

Timer entry or (pro-longing) re-trigger to absolute UTC end.

If secUTCend is now or in the past or if it is equal the the end of the already active timer, nothing will be done (returns 1).

This function starts an inactive timer to end at secUTCend. If the timer is active already secUTCend will be taken as new end time.

Parameters
mepointer to own state; not null
secUTCendend time
Returns
0: OK (started or re-triggered); 1: no state change (on and no prolonging, or secUTCend in past)

◆ timerDoLeave()

uint8_t timerDoLeave ( state_t *const  me,
uint32_t  ignored 
)

Timer leave, that is stop timer.

Note: This function is usable for other state machine types, too, if appropriate.

Parameters
mepointer to own state; not null
ignoredas the name says
Returns
0: state changed, 1: state hold

◆ switchDebTick()

uint8_t switchDebTick ( state_t *const  me,
uint32_t  controlV 
)

Switch de-bounce trigger.

Parameters
mepointer to own state; not null
controlV0: input OFF else: input ON
Returns
0: state changed, 1: state hold
See also
newSwitchDeb

◆ switchDebTickAC()

uint8_t switchDebTickAC ( state_t *const  me,
uint32_t  controlV 
)

Switch de-bounce trigger AC.

This function does essentially the same as switchDebTick, except for On ticks being counted twice. This is meant for half wave rectified AC signals sampled at multiples of their frequency. Obviously, half or 1/2 + 1 of the samples will always be Off. And, of course, the state machine has to be made with a on chain length being by the number of samples per period higher than the normal switch de-bounce filter time, to avoid spiky ON results.

Parameters
mepointer to own state; not null
controlV0: input OFF else: input ON
Returns
0: OFF, 1: ON
See also
newSwitchDeb

◆ switchDebDoEnter()

uint8_t switchDebDoEnter ( state_t *const  me,
uint32_t  controlV 
)

Switch de-bounce turn / force ON.

Parameters
mepointer to own state; not null
controlVirrelevant but recorded ob state change
Returns
0: state changed, 1: state hold

◆ switchDebDoLeave()

uint8_t switchDebDoLeave ( state_t *const  me,
uint32_t  controlV 
)

Switch de-bounce turn / force OFF.

Note: this function is usable for other non timer stati, too;

Parameters
mepointer to own state; not null
controlVirrelevant but recorded ob state change
Returns
0: state changed, 1: state hold

◆ floatHystTick()

uint8_t floatHystTick ( state_t *const  me,
float  controlV 
)

Float value hysteresis trigger.

Parameters
mepointer to own state; not null
controlVthe sampled analogue value
Returns
0: state change, 1: no change, 0xFF: fault i.e. controlV is NaN (no state change)

◆ floatHystDoEnter()

uint8_t floatHystDoEnter ( state_t *const  me,
float  analogueVal 
)

Float value hysteresis turn / force ON.

Parameters
mepointer to own state; not null
analogueValirrelevant, but recorded
Returns
0: OK, state now ON; 0xFF: fault (me is NULL e.g.)

◆ floatHystDoLeave()

uint8_t floatHystDoLeave ( state_t *const  me,
float  analogueVal 
)

Float value hysteresis turn / force OFF.

Note: this function is usable for other non timer stati, too;

Parameters
mepointer to own state; not null
analogueValirrelevant, but recorded; may take an (uint32_t) cast float
Returns
0: state change, 1: no change

◆ fiveBandTick()

uint8_t fiveBandTick ( state_t *const  me,
float  controlV 
)

Five band checker trigger.

Parameters
mepointer to own state; not null
controlVthe sampled analogue value
Returns
0: state change, 1: no change

◆ fiveBandDoEnter()

uint8_t fiveBandDoEnter ( state_t *const  me,
float  analogueVal 
)

Five band checker turn / force ON.

This function puts the checker in state bad Hi (2) no matter the parameter value.

Parameters
mepointer to own state; not null
analogueValirrelevant, but recorded on state change
Returns
0: state change, 1: no change

◆ fiveBandDoLeave()

uint8_t fiveBandDoLeave ( state_t *const  me,
float  analogueVal 
)

Five band checker turn / force OFF.

This function puts the checker in state OK (0) no matter the parameter value.

Parameters
mepointer to own state; not null
analogueValirrelevant, but recorded on state change
Returns
0: state change, 1: no change

◆ seqContDoEnter()

uint8_t seqContDoEnter ( state_t *const  me,
char const *  startCommand 
)

Sequential control entry.

This function starts the sequence from OFF to ON.

Parameters
mepointer to own state; not null
startCommandthe cause of the state change; 6 characters (max.) to be recorded and else irrelevant for his function
Returns
0: OK state now ON or on its way there; 1: already ON

◆ seqContDoLeave()

uint8_t seqContDoLeave ( state_t *const  me,
char const *  stopCommand 
)

Sequential control leave.

This function starts the sequence from ON to OFF.

Parameters
mepointer to own state; not null
stopCommandIt is recorded on state changes and else irrelevant for this function; see description on seqContTick
Returns
0: OK state now OFF or on its way there; else: other inhibit condition

◆ seqContTick()

uint8_t seqContTick ( state_t *const  me)

Sequential control tick or check.

If this sequential control (me) is not in a stable OFF or ON state, that is state_t.status is 0 or 1 and state_t.subStatus is 0, this function should be called at regular intervals or on relevant conditions state changes.

The function must keep or advance the state.

It must react on interrupts by seqContDoEnter or seqContDoLeave recognisable by state_t.status == 5 respectively 4. Note: This is just for the case, that individual the call back function state_t.onStateChange does not handle this "interrupts" — what it really should.

This (basic) implementation advances the sub state from 1 to n-1 respectively m-1. Interrupts by seqContDoEnter or seqContDoLeave are handled by changing to sub state 1 of the opposite leg.

When this basic implementation is not sufficient for a concrete SFC, the application may provide an own tick/check function. However, in most cases seemingly complicated cases — nonlinear chains, wait conditions etc. — the specialised behaviour can most often be implemented by an individual state_t.onStateChange call back function.

Parameters
mepointer to own state; not null
Returns
0: state or sub-state changed 0xFF: fault status panic ... else: current state kept, of course