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