fseq.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #include "app/fseq/fseq.h"
  2. #include "my_assert.h"
  3. #include <stdbool.h>
  4. // @sFSeqObj_t
  5. // The sequencer private structure
  6. typedef struct
  7. {
  8. const fFSeqEntry_t * fEntry; // current "function object" pointer
  9. tFSeqCtx_t ctx; // user context
  10. }
  11. sFSeqObj_t;
  12. // @fSeqConstruct
  13. // Construct the sequencer object, but not run it.
  14. // @fSeqObj - the object to construct
  15. // @first - the main state of the object, can not be NULL
  16. // @ctx - user-defined context, can be NULL
  17. void fSeqConstruct( xFSeqObj_t * fSeq, const fFSeqEntry_t * first, tFSeqCtx_t ctx )
  18. {
  19. my_assert( fSeq );
  20. my_assert( first );
  21. my_assert( first->vtbl );
  22. my_assert( first->vtbl->f );
  23. if( NULL != fSeq && NULL != first )
  24. {
  25. ((sFSeqObj_t*)fSeq)->fEntry = first;
  26. ((sFSeqObj_t*)fSeq)->ctx = ctx;
  27. }
  28. }
  29. // @fSeqStartup
  30. // Starts the constructed sequencer.
  31. // @fSeqObj - the sequencer object to start
  32. // @first - the state to start from, can be NULL
  33. // If @first is NULL, the value @first from the @fSeqConstruct() call will be used.
  34. void fSeqStartup( xFSeqObj_t * fSeq, const fFSeqEntry_t * first )
  35. {
  36. if( NULL != first )
  37. {
  38. ((sFSeqObj_t*)fSeq)->fEntry = first;
  39. }
  40. #if FSEQ_ENTRY_EXIT_SUPPORT
  41. #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
  42. ((sFSeqObj_t*)fSeq)->fEntry->vtbl->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  43. #else
  44. ((sFSeqObj_t*)fSeq)->fEntry->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  45. #endif
  46. #endif
  47. }
  48. // @fSeqShutdown
  49. // Shutdowns the running sequencer
  50. // @fSeqObj - the sequencer object to shutdown
  51. void fSeqShutdown( xFSeqObj_t * fSeq )
  52. {
  53. #if FSEQ_ENTRY_EXIT_SUPPORT
  54. #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
  55. ((sFSeqObj_t*)fSeq)->fEntry->vtbl->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  56. #else
  57. ((sFSeqObj_t*)fSeq)->fEntry->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  58. #endif
  59. #endif
  60. }
  61. // @fSeqDispatch
  62. // Provides the sequencer work
  63. // Must be called to make the sequencer call the state functions
  64. // @fSeqObj - the sequencer object to operate with
  65. void fSeqDispatch( xFSeqObj_t * fSeq )
  66. {
  67. const fFSeqEntry_t * next;
  68. #if FSEQ_ENTRY_EXIT_SUPPORT
  69. const fFSeqEntry_t * next_deferred = NULL;
  70. #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
  71. while( (next = ((sFSeqObj_t*)fSeq)->fEntry->vtbl->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &next_deferred ), next ) )
  72. {
  73. if( ((sFSeqObj_t*)fSeq)->fEntry != next ) // provide leave/enter events only if the operator has been changed
  74. {
  75. ((sFSeqObj_t*)fSeq)->fEntry->vtbl->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  76. ((sFSeqObj_t*)fSeq)->fEntry = next;
  77. ((sFSeqObj_t*)fSeq)->fEntry->vtbl->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  78. }
  79. }
  80. if( NULL != next_deferred )
  81. { // provide leave/enter events even if the operator has been changed (deffered feature)
  82. ((sFSeqObj_t*)fSeq)->fEntry->vtbl->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  83. ((sFSeqObj_t*)fSeq)->fEntry = next_deferred;
  84. ((sFSeqObj_t*)fSeq)->fEntry->vtbl->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  85. }
  86. #else
  87. while( (next = ((sFSeqObj_t*)fSeq)->fEntry->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &next_deferred ), next ) )
  88. {
  89. if( ((sFSeqObj_t*)fSeq)->fEntry != next ) // provide leave/enter events only if the operator has been changed
  90. {
  91. ((sFSeqObj_t*)fSeq)->fEntry->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  92. ((sFSeqObj_t*)fSeq)->fEntry = next;
  93. ((sFSeqObj_t*)fSeq)->fEntry->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  94. }
  95. }
  96. if( NULL != next_deferred )
  97. { // provide leave/enter events even if the operator has been changed (deffered feature)
  98. ((sFSeqObj_t*)fSeq)->fEntry->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  99. ((sFSeqObj_t*)fSeq)->fEntry = next_deferred;
  100. ((sFSeqObj_t*)fSeq)->fEntry->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
  101. }
  102. #endif
  103. #else
  104. #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
  105. while( NULL != (next = ((sFSeqObj_t*)fSeq)->fEntry->vtbl->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &((sFSeqObj_t*)fSeq)->fEntry ), next) )
  106. {
  107. ((sFSeqObj_t*)fSeq)->fEntry = next;
  108. }
  109. #else
  110. while( NULL != (next = ((sFSeqObj_t*)fSeq)->fEntry->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &((sFSeqObj_t*)fSeq)->fEntry ), next) )
  111. {
  112. ((sFSeqObj_t*)fSeq)->fEntry = next;
  113. }
  114. #endif
  115. #endif
  116. }
  117. #if 0
  118. #if FSEQ_ALT_INHERIT_METHOD_SUPPORT == 0
  119. // ----------------
  120. // Inheritance example:
  121. xFSeqObj_t seq; // sequencer
  122. // ...
  123. // first state vtable method prototypes:
  124. const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t *, tFSeqCtx_t, const fFSeqEntry_t * * );
  125. void firstStateEnter( const fFSeqEntry_t *, tFSeqCtx_t );
  126. void firstStateLeave( const fFSeqEntry_t *, tFSeqCtx_t );
  127. // ...
  128. struct
  129. {
  130. int publicVar;
  131. }
  132. GlobalContext; // no comments
  133. // ...
  134. typedef struct
  135. {
  136. int privateVar;
  137. }
  138. tFirstStatePrivateContext;
  139. tFirstStatePrivateContext firstStatePrivateDynamicContext; // the dynamic private context of first state (RAM)
  140. // ...
  141. // The state user-structure, incuding the state entry itself (firstState) and the const pointer to the another object.
  142. const struct {
  143. fFSeqEntry_t firstState;
  144. void * ctx_ref;
  145. } firstStateExtended = {
  146. .firstState = { firstStateFunction, firstStateEnter, firstStateLeave },
  147. .ctx_ref = &firstStatePrivateDynamicContext // link the const pointer with the dynamic object
  148. };
  149. // ...
  150. void foo() // some user function
  151. {
  152. fSeqConstruct( &seq, &firstStateExtended.firstState, &GlobalContext ); // consturct sequencer and link the global context
  153. }
  154. // ...
  155. // @firstStateFunction
  156. // firstState function body
  157. const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t * this, tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
  158. {
  159. const void * const_ctx_ref = (const void*)(&this[1]); // get access to the @ctx_ref field from @firstStateExtended structure
  160. // ...
  161. tFirstStatePrivateContext * private_ctx = (void*)const_ctx_ref; // cast the pointer
  162. // ...
  163. private_ctx->privateVar = 1; // use private context
  164. }
  165. #endif
  166. #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
  167. // ------------------------------------------------------------------------------------------------
  168. // Inheritance example (Method #1, see @FSEQ_ALT_INHERIT_METHOD_SUPPORT):
  169. xFSeqObj_t seq; // sequencer
  170. // ...
  171. // first state vtable method prototypes:
  172. const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t *, tFSeqCtx_t, const fFSeqEntry_t * * );
  173. void firstStateEnter( const fFSeqEntry_t *, tFSeqCtx_t );
  174. void firstStateLeave( const fFSeqEntry_t *, tFSeqCtx_t );
  175. // ...
  176. struct
  177. {
  178. int publicVar;
  179. }
  180. GlobalContext; // no comments
  181. // ...
  182. typedef struct
  183. {
  184. int privateVar;
  185. }
  186. tFirstStatePrivateContext;
  187. // ...
  188. typedef struct
  189. {
  190. fFSeqEntry_t firstState;
  191. tFirstStatePrivateContext privateContext;
  192. }
  193. tFirstStateAndPrivateContext;
  194. // the structure of state methods:
  195. const fFSeqVTable_t firstStateVTable = { firstStateFunction, firstStateEnter, firstStateLeave };
  196. // The state user-structure, incuding the state entry, and the private context itself:
  197. tFirstStateAndPrivateContext firstStateExtended = { // the dynamic private context of first state (RAM)
  198. .firstState.vtbl = &firstStateVTable,
  199. .privateContext = { .privateVar = 0, // some values...
  200. }
  201. };
  202. // ...
  203. // ...
  204. void foo() // some user function
  205. {
  206. fSeqConstruct( &seq, &firstStateExtended.firstState, &GlobalContext ); // consturct sequencer and link the global context
  207. }
  208. // ...
  209. // @firstStateFunction
  210. // firstState function body
  211. const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t * this, tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
  212. {
  213. tFirstStatePrivateContext * private_ctx = (tFirstStatePrivateContext*)(&this[1]); // get access to the private context
  214. // ...
  215. private_ctx->privateVar = 1; // use private context
  216. }
  217. // ------------------------------------------------------------------------------------------------
  218. #endif
  219. #endif