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