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