/*! @page q_qcoroutines Co-Routines
* @tableofcontents
*
* @section q_qcoroutines_overview Overview
* A task coded as a Co-Routine, is just a task that allows multiple entry points
* for suspending and resuming execution at certain locations, this feature can
* bring benefits by improving the task cooperative scheme and providing a linear
* code execution for event-driven systems without complex state machines or full
* multithreading.
*
* <center>
* @htmlonly
* <!DOCTYPE html>
* <html>
* <head>
* <title>coroutines++</title>
* <meta charset="utf-8"/>
* </head>
* <body><div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="{&quot;highlight&quot;:&quot;#0000ff&quot;,&quot;nav&quot;:true,&quot;zoom&quot;:1.5,&quot;resize&quot;:true,&quot;toolbar&quot;:&quot;zoom layers tags lightbox&quot;,&quot;edit&quot;:&quot;_blank&quot;,&quot;xml&quot;:&quot;&lt;mxfile host=\&quot;app.diagrams.net\&quot; modified=\&quot;2023-05-05T15:39:02.820Z\&quot; agent=\&quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36\&quot; etag=\&quot;mj9W_H0TDWNc1i3MwvPx\&quot; version=\&quot;21.2.3\&quot; type=\&quot;google\&quot;&gt;\n  &lt;diagram name=\&quot;Página-1\&quot; id=\&quot;OwHXzfAKBHHQWS32Xnqf\&quot;&gt;\n    &lt;mxGraphModel dx=\&quot;741\&quot; dy=\&quot;-37\&quot; grid=\&quot;1\&quot; gridSize=\&quot;10\&quot; guides=\&quot;1\&quot; tooltips=\&quot;1\&quot; connect=\&quot;1\&quot; arrows=\&quot;1\&quot; fold=\&quot;1\&quot; page=\&quot;1\&quot; pageScale=\&quot;1\&quot; pageWidth=\&quot;1169\&quot; pageHeight=\&quot;827\&quot; math=\&quot;0\&quot; shadow=\&quot;0\&quot;&gt;\n      &lt;root&gt;\n        &lt;mxCell id=\&quot;0\&quot; /&gt;\n        &lt;mxCell id=\&quot;1\&quot; parent=\&quot;0\&quot; /&gt;\n        &lt;mxCell id=\&quot;tTk1LmOXMArJNXh1joMB-1\&quot; value=\&quot;&amp;amp;nbsp;co::reenter() {&amp;lt;br&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;co::yield();&amp;lt;br&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;co::yield();&amp;lt;br&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br&amp;gt;&amp;amp;nbsp;}\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;strokeColor=#007FFF;fillColor=none;fontFamily=Lucida Console;strokeWidth=2;fontColor=#808080;fontStyle=0;fontSize=10;align=left;\&quot; parent=\&quot;1\&quot; vertex=\&quot;1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;721\&quot; y=\&quot;1446\&quot; width=\&quot;138\&quot; height=\&quot;124\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;tTk1LmOXMArJNXh1joMB-2\&quot; value=\&quot;Task A\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#CCE5FF;fontColor=#808080;strokeColor=#007FFF;fillStyle=solid;fontFamily=Helvetica;strokeWidth=2;fontStyle=1\&quot; parent=\&quot;1\&quot; vertex=\&quot;1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;721\&quot; y=\&quot;1430\&quot; width=\&quot;138\&quot; height=\&quot;16\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;tTk1LmOXMArJNXh1joMB-5\&quot; value=\&quot;\&quot; style=\&quot;endArrow=blockThin;html=1;rounded=0;shadow=0;fontFamily=Lucida Console;fontSize=10;fontColor=#B3B3B3;strokeColor=#808080;strokeWidth=1;startArrow=oval;startFill=1;endFill=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;\&quot; parent=\&quot;1\&quot; edge=\&quot;1\&quot;&gt;\n          &lt;mxGeometry width=\&quot;50\&quot; height=\&quot;50\&quot; relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;845.0000000000002\&quot; y=\&quot;1461.4399999999998\&quot; as=\&quot;sourcePoint\&quot; /&gt;\n            &lt;mxPoint x=\&quot;845\&quot; y=\&quot;1560\&quot; as=\&quot;targetPoint\&quot; /&gt;\n            &lt;Array as=\&quot;points\&quot;&gt;\n              &lt;mxPoint x=\&quot;845\&quot; y=\&quot;1490\&quot; /&gt;\n              &lt;mxPoint x=\&quot;925\&quot; y=\&quot;1461\&quot; /&gt;\n              &lt;mxPoint x=\&quot;925\&quot; y=\&quot;1500\&quot; /&gt;\n              &lt;mxPoint x=\&quot;845\&quot; y=\&quot;1500\&quot; /&gt;\n              &lt;mxPoint x=\&quot;845\&quot; y=\&quot;1530\&quot; /&gt;\n              &lt;mxPoint x=\&quot;925\&quot; y=\&quot;1510\&quot; /&gt;\n              &lt;mxPoint x=\&quot;925\&quot; y=\&quot;1550\&quot; /&gt;\n              &lt;mxPoint x=\&quot;845\&quot; y=\&quot;1540\&quot; /&gt;\n            &lt;/Array&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;TdvfbX77WpDKRGBcznC6-2\&quot; value=\&quot;&amp;amp;nbsp;co::reenter() {&amp;lt;br style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;co::yield();&amp;lt;br style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;&amp;amp;nbsp; &amp;amp;nbsp; &amp;amp;nbsp;...&amp;lt;br style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;&amp;amp;nbsp;}\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;strokeColor=#007FFF;fillColor=none;fontFamily=Lucida Console;strokeWidth=2;fontColor=#808080;fontStyle=0;fontSize=10;align=left;\&quot; vertex=\&quot;1\&quot; parent=\&quot;1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;917\&quot; y=\&quot;1446\&quot; width=\&quot;138\&quot; height=\&quot;124\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;TdvfbX77WpDKRGBcznC6-4\&quot; value=\&quot;Task B\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#CCE5FF;fontColor=#808080;strokeColor=#007FFF;fillStyle=solid;fontFamily=Helvetica;strokeWidth=2;fontStyle=1\&quot; vertex=\&quot;1\&quot; parent=\&quot;1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;917\&quot; y=\&quot;1430\&quot; width=\&quot;138\&quot; height=\&quot;16\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n      &lt;/root&gt;\n    &lt;/mxGraphModel&gt;\n  &lt;/diagram&gt;\n&lt;/mxfile&gt;\n&quot;}"></div>
* <script type="text/javascript" src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>
* </body>
* </html>
* @endhtmlonly
* <em>Coroutines in QuarkTS++</em>
* </center>
*
* The QuarkTS++ implementation is stackless by using the Duff's device approach, and is heavily
* inspired by the Knuth method, <a style="font-weight:bold" href="https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html">Simon Tatham's Co-Routines in C</a>
* and <a style="font-weight:bold" href="http://dunkels.com/adam/pt/index.html">Adam Dunkels Protothreads</a>
* . This means that a local-continuation variable is used to preserve the current
* state of execution at a particular place of the Co-Routine scope but without
* any call history or local variables. This brings benefits to lower RAM usage,
* but at the cost of some restrictions on how a Co-routine can be used.
*
* <b> Limitations and restrictions </b>
*
* - The stack of a Co-Routine is not maintained when a yield is performed. This
* means variables allocated on the stack will loose their values. To overcome
* this, a variable that must maintain its value across a blocking call must be
* declared as @c static.
* - Calls to API functions that could cause the Co-Routine to block, can only
* be made from the Co-Routine function itself - not from within a function
* called by the Co-Routine.
* - The implementation does not permit yielding or blocking calls to be made from
* within a @c switch statement.
*
* @section q_coroutine_code Coding a Co-Routine
* The application writer just needs to create the body of the Co-Routine . This
* means starting a Co-Routine segment with qOS::co::reenter() statement . From now on,
* yields and blocking calls from the Co-Routine scope are allowed.
*
*  @code{.c}
*  void CoroutineTask_Callback( event_t e ) {
*      co::reenter() {
*          for (;;) {
*              if ( EventNotComing() ) {
*                  co::yield();
*              }
*              DoTheEventProcessing();
*              co::delay( WAIT_TIME_MS );
*              PerformActions();
*         }
*      }
*  }
*  @endcode
*
* The qOS::co::reenter() statement should be placed at the start of the task function
* in which the Co-routine runs.
*
* A qOS::co::yield() statement return the CPU control back to the scheduler but saving
* the  execution progress, thereby allowing other processing tasks to take place
* in the system. With the next task activation, the Co-Routine will resume the
* execution after the last qOS::co::yield() statement.
*
* @note Co-Routine statements can only be invoked from the scope of the
* Co-Routine.
* @remark You should put an endless-loop inside a Co-routine, this behavior is
* not hardcoded within the segment definition.
*
* @section q_coroutine_blocking Blocking calls in a Co-routine
* Blocking calls inside a Co-Routine should be made with the provided
* statements, all of them with a common feature: an implicit yield.
*
* A widely used procedure is to wait for a fixed period of time. For this, the
* qOS::co::delay() should be used. This statement makes an apparent blocking over the
* application flow, but to be precise, a yield is performed until the requested
* time expires, this allows other tasks to be executed until the blocking call
* finish. This "yielding until condition meet" behavior its the common pattern
* among the other blocking statements.
*
* Another common blocking call is qOS::co::waitUntil(). This statement takes a
* condition argument, a logical expression that will be performed when the
* Co-Routine resumes their execution. As mentioned before, this type of
* statement exposes the expected behavior, yielding until the condition is met.
*
* An additional overload of this qOS::co::waitUntil() is also provided. This one
* sets a timeout for the logical condition to be met.
*
* Optionally, the qOS::co::performUntil structure gives to application writer the ability
* to perform a multi-line job before the yield, allowing more complex actions
* to being performed after the Co-Routine resumes:
*
*  @code{.c}
*  co::perform() {
*      /*Job : a set of instructions */
*  } co::until( condition );
*  @endcode
*
* @warning Co-routines statements are not allowed within the job segment.
*
* @section q_coroutine_example1 Co-Routine usage example
*
*  @code{.c}
*  void Sender_Task( event_t e ) {
*      co::reenter() {
*          Send_Packet();
*          /* Wait until an acknowledgment has been received, or until
*           * the timer expires. If the timer expires, we should send
*           * the packet again.
*           */
*          co::waitUntil( PacketACK_Received(), TIMEOUT_TIME );
*          co::restart();
*      }
*  }
*  /*===================================================================*/
*  void Receiver_Task( event_t e ) {
*      co::reenter() {
*          /* Wait until a packet has been received*/
*          co::waitUntil( Packet_Received() );
*          Send_Acknowledgement();
*          co::restart();
*      };
*  }
*  @endcode
*
* @section q_coroutine_positions Positional jumps
* This feature provides positional local jumps, control flow that deviates from
* the usual Co-Routine call.
*
* The complementary statements qOS::co::getPosition() and qOS::co::setPosition() provide
* this
* functionality. The first one saves the Co-Routine state at some point of their
* execution into @c CRPos, a variable of type qOS::co::position , that can be used
* at some later point of program execution by qOS::co::setPosition() to restore
* the Co-Routine state to the one saved by qOS::co::getPosition() into CRPos. This
* process can be imagined to be a "jump" back to the point of program execution
* where qOS::co::getPosition() saved the Co-Routine environment.
*
* @section q_coroutine_semaphores Semaphores
* This extension implements counting semaphores on top of Co-Routines.
* Semaphores are a synchronization primitive that provide two operations: @a wait
* and @a signal. The @a wait operation checks the semaphore counter and blocks
* the Co-Routine if the counter is zero. The @a signal operation increases the
* semaphore counter but does not block. If another Co-Routine has blocked
* waiting for the semaphore that is signaled, the blocked Co-Routines will
* become runnable again.
*
* Semaphores are referenced by handles, a variable of type qOS::co::semaphore and
* must be initialized at time of creating with its own constructor. Here, a value for the
* counter is required. Internally, semaphores use an @c size_t to represent
* the counter, therefore the value argument should be within range of this
* data-type.
*
* To perform the wait operation, the qOS::co::semWait() statement should be used.
* The wait operation causes the Co-routine to block while the counter is zero.
* When the counter reaches a value larger than zero, the Co-Routine will
* continue.
*
* Finally, qOS::co::semSignal() carries out the @a signal operation on the semaphore.
* This signaling increments the counter inside the semaphore, which eventually
* will cause waiting Coroutines to continue executing.
*
* @section q_coroutine_example2 Co-Routine example with semaphores.
* The following example shows how to implement the bounded buffer problem using
* Co-Routines and semaphores. The example uses two tasks: one that produces items
* and other that consumes items.
*
* Note that there is no need for a mutex to guard the @c add_to_buffer() and
* @c get_from_buffer() functions because of the implicit locking semantics of
* Co-Routines, so it will never be preempted and will never block except in an
* explicit qOS::co::semWait() statement.
*
*  @code{.c}
*  #include "HAL.h"
*  #include "QuarkTS.h"
*  #include "AppLibrary.h"
*
*  using namespace qOS;
*
*  #define NUM_ITEMS    ( 32 )
*  #define BUFSIZE      ( 8 )
*
*  task_t ProducerTask, ConsumerTask;
*  co::semaphore mutex( 1 ), full( BUFSIZE ), empty( 0 );
*  /*===================================================================*/
*  void ProducerTask_Callback( event_t e ) {
*      static int produced;
*
*      co::reenter() {
*          for ( produced = 0 ; produced < NUM_ITEMS ; ++produced ) {
*              co::semWait( full );
*              co::semWait( mutex );
*
*              add_to_buffer( produce_item() );
*
*              co::semSignal( mutex );
*              co::semSignal( empty );
*          }
*          co::restart();
*      }
*  }
*  /*===================================================================*/
*  void ConsumerTask_Callback( event_t e ) {
*      static int consumed;
*
*      co::reenter() {
*          for ( consumed = 0 ; consumed < NUM_ITEMS ; ++consumed ) {
*              co::semWait( empty );
*              co::semWait( mutex );
*
*              consume_item( get_from_buffer() );
*              co::semSignal( mutex );
*              co::semSignal( full );
*          }
*      };
*  }
*  /*===================================================================*/
*  void IdleTask_Callback( event_t e ) {
*      /*nothing to do*/
*  }
*  /*===================================================================*/
*  int main(void) {
*      HAL_Init();
*
*      os.init( HAL_GetTick, IdleTask_Callback );
*
*      os.add( ProducerTask, ProducerTask_Callback, core::MEDIUM_PRIORITY,
               100_ms, task::PERIODIC, taskState::ENABLED );
*      os.add( ConsumerTask, ConsumerTask_Callback, core::MEDIUM_PRIORITY,
               100_ms, task::PERIODIC, taskState::ENABLED );
*      os.run();
*      return 0;
*  }
*  @endcode
*
* @section q_coroutine_ext External control
* In certain situations, it may be necessary to control the flow of execution
* outside of the segment that defines the Co-routine itself. This is typically
* done to defer or resume the Co-routine in response to specific occurrences
* that arise in other contexts, such as tasks or interrupts.
*
* To address these specific scenarios, a handler for the Co-routine must be
* defined, which is a variable of type qOS::co::handle. Additionally, to
* initiate the scope of the target Co-routine, the statement qOS::co::reenter()
* should be used taking this handler as argument.
*
*  @code{.c}
*  co::handle xHandleCR;
*
*  /*===================================================================*/
*  void AnotherTask_Callback( event_t e ) {
*      int UserInput = 0;
*      if ( e.firstIteration() ) {
*          xHandleCR.try_resume();
*      }
*      if ( e.lastIteration() ) {
*          xHandleCR.try_suspend();
*      }
*      UserInput = GetTerminalInput();
*      if ( UserInput == USR_RESTART ) {
*          xHandleCR.try_restart();
*      }
*      Perform_AnotherTask_Activities();
*  }
*  /*===================================================================*/
*  void CoroutineTask_Callback( event_t e ) {
*      co::reenter( xHandleCR ) { /*externally controlled*/
*          for(;;) {
*              if ( EventNotComing() ) {
*                  co::yield();
*              }
*              RunFirstJob();
*              co::delay( WAIT_TIME );
*              SecondJobStatus = RunSecondJob();
*              co::waitUntil( JobFlag == JOB_SUCCESS, JOB_TIMEOUT );
*              CleanUpStatus = CleanupJob();
*              co::waitUntil( SomeVar > SomeValue );
*          }
*      };
*  }
*  @endcode
*
* As shown in the code snippet above, the Co-routine handle its globally declared
* to enable other contexts to access it. The example demonstrates  how  another
* task can control the Coroutine using the "try_" methods. It's
* important to note that the actions performed by this API can only be effective
* after the handle instantiation, which is a one-time operation that occurs
* during the first call of the Co-routine.
*
*/