| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- #include "app/fseq/fseq.h"
- #include "my_assert.h"
- #include <stdbool.h>
- // @sFSeqObj_t
- // The sequencer private structure
- typedef struct
- {
- const fFSeqEntry_t * fEntry; // current "function object" pointer
- tFSeqCtx_t ctx; // user context
- }
- sFSeqObj_t;
- // @fSeqConstruct
- // Construct the sequencer object, but not run it.
- // @fSeqObj - the object to construct
- // @first - the main state of the object, can not be NULL
- // @ctx - user-defined context, can be NULL
- void fSeqConstruct( xFSeqObj_t * fSeq, const fFSeqEntry_t * first, tFSeqCtx_t ctx )
- {
- my_assert( fSeq );
- my_assert( first );
- my_assert( first->vtbl );
- my_assert( first->vtbl->f );
- if( NULL != fSeq && NULL != first )
- {
- ((sFSeqObj_t*)fSeq)->fEntry = first;
- ((sFSeqObj_t*)fSeq)->ctx = ctx;
- }
- }
- // @fSeqStartup
- // Starts the constructed sequencer.
- // @fSeqObj - the sequencer object to start
- // @first - the state to start from, can be NULL
- // If @first is NULL, the value @first from the @fSeqConstruct() call will be used.
- void fSeqStartup( xFSeqObj_t * fSeq, const fFSeqEntry_t * first )
- {
- if( NULL != first )
- {
- ((sFSeqObj_t*)fSeq)->fEntry = first;
- }
- #if FSEQ_ENTRY_EXIT_SUPPORT
- #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
- ((sFSeqObj_t*)fSeq)->fEntry->vtbl->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- #else
- ((sFSeqObj_t*)fSeq)->fEntry->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- #endif
- #endif
- }
- // @fSeqShutdown
- // Shutdowns the running sequencer
- // @fSeqObj - the sequencer object to shutdown
- void fSeqShutdown( xFSeqObj_t * fSeq )
- {
- #if FSEQ_ENTRY_EXIT_SUPPORT
- #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
- ((sFSeqObj_t*)fSeq)->fEntry->vtbl->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- #else
- ((sFSeqObj_t*)fSeq)->fEntry->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- #endif
- #endif
- }
- // @fSeqDispatch
- // Provides the sequencer work
- // Must be called to make the sequencer call the state functions
- // @fSeqObj - the sequencer object to operate with
- void fSeqDispatch( xFSeqObj_t * fSeq )
- {
- const fFSeqEntry_t * next;
-
- #if FSEQ_ENTRY_EXIT_SUPPORT
- const fFSeqEntry_t * next_deferred = NULL;
- #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
- while( (next = ((sFSeqObj_t*)fSeq)->fEntry->vtbl->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &next_deferred ), next ) )
- {
- if( ((sFSeqObj_t*)fSeq)->fEntry != next ) // provide leave/enter events only if the operator has been changed
- {
- ((sFSeqObj_t*)fSeq)->fEntry->vtbl->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- ((sFSeqObj_t*)fSeq)->fEntry = next;
- ((sFSeqObj_t*)fSeq)->fEntry->vtbl->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- }
- }
- if( NULL != next_deferred )
- { // provide leave/enter events even if the operator has been changed (deffered feature)
- ((sFSeqObj_t*)fSeq)->fEntry->vtbl->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- ((sFSeqObj_t*)fSeq)->fEntry = next_deferred;
- ((sFSeqObj_t*)fSeq)->fEntry->vtbl->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- }
- #else
- while( (next = ((sFSeqObj_t*)fSeq)->fEntry->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &next_deferred ), next ) )
- {
- if( ((sFSeqObj_t*)fSeq)->fEntry != next ) // provide leave/enter events only if the operator has been changed
- {
- ((sFSeqObj_t*)fSeq)->fEntry->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- ((sFSeqObj_t*)fSeq)->fEntry = next;
- ((sFSeqObj_t*)fSeq)->fEntry->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- }
- }
- if( NULL != next_deferred )
- { // provide leave/enter events even if the operator has been changed (deffered feature)
- ((sFSeqObj_t*)fSeq)->fEntry->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- ((sFSeqObj_t*)fSeq)->fEntry = next_deferred;
- ((sFSeqObj_t*)fSeq)->fEntry->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
- }
- #endif
- #else
- #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
- while( NULL != (next = ((sFSeqObj_t*)fSeq)->fEntry->vtbl->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &((sFSeqObj_t*)fSeq)->fEntry ), next) )
- {
- ((sFSeqObj_t*)fSeq)->fEntry = next;
- }
- #else
- while( NULL != (next = ((sFSeqObj_t*)fSeq)->fEntry->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &((sFSeqObj_t*)fSeq)->fEntry ), next) )
- {
- ((sFSeqObj_t*)fSeq)->fEntry = next;
- }
- #endif
- #endif
- }
- #if 0
- #if FSEQ_ALT_INHERIT_METHOD_SUPPORT == 0
- // ----------------
- // Inheritance example:
- xFSeqObj_t seq; // sequencer
- // ...
- // first state vtable method prototypes:
- const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t *, tFSeqCtx_t, const fFSeqEntry_t * * );
- void firstStateEnter( const fFSeqEntry_t *, tFSeqCtx_t );
- void firstStateLeave( const fFSeqEntry_t *, tFSeqCtx_t );
- // ...
- struct
- {
- int publicVar;
- }
- GlobalContext; // no comments
- // ...
- typedef struct
- {
- int privateVar;
- }
- tFirstStatePrivateContext;
-
- tFirstStatePrivateContext firstStatePrivateDynamicContext; // the dynamic private context of first state (RAM)
- // ...
- // The state user-structure, incuding the state entry itself (firstState) and the const pointer to the another object.
- const struct {
- fFSeqEntry_t firstState;
- void * ctx_ref;
- } firstStateExtended = {
- .firstState = { firstStateFunction, firstStateEnter, firstStateLeave },
- .ctx_ref = &firstStatePrivateDynamicContext // link the const pointer with the dynamic object
- };
- // ...
- void foo() // some user function
- {
- fSeqConstruct( &seq, &firstStateExtended.firstState, &GlobalContext ); // consturct sequencer and link the global context
- }
- // ...
- // @firstStateFunction
- // firstState function body
- const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t * this, tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
- {
- const void * const_ctx_ref = (const void*)(&this[1]); // get access to the @ctx_ref field from @firstStateExtended structure
- // ...
- tFirstStatePrivateContext * private_ctx = (void*)const_ctx_ref; // cast the pointer
- // ...
- private_ctx->privateVar = 1; // use private context
- }
- #endif
- #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
- // ------------------------------------------------------------------------------------------------
- // Inheritance example (Method #1, see @FSEQ_ALT_INHERIT_METHOD_SUPPORT):
- xFSeqObj_t seq; // sequencer
- // ...
- // first state vtable method prototypes:
- const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t *, tFSeqCtx_t, const fFSeqEntry_t * * );
- void firstStateEnter( const fFSeqEntry_t *, tFSeqCtx_t );
- void firstStateLeave( const fFSeqEntry_t *, tFSeqCtx_t );
- // ...
- struct
- {
- int publicVar;
- }
- GlobalContext; // no comments
- // ...
- typedef struct
- {
- int privateVar;
- }
- tFirstStatePrivateContext;
- // ...
- typedef struct
- {
- fFSeqEntry_t firstState;
- tFirstStatePrivateContext privateContext;
- }
- tFirstStateAndPrivateContext;
- // the structure of state methods:
- const fFSeqVTable_t firstStateVTable = { firstStateFunction, firstStateEnter, firstStateLeave };
- // The state user-structure, incuding the state entry, and the private context itself:
- tFirstStateAndPrivateContext firstStateExtended = { // the dynamic private context of first state (RAM)
- .firstState.vtbl = &firstStateVTable,
- .privateContext = { .privateVar = 0, // some values...
- }
- };
- // ...
- // ...
- void foo() // some user function
- {
- fSeqConstruct( &seq, &firstStateExtended.firstState, &GlobalContext ); // consturct sequencer and link the global context
- }
- // ...
- // @firstStateFunction
- // firstState function body
- const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t * this, tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
- {
- tFirstStatePrivateContext * private_ctx = (tFirstStatePrivateContext*)(&this[1]); // get access to the private context
- // ...
- private_ctx->privateVar = 1; // use private context
- }
- // ------------------------------------------------------------------------------------------------
- #endif
- #endif
|