rasProject_01 / weSweetHome  R. 240
process control       /     RasPi software         by   weinert-automation
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
weStateM.c File Reference

States and state machine support. More...

#include "weStateM.h"
#include "weUtil.h"

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 const 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 *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 machine support.

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. 108 02.12.2018 : parts moved out, one event file
Rev. 193 25.02.2019 : fifeBandCheck implemented
Rev. 195 01.03.2019 : switch de-bounce debugged
Rev. 198 04.03.2019 : justLogStateChg added
Rev. 200 16.04.2019 : state expanded, logging improved
Rev. 204 15.05.2019 : logStateReason repaired
Rev. 223 23.06.2020 : switchDebTickAC added
Rev. 263 08.09.2024 : formEpocTime added (to make logged timers readable)
uint8_t switchDebTickAC(state_t *const me, uint32_t controlV)
Switch de-bounce trigger AC.
Definition: weStateM.c:451
void logStateReason(state_t const *const me, char const *stamp, char const *cause)
Log status text with cause and info.
Definition: weStateM.c:217
char * formEpocTime(char *target, uint32_t value)
Format 32 bit unsigned epoch time as ddhh:ssss relative to today.
Definition: weUtil.c:303

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)

    cross-compile by: arm-linux-gnueabihf-gcc -DMCU=BCM2837 -I./include -c -o weRasp/weStateM.o weRasp/weStateM.c

Function Documentation

◆ 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

◆ 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

◆ 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