]> begriffs open source - freertos/blob - include/croutine.h
Style: uncrustify kernel files
[freertos] / include / croutine.h
1 /*\r
2  * FreeRTOS Kernel V10.3.1\r
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  */\r
26 \r
27 #ifndef CO_ROUTINE_H\r
28 #define CO_ROUTINE_H\r
29 \r
30 #ifndef INC_FREERTOS_H\r
31         #error "include FreeRTOS.h must appear in source files before include croutine.h"\r
32 #endif\r
33 \r
34 #include "list.h"\r
35 \r
36 #ifdef __cplusplus\r
37 extern "C" {\r
38 #endif\r
39 \r
40 /* Used to hide the implementation of the co-routine control block.  The\r
41 control block structure however has to be included in the header due to\r
42 the macro implementation of the co-routine functionality. */\r
43 typedef void * CoRoutineHandle_t;\r
44 \r
45 /* Defines the prototype to which co-routine functions must conform. */\r
46 typedef void (*crCOROUTINE_CODE)( CoRoutineHandle_t, UBaseType_t );\r
47 \r
48 typedef struct corCoRoutineControlBlock\r
49 {\r
50         crCOROUTINE_CODE        pxCoRoutineFunction;\r
51         ListItem_t                      xGenericListItem;       /*< List item used to place the CRCB in ready and blocked queues. */\r
52         ListItem_t                      xEventListItem;         /*< List item used to place the CRCB in event lists. */\r
53         UBaseType_t             uxPriority;                     /*< The priority of the co-routine in relation to other co-routines. */\r
54         UBaseType_t             uxIndex;                        /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */\r
55         uint16_t                        uxState;                        /*< Used internally by the co-routine implementation. */\r
56 } CRCB_t; /* Co-routine control block.  Note must be identical in size down to uxPriority with TCB_t. */\r
57 \r
58 /**\r
59  * croutine. h\r
60  *<pre>\r
61  BaseType_t xCoRoutineCreate(\r
62                                  crCOROUTINE_CODE pxCoRoutineCode,\r
63                                  UBaseType_t uxPriority,\r
64                                  UBaseType_t uxIndex\r
65                                );</pre>\r
66  *\r
67  * Create a new co-routine and add it to the list of co-routines that are\r
68  * ready to run.\r
69  *\r
70  * @param pxCoRoutineCode Pointer to the co-routine function.  Co-routine\r
71  * functions require special syntax - see the co-routine section of the WEB\r
72  * documentation for more information.\r
73  *\r
74  * @param uxPriority The priority with respect to other co-routines at which\r
75  *  the co-routine will run.\r
76  *\r
77  * @param uxIndex Used to distinguish between different co-routines that\r
78  * execute the same function.  See the example below and the co-routine section\r
79  * of the WEB documentation for further information.\r
80  *\r
81  * @return pdPASS if the co-routine was successfully created and added to a ready\r
82  * list, otherwise an error code defined with ProjDefs.h.\r
83  *\r
84  * Example usage:\r
85    <pre>\r
86  // Co-routine to be created.\r
87  void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )\r
88  {\r
89  // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
90  // This may not be necessary for const variables.\r
91  static const char cLedToFlash[ 2 ] = { 5, 6 };\r
92  static const TickType_t uxFlashRates[ 2 ] = { 200, 400 };\r
93 \r
94      // Must start every co-routine with a call to crSTART();\r
95      crSTART( xHandle );\r
96 \r
97      for( ;; )\r
98      {\r
99          // This co-routine just delays for a fixed period, then toggles\r
100          // an LED.  Two co-routines are created using this function, so\r
101          // the uxIndex parameter is used to tell the co-routine which\r
102          // LED to flash and how int32_t to delay.  This assumes xQueue has\r
103          // already been created.\r
104          vParTestToggleLED( cLedToFlash[ uxIndex ] );\r
105          crDELAY( xHandle, uxFlashRates[ uxIndex ] );\r
106      }\r
107 \r
108      // Must end every co-routine with a call to crEND();\r
109      crEND();\r
110  }\r
111 \r
112  // Function that creates two co-routines.\r
113  void vOtherFunction( void )\r
114  {\r
115  uint8_t ucParameterToPass;\r
116  TaskHandle_t xHandle;\r
117 \r
118      // Create two co-routines at priority 0.  The first is given index 0\r
119      // so (from the code above) toggles LED 5 every 200 ticks.  The second\r
120      // is given index 1 so toggles LED 6 every 400 ticks.\r
121      for( uxIndex = 0; uxIndex < 2; uxIndex++ )\r
122      {\r
123          xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );\r
124      }\r
125  }\r
126    </pre>\r
127  * \defgroup xCoRoutineCreate xCoRoutineCreate\r
128  * \ingroup Tasks\r
129  */\r
130 BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex );\r
131 \r
132 \r
133 /**\r
134  * croutine. h\r
135  *<pre>\r
136  void vCoRoutineSchedule( void );</pre>\r
137  *\r
138  * Run a co-routine.\r
139  *\r
140  * vCoRoutineSchedule() executes the highest priority co-routine that is able\r
141  * to run.  The co-routine will execute until it either blocks, yields or is\r
142  * preempted by a task.  Co-routines execute cooperatively so one\r
143  * co-routine cannot be preempted by another, but can be preempted by a task.\r
144  *\r
145  * If an application comprises of both tasks and co-routines then\r
146  * vCoRoutineSchedule should be called from the idle task (in an idle task\r
147  * hook).\r
148  *\r
149  * Example usage:\r
150    <pre>\r
151  // This idle task hook will schedule a co-routine each time it is called.\r
152  // The rest of the idle task will execute between co-routine calls.\r
153  void vApplicationIdleHook( void )\r
154  {\r
155         vCoRoutineSchedule();\r
156  }\r
157 \r
158  // Alternatively, if you do not require any other part of the idle task to\r
159  // execute, the idle task hook can call vCoRoutineSchedule() within an\r
160  // infinite loop.\r
161  void vApplicationIdleHook( void )\r
162  {\r
163     for( ;; )\r
164     {\r
165         vCoRoutineSchedule();\r
166     }\r
167  }\r
168  </pre>\r
169  * \defgroup vCoRoutineSchedule vCoRoutineSchedule\r
170  * \ingroup Tasks\r
171  */\r
172 void vCoRoutineSchedule( void );\r
173 \r
174 /**\r
175  * croutine. h\r
176  * <pre>\r
177  crSTART( CoRoutineHandle_t xHandle );</pre>\r
178  *\r
179  * This macro MUST always be called at the start of a co-routine function.\r
180  *\r
181  * Example usage:\r
182    <pre>\r
183  // Co-routine to be created.\r
184  void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )\r
185  {\r
186  // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
187  static int32_t ulAVariable;\r
188 \r
189      // Must start every co-routine with a call to crSTART();\r
190      crSTART( xHandle );\r
191 \r
192      for( ;; )\r
193      {\r
194           // Co-routine functionality goes here.\r
195      }\r
196 \r
197      // Must end every co-routine with a call to crEND();\r
198      crEND();\r
199  }</pre>\r
200  * \defgroup crSTART crSTART\r
201  * \ingroup Tasks\r
202  */\r
203 #define crSTART( pxCRCB ) switch( ( ( CRCB_t * )( pxCRCB ) )->uxState ) { case 0:\r
204 \r
205 /**\r
206  * croutine. h\r
207  * <pre>\r
208  crEND();</pre>\r
209  *\r
210  * This macro MUST always be called at the end of a co-routine function.\r
211  *\r
212  * Example usage:\r
213    <pre>\r
214  // Co-routine to be created.\r
215  void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )\r
216  {\r
217  // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
218  static int32_t ulAVariable;\r
219 \r
220      // Must start every co-routine with a call to crSTART();\r
221      crSTART( xHandle );\r
222 \r
223      for( ;; )\r
224      {\r
225           // Co-routine functionality goes here.\r
226      }\r
227 \r
228      // Must end every co-routine with a call to crEND();\r
229      crEND();\r
230  }</pre>\r
231  * \defgroup crSTART crSTART\r
232  * \ingroup Tasks\r
233  */\r
234 #define crEND() }\r
235 \r
236 /*\r
237  * These macros are intended for internal use by the co-routine implementation\r
238  * only.  The macros should not be used directly by application writers.\r
239  */\r
240 #define crSET_STATE0( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2):\r
241 #define crSET_STATE1( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1):\r
242 \r
243 /**\r
244  * croutine. h\r
245  *<pre>\r
246  crDELAY( CoRoutineHandle_t xHandle, TickType_t xTicksToDelay );</pre>\r
247  *\r
248  * Delay a co-routine for a fixed period of time.\r
249  *\r
250  * crDELAY can only be called from the co-routine function itself - not\r
251  * from within a function called by the co-routine function.  This is because\r
252  * co-routines do not maintain their own stack.\r
253  *\r
254  * @param xHandle The handle of the co-routine to delay.  This is the xHandle\r
255  * parameter of the co-routine function.\r
256  *\r
257  * @param xTickToDelay The number of ticks that the co-routine should delay\r
258  * for.  The actual amount of time this equates to is defined by\r
259  * configTICK_RATE_HZ (set in FreeRTOSConfig.h).  The constant portTICK_PERIOD_MS\r
260  * can be used to convert ticks to milliseconds.\r
261  *\r
262  * Example usage:\r
263    <pre>\r
264  // Co-routine to be created.\r
265  void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )\r
266  {\r
267  // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
268  // This may not be necessary for const variables.\r
269  // We are to delay for 200ms.\r
270  static const xTickType xDelayTime = 200 / portTICK_PERIOD_MS;\r
271 \r
272      // Must start every co-routine with a call to crSTART();\r
273      crSTART( xHandle );\r
274 \r
275      for( ;; )\r
276      {\r
277         // Delay for 200ms.\r
278         crDELAY( xHandle, xDelayTime );\r
279 \r
280         // Do something here.\r
281      }\r
282 \r
283      // Must end every co-routine with a call to crEND();\r
284      crEND();\r
285  }</pre>\r
286  * \defgroup crDELAY crDELAY\r
287  * \ingroup Tasks\r
288  */\r
289 #define crDELAY( xHandle, xTicksToDelay )                                                                                               \\r
290         if( ( xTicksToDelay ) > 0 )                                                                                                                     \\r
291         {                                                                                                                                                                       \\r
292                 vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL );                                                  \\r
293         }                                                                                                                                                                       \\r
294         crSET_STATE0( ( xHandle ) );\r
295 \r
296 /**\r
297  * <pre>\r
298  crQUEUE_SEND(\r
299                   CoRoutineHandle_t xHandle,\r
300                   QueueHandle_t pxQueue,\r
301                   void *pvItemToQueue,\r
302                   TickType_t xTicksToWait,\r
303                   BaseType_t *pxResult\r
304              )</pre>\r
305  *\r
306  * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine\r
307  * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.\r
308  *\r
309  * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas\r
310  * xQueueSend() and xQueueReceive() can only be used from tasks.\r
311  *\r
312  * crQUEUE_SEND can only be called from the co-routine function itself - not\r
313  * from within a function called by the co-routine function.  This is because\r
314  * co-routines do not maintain their own stack.\r
315  *\r
316  * See the co-routine section of the WEB documentation for information on\r
317  * passing data between tasks and co-routines and between ISR's and\r
318  * co-routines.\r
319  *\r
320  * @param xHandle The handle of the calling co-routine.  This is the xHandle\r
321  * parameter of the co-routine function.\r
322  *\r
323  * @param pxQueue The handle of the queue on which the data will be posted.\r
324  * The handle is obtained as the return value when the queue is created using\r
325  * the xQueueCreate() API function.\r
326  *\r
327  * @param pvItemToQueue A pointer to the data being posted onto the queue.\r
328  * The number of bytes of each queued item is specified when the queue is\r
329  * created.  This number of bytes is copied from pvItemToQueue into the queue\r
330  * itself.\r
331  *\r
332  * @param xTickToDelay The number of ticks that the co-routine should block\r
333  * to wait for space to become available on the queue, should space not be\r
334  * available immediately. The actual amount of time this equates to is defined\r
335  * by configTICK_RATE_HZ (set in FreeRTOSConfig.h).  The constant\r
336  * portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see example\r
337  * below).\r
338  *\r
339  * @param pxResult The variable pointed to by pxResult will be set to pdPASS if\r
340  * data was successfully posted onto the queue, otherwise it will be set to an\r
341  * error defined within ProjDefs.h.\r
342  *\r
343  * Example usage:\r
344    <pre>\r
345  // Co-routine function that blocks for a fixed period then posts a number onto\r
346  // a queue.\r
347  static void prvCoRoutineFlashTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )\r
348  {\r
349  // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
350  static BaseType_t xNumberToPost = 0;\r
351  static BaseType_t xResult;\r
352 \r
353     // Co-routines must begin with a call to crSTART().\r
354     crSTART( xHandle );\r
355 \r
356     for( ;; )\r
357     {\r
358         // This assumes the queue has already been created.\r
359         crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );\r
360 \r
361         if( xResult != pdPASS )\r
362         {\r
363             // The message was not posted!\r
364         }\r
365 \r
366         // Increment the number to be posted onto the queue.\r
367         xNumberToPost++;\r
368 \r
369         // Delay for 100 ticks.\r
370         crDELAY( xHandle, 100 );\r
371     }\r
372 \r
373     // Co-routines must end with a call to crEND().\r
374     crEND();\r
375  }</pre>\r
376  * \defgroup crQUEUE_SEND crQUEUE_SEND\r
377  * \ingroup Tasks\r
378  */\r
379 #define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult )                 \\r
380 {                                                                                                                                                                               \\r
381         *( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) );       \\r
382         if( *( pxResult ) == errQUEUE_BLOCKED )                                                                                         \\r
383         {                                                                                                                                                                       \\r
384                 crSET_STATE0( ( xHandle ) );                                                                                                    \\r
385                 *pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 );                                  \\r
386         }                                                                                                                                                                       \\r
387         if( *pxResult == errQUEUE_YIELD )                                                                                                       \\r
388         {                                                                                                                                                                       \\r
389                 crSET_STATE1( ( xHandle ) );                                                                                                    \\r
390                 *pxResult = pdPASS;                                                                                                                             \\r
391         }                                                                                                                                                                       \\r
392 }\r
393 \r
394 /**\r
395  * croutine. h\r
396  * <pre>\r
397   crQUEUE_RECEIVE(\r
398                      CoRoutineHandle_t xHandle,\r
399                      QueueHandle_t pxQueue,\r
400                      void *pvBuffer,\r
401                      TickType_t xTicksToWait,\r
402                      BaseType_t *pxResult\r
403                  )</pre>\r
404  *\r
405  * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine\r
406  * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.\r
407  *\r
408  * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas\r
409  * xQueueSend() and xQueueReceive() can only be used from tasks.\r
410  *\r
411  * crQUEUE_RECEIVE can only be called from the co-routine function itself - not\r
412  * from within a function called by the co-routine function.  This is because\r
413  * co-routines do not maintain their own stack.\r
414  *\r
415  * See the co-routine section of the WEB documentation for information on\r
416  * passing data between tasks and co-routines and between ISR's and\r
417  * co-routines.\r
418  *\r
419  * @param xHandle The handle of the calling co-routine.  This is the xHandle\r
420  * parameter of the co-routine function.\r
421  *\r
422  * @param pxQueue The handle of the queue from which the data will be received.\r
423  * The handle is obtained as the return value when the queue is created using\r
424  * the xQueueCreate() API function.\r
425  *\r
426  * @param pvBuffer The buffer into which the received item is to be copied.\r
427  * The number of bytes of each queued item is specified when the queue is\r
428  * created.  This number of bytes is copied into pvBuffer.\r
429  *\r
430  * @param xTickToDelay The number of ticks that the co-routine should block\r
431  * to wait for data to become available from the queue, should data not be\r
432  * available immediately. The actual amount of time this equates to is defined\r
433  * by configTICK_RATE_HZ (set in FreeRTOSConfig.h).  The constant\r
434  * portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see the\r
435  * crQUEUE_SEND example).\r
436  *\r
437  * @param pxResult The variable pointed to by pxResult will be set to pdPASS if\r
438  * data was successfully retrieved from the queue, otherwise it will be set to\r
439  * an error code as defined within ProjDefs.h.\r
440  *\r
441  * Example usage:\r
442  <pre>\r
443  // A co-routine receives the number of an LED to flash from a queue.  It\r
444  // blocks on the queue until the number is received.\r
445  static void prvCoRoutineFlashWorkTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )\r
446  {\r
447  // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
448  static BaseType_t xResult;\r
449  static UBaseType_t uxLEDToFlash;\r
450 \r
451     // All co-routines must start with a call to crSTART().\r
452     crSTART( xHandle );\r
453 \r
454     for( ;; )\r
455     {\r
456         // Wait for data to become available on the queue.\r
457         crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );\r
458 \r
459         if( xResult == pdPASS )\r
460         {\r
461             // We received the LED to flash - flash it!\r
462             vParTestToggleLED( uxLEDToFlash );\r
463         }\r
464     }\r
465 \r
466     crEND();\r
467  }</pre>\r
468  * \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE\r
469  * \ingroup Tasks\r
470  */\r
471 #define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult )                   \\r
472 {                                                                                                                                                                               \\r
473         *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) );         \\r
474         if( *( pxResult ) == errQUEUE_BLOCKED )                                                                                         \\r
475         {                                                                                                                                                                       \\r
476                 crSET_STATE0( ( xHandle ) );                                                                                                    \\r
477                 *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 );                                \\r
478         }                                                                                                                                                                       \\r
479         if( *( pxResult ) == errQUEUE_YIELD )                                                                                           \\r
480         {                                                                                                                                                                       \\r
481                 crSET_STATE1( ( xHandle ) );                                                                                                    \\r
482                 *( pxResult ) = pdPASS;                                                                                                                 \\r
483         }                                                                                                                                                                       \\r
484 }\r
485 \r
486 /**\r
487  * croutine. h\r
488  * <pre>\r
489   crQUEUE_SEND_FROM_ISR(\r
490                             QueueHandle_t pxQueue,\r
491                             void *pvItemToQueue,\r
492                             BaseType_t xCoRoutinePreviouslyWoken\r
493                        )</pre>\r
494  *\r
495  * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the\r
496  * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()\r
497  * functions used by tasks.\r
498  *\r
499  * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to\r
500  * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and\r
501  * xQueueReceiveFromISR() can only be used to pass data between a task and and\r
502  * ISR.\r
503  *\r
504  * crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue\r
505  * that is being used from within a co-routine.\r
506  *\r
507  * See the co-routine section of the WEB documentation for information on\r
508  * passing data between tasks and co-routines and between ISR's and\r
509  * co-routines.\r
510  *\r
511  * @param xQueue The handle to the queue on which the item is to be posted.\r
512  *\r
513  * @param pvItemToQueue A pointer to the item that is to be placed on the\r
514  * queue.  The size of the items the queue will hold was defined when the\r
515  * queue was created, so this many bytes will be copied from pvItemToQueue\r
516  * into the queue storage area.\r
517  *\r
518  * @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto\r
519  * the same queue multiple times from a single interrupt.  The first call\r
520  * should always pass in pdFALSE.  Subsequent calls should pass in\r
521  * the value returned from the previous call.\r
522  *\r
523  * @return pdTRUE if a co-routine was woken by posting onto the queue.  This is\r
524  * used by the ISR to determine if a context switch may be required following\r
525  * the ISR.\r
526  *\r
527  * Example usage:\r
528  <pre>\r
529  // A co-routine that blocks on a queue waiting for characters to be received.\r
530  static void vReceivingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )\r
531  {\r
532  char cRxedChar;\r
533  BaseType_t xResult;\r
534 \r
535      // All co-routines must start with a call to crSTART().\r
536      crSTART( xHandle );\r
537 \r
538      for( ;; )\r
539      {\r
540          // Wait for data to become available on the queue.  This assumes the\r
541          // queue xCommsRxQueue has already been created!\r
542          crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );\r
543 \r
544          // Was a character received?\r
545          if( xResult == pdPASS )\r
546          {\r
547              // Process the character here.\r
548          }\r
549      }\r
550 \r
551      // All co-routines must end with a call to crEND().\r
552      crEND();\r
553  }\r
554 \r
555  // An ISR that uses a queue to send characters received on a serial port to\r
556  // a co-routine.\r
557  void vUART_ISR( void )\r
558  {\r
559  char cRxedChar;\r
560  BaseType_t xCRWokenByPost = pdFALSE;\r
561 \r
562      // We loop around reading characters until there are none left in the UART.\r
563      while( UART_RX_REG_NOT_EMPTY() )\r
564      {\r
565          // Obtain the character from the UART.\r
566          cRxedChar = UART_RX_REG;\r
567 \r
568          // Post the character onto a queue.  xCRWokenByPost will be pdFALSE\r
569          // the first time around the loop.  If the post causes a co-routine\r
570          // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.\r
571          // In this manner we can ensure that if more than one co-routine is\r
572          // blocked on the queue only one is woken by this ISR no matter how\r
573          // many characters are posted to the queue.\r
574          xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );\r
575      }\r
576  }</pre>\r
577  * \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR\r
578  * \ingroup Tasks\r
579  */\r
580 #define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) )\r
581 \r
582 \r
583 /**\r
584  * croutine. h\r
585  * <pre>\r
586   crQUEUE_SEND_FROM_ISR(\r
587                             QueueHandle_t pxQueue,\r
588                             void *pvBuffer,\r
589                             BaseType_t * pxCoRoutineWoken\r
590                        )</pre>\r
591  *\r
592  * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the\r
593  * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()\r
594  * functions used by tasks.\r
595  *\r
596  * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to\r
597  * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and\r
598  * xQueueReceiveFromISR() can only be used to pass data between a task and and\r
599  * ISR.\r
600  *\r
601  * crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data\r
602  * from a queue that is being used from within a co-routine (a co-routine\r
603  * posted to the queue).\r
604  *\r
605  * See the co-routine section of the WEB documentation for information on\r
606  * passing data between tasks and co-routines and between ISR's and\r
607  * co-routines.\r
608  *\r
609  * @param xQueue The handle to the queue on which the item is to be posted.\r
610  *\r
611  * @param pvBuffer A pointer to a buffer into which the received item will be\r
612  * placed.  The size of the items the queue will hold was defined when the\r
613  * queue was created, so this many bytes will be copied from the queue into\r
614  * pvBuffer.\r
615  *\r
616  * @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become\r
617  * available on the queue.  If crQUEUE_RECEIVE_FROM_ISR causes such a\r
618  * co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise\r
619  * *pxCoRoutineWoken will remain unchanged.\r
620  *\r
621  * @return pdTRUE an item was successfully received from the queue, otherwise\r
622  * pdFALSE.\r
623  *\r
624  * Example usage:\r
625  <pre>\r
626  // A co-routine that posts a character to a queue then blocks for a fixed\r
627  // period.  The character is incremented each time.\r
628  static void vSendingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )\r
629  {\r
630  // cChar holds its value while this co-routine is blocked and must therefore\r
631  // be declared static.\r
632  static char cCharToTx = 'a';\r
633  BaseType_t xResult;\r
634 \r
635      // All co-routines must start with a call to crSTART().\r
636      crSTART( xHandle );\r
637 \r
638      for( ;; )\r
639      {\r
640          // Send the next character to the queue.\r
641          crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );\r
642 \r
643          if( xResult == pdPASS )\r
644          {\r
645              // The character was successfully posted to the queue.\r
646          }\r
647                  else\r
648                  {\r
649                         // Could not post the character to the queue.\r
650                  }\r
651 \r
652          // Enable the UART Tx interrupt to cause an interrupt in this\r
653                  // hypothetical UART.  The interrupt will obtain the character\r
654                  // from the queue and send it.\r
655                  ENABLE_RX_INTERRUPT();\r
656 \r
657                  // Increment to the next character then block for a fixed period.\r
658                  // cCharToTx will maintain its value across the delay as it is\r
659                  // declared static.\r
660                  cCharToTx++;\r
661                  if( cCharToTx > 'x' )\r
662                  {\r
663                         cCharToTx = 'a';\r
664                  }\r
665                  crDELAY( 100 );\r
666      }\r
667 \r
668      // All co-routines must end with a call to crEND().\r
669      crEND();\r
670  }\r
671 \r
672  // An ISR that uses a queue to receive characters to send on a UART.\r
673  void vUART_ISR( void )\r
674  {\r
675  char cCharToTx;\r
676  BaseType_t xCRWokenByPost = pdFALSE;\r
677 \r
678      while( UART_TX_REG_EMPTY() )\r
679      {\r
680          // Are there any characters in the queue waiting to be sent?\r
681                  // xCRWokenByPost will automatically be set to pdTRUE if a co-routine\r
682                  // is woken by the post - ensuring that only a single co-routine is\r
683                  // woken no matter how many times we go around this loop.\r
684          if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )\r
685                  {\r
686                          SEND_CHARACTER( cCharToTx );\r
687                  }\r
688      }\r
689  }</pre>\r
690  * \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR\r
691  * \ingroup Tasks\r
692  */\r
693 #define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) )\r
694 \r
695 /*\r
696  * This function is intended for internal use by the co-routine macros only.\r
697  * The macro nature of the co-routine implementation requires that the\r
698  * prototype appears here.  The function should not be used by application\r
699  * writers.\r
700  *\r
701  * Removes the current co-routine from its ready list and places it in the\r
702  * appropriate delayed list.\r
703  */\r
704 void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList );\r
705 \r
706 /*\r
707  * This function is intended for internal use by the queue implementation only.\r
708  * The function should not be used by application writers.\r
709  *\r
710  * Removes the highest priority co-routine from the event list and places it in\r
711  * the pending ready list.\r
712  */\r
713 BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList );\r
714 \r
715 #ifdef __cplusplus\r
716 }\r
717 #endif\r
718 \r
719 #endif /* CO_ROUTINE_H */\r