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