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