/* * FreeRTOS V202212.00 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * https://www.FreeRTOS.org * https://github.com/FreeRTOS * */ /* * This demo file demonstrates how to send data between an ISR and a * co-routine. A tick hook function is used to periodically pass data between * the RTOS tick and a set of 'hook' co-routines. * * hookNUM_HOOK_CO_ROUTINES co-routines are created. Each co-routine blocks * to wait for a character to be received on a queue from the tick ISR, checks * to ensure the character received was that expected, then sends the number * back to the tick ISR on a different queue. * * The tick ISR checks the numbers received back from the 'hook' co-routines * matches the number previously sent. * * If at any time a queue function returns unexpectedly, or an incorrect value * is received either by the tick hook or a co-routine then an error is * latched. * * This demo relies on each 'hook' co-routine to execute between each * hookTICK_CALLS_BEFORE_POST tick interrupts. This and the heavy use of * queues from within an interrupt may result in an error being detected on * slower targets simply due to timing. */ /* Scheduler includes. */ #include "FreeRTOS.h" #include "croutine.h" #include "queue.h" /* Demo application includes. */ #include "crhook.h" /* The number of 'hook' co-routines that are to be created. */ #define hookNUM_HOOK_CO_ROUTINES ( 4 ) /* The number of times the tick hook should be called before a character is * posted to the 'hook' co-routines. */ #define hookTICK_CALLS_BEFORE_POST ( 500 ) /* There should never be more than one item in any queue at any time. */ #define hookHOOK_QUEUE_LENGTH ( 1 ) /* Don't block when initially posting to the queue. */ #define hookNO_BLOCK_TIME ( 0 ) /* The priority relative to other co-routines (rather than tasks) that the * 'hook' co-routines should take. */ #define mainHOOK_CR_PRIORITY ( 1 ) /*-----------------------------------------------------------*/ #if ( configUSE_CO_ROUTINES == 1 ) /* * The co-routine function itself. */ static void prvHookCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ); /* * The tick hook function. This receives a number from each 'hook' co-routine * then sends a number to each co-routine. An error is flagged if a send or * receive fails, or an unexpected number is received. */ void vApplicationTickHook( void ); /*-----------------------------------------------------------*/ /* Queues used to send data FROM a co-routine TO the tick hook function. * The hook functions received (Rx's) on these queues. One queue per * 'hook' co-routine. */ static QueueHandle_t xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ]; /* Queues used to send data FROM the tick hook TO a co-routine function. * The hood function transmits (Tx's) on these queues. One queue per * 'hook' co-routine. */ static QueueHandle_t xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ]; /* Set to true if an error is detected at any time. */ static BaseType_t xCoRoutineErrorDetected = pdFALSE; /*-----------------------------------------------------------*/ void vStartHookCoRoutines( void ) { UBaseType_t uxIndex, uxValueToPost = 0; for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ ) { /* Create a queue to transmit to and receive from each 'hook' * co-routine. */ xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) ); xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) ); /* To start things off the tick hook function expects the queue it * uses to receive data to contain a value. */ xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME ); /* Create the 'hook' co-routine itself. */ xCoRoutineCreate( prvHookCoRoutine, mainHOOK_CR_PRIORITY, uxIndex ); } } /*-----------------------------------------------------------*/ static UBaseType_t uxCallCounter = 0, uxNumberToPost = 0; void vApplicationTickHook( void ) { UBaseType_t uxReceivedNumber; BaseType_t xIndex, xCoRoutineWoken; /* Is it time to talk to the 'hook' co-routines again? */ uxCallCounter++; if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST ) { uxCallCounter = 0; for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ ) { xCoRoutineWoken = pdFALSE; if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS ) { /* There is no reason why we would not expect the queue to * contain a value. */ xCoRoutineErrorDetected = pdTRUE; } else { /* Each queue used to receive data from the 'hook' co-routines * should contain the number we last posted to the same co-routine. */ if( uxReceivedNumber != uxNumberToPost ) { xCoRoutineErrorDetected = pdTRUE; } /* Nothing should be blocked waiting to post to the queue. */ if( xCoRoutineWoken != pdFALSE ) { xCoRoutineErrorDetected = pdTRUE; } } } /* Start the next cycle by posting the next number onto each Tx queue. */ uxNumberToPost++; for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ ) { if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE ) { /* Posting to the queue should have woken the co-routine that * was blocked on the queue. */ xCoRoutineErrorDetected = pdTRUE; } } } } /*-----------------------------------------------------------*/ static void prvHookCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) { static UBaseType_t uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ]; BaseType_t xResult; /* Each co-routine MUST start with a call to crSTART(); */ crSTART( xHandle ); for( ; ; ) { /* Wait to receive a value from the tick hook. */ xResult = pdFAIL; crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult ); /* There is no reason why we should not have received something on * the queue. */ if( xResult != pdPASS ) { xCoRoutineErrorDetected = pdTRUE; } /* Send the same number back to the idle hook so it can verify it. */ xResult = pdFAIL; crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult ); if( xResult != pdPASS ) { /* There is no reason why we should not have been able to post to * the queue. */ xCoRoutineErrorDetected = pdTRUE; } } /* Each co-routine MUST end with a call to crEND(). */ crEND(); } /*-----------------------------------------------------------*/ BaseType_t xAreHookCoRoutinesStillRunning( void ) { if( xCoRoutineErrorDetected ) { return pdFALSE; } else { return pdTRUE; } } #endif /* if ( configUSE_CO_ROUTINES == 1 ) */