static void prvRecursiveMutexPollingTask( void *pvParameters ) { /* Just to remove compiler warning. */ ( void ) pvParameters; for( ;; ) { /* Keep attempting to obtain the mutex. We should only obtain it when the blocking task has suspended itself, which in turn should only happen when the controlling task is also suspended. */ if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS ) { /* Is the blocking task suspended? */ if( ( xBlockingIsSuspended != pdTRUE ) || ( xControllingIsSuspended != pdTRUE ) ) { xErrorOccurred = pdTRUE; } else { /* Keep count of the number of cycles this task has performed so a stall can be detected. */ uxPollingCycles++; /* We can resume the other tasks here even though they have a higher priority than the polling task. When they execute they will attempt to obtain the mutex but fail because the polling task is still the mutex holder. The polling task (this task) will then inherit the higher priority. The Blocking task will block indefinitely when it attempts to obtain the mutex, the Controlling task will only block for a fixed period and an error will be latched if the polling task has not returned the mutex by the time this fixed period has expired. */ vTaskResume( xBlockingTaskHandle ); #if configUSE_PREEMPTION == 0 taskYIELD(); #endif vTaskResume( xControllingTaskHandle ); #if configUSE_PREEMPTION == 0 taskYIELD(); #endif /* The other two tasks should now have executed and no longer be suspended. */ if( ( xBlockingIsSuspended == pdTRUE ) || ( xControllingIsSuspended == pdTRUE ) ) { xErrorOccurred = pdTRUE; } /* Release the mutex, disinheriting the higher priority again. */ if( xSemaphoreGiveRecursive( xMutex ) != pdPASS ) { xErrorOccurred = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif } } #if configUSE_PREEMPTION == 0 { taskYIELD(); } #endif } }
signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) { signed portBASE_TYPE xReturn; xTimeOutType xTimeOut; /* This function is very similar to xQueueSend(). See comments within xQueueSend() for a more detailed explanation. Make sure other tasks do not access the queue. */ vTaskSuspendAll(); /* Capture the current time status for future reference. */ vTaskSetTimeOutState( &xTimeOut ); /* Make sure interrupts do not access the queue. */ prvLockQueue( pxQueue ); do { /* If there are no messages in the queue we may have to block. */ if( prvIsQueueEmpty( pxQueue ) ) { /* There are no messages in the queue, do we want to block or just leave with nothing? */ if( xTicksToWait > ( portTickType ) 0 ) { vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); taskENTER_CRITICAL(); { prvUnlockQueue( pxQueue ); if( !xTaskResumeAll() ) { taskYIELD(); } vTaskSuspendAll(); prvLockQueue( pxQueue ); } taskEXIT_CRITICAL(); } } taskENTER_CRITICAL(); { if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { pxQueue->pcReadFrom += pxQueue->uxItemSize; if( pxQueue->pcReadFrom >= pxQueue->pcTail ) { pxQueue->pcReadFrom = pxQueue->pcHead; } --( pxQueue->uxMessagesWaiting ); memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); /* Increment the lock count so prvUnlockQueue knows to check for tasks waiting for space to become available on the queue. */ ++( pxQueue->xRxLock ); xReturn = pdPASS; } else { xReturn = errQUEUE_EMPTY; } } taskEXIT_CRITICAL(); if( xReturn == errQUEUE_EMPTY ) { if( xTicksToWait > 0 ) { if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { xReturn = queueERRONEOUS_UNBLOCK; } } } } while( xReturn == queueERRONEOUS_UNBLOCK ); /* We no longer require exclusive access to the queue. */ prvUnlockQueue( pxQueue ); xTaskResumeAll(); return xReturn; }
/** * @brief Mutex Low Priority Thread. * @param argument: Not used * @retval None */ static void MutexLowPriorityThread(void const *argument) { /* Just to remove compiler warning */ (void) argument; for (;;) { /* Keep attempting to obtain the mutex. We should only obtain it when the medium-priority thread has suspended itself, which in turn should only happen when the high-priority thread is also suspended */ if (osMutexWait(osMutex, mutexNO_DELAY) == osOK) { /* Is the haigh and medium-priority threads suspended? */ if ((osThreadGetState(osHighPriorityThreadHandle) != osThreadSuspended) || (osThreadGetState(osMediumPriorityThreadHandle) != osThreadSuspended)) { /* Toggle LED3 to indicate error */ BSP_LED_Toggle(LED3); } else { /* Keep count of the number of cycles this task has performed so a stall can be detected */ LowPriorityThreadCycles++; BSP_LED_Toggle(LED4); /* We can resume the other tasks here even though they have a higher priority than the this thread. When they execute they will attempt to obtain the mutex but fail because the low-priority thread is still the mutex holder. this thread will then inherit the higher priority. The medium-priority thread will block indefinitely when it attempts to obtain the mutex, the high-priority thread will only block for a fixed period and an error will be latched if the high-priority thread has not returned the mutex by the time this fixed period has expired */ osThreadResume(osMediumPriorityThreadHandle); osThreadResume(osHighPriorityThreadHandle); /* The other two tasks should now have executed and no longer be suspended */ if ((osThreadGetState(osHighPriorityThreadHandle) == osThreadSuspended) || (osThreadGetState(osMediumPriorityThreadHandle) == osThreadSuspended)) { /* Toggle LED3 to indicate error */ BSP_LED_Toggle(LED3); } /* Release the mutex, disinheriting the higher priority again */ if (osMutexRelease(osMutex) != osOK) { /* Toggle LED3 to indicate error */ BSP_LED_Toggle(LED3); } } } #if configUSE_PREEMPTION == 0 { taskYIELD(); } #endif } }
static void prvSendFrontAndBackTest( void *pvParameters ) { unsigned portLONG ulData, ulData2; xQueueHandle xQueue; #ifdef USE_STDIO void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend ); const portCHAR * const pcTaskStartMsg = "Alt queue SendToFront/SendToBack/Peek test started.\r\n"; /* Queue a message for printing to say the task has started. */ vPrintDisplayMessage( &pcTaskStartMsg ); #endif xQueue = ( xQueueHandle ) pvParameters; for( ;; ) { /* The queue is empty, so sending an item to the back of the queue should have the same efect as sending it to the front of the queue. First send to the front and check everything is as expected. */ xQueueAltSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK ); if( uxQueueMessagesWaiting( xQueue ) != 1 ) { xErrorDetected = pdTRUE; } if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } /* The data we sent to the queue should equal the data we just received from the queue. */ if( ulLoopCounter != ulData ) { xErrorDetected = pdTRUE; } /* Then do the same, sending the data to the back, checking everything is as expected. */ if( uxQueueMessagesWaiting( xQueue ) != 0 ) { xErrorDetected = pdTRUE; } xQueueAltSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK ); if( uxQueueMessagesWaiting( xQueue ) != 1 ) { xErrorDetected = pdTRUE; } if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } if( uxQueueMessagesWaiting( xQueue ) != 0 ) { xErrorDetected = pdTRUE; } /* The data we sent to the queue should equal the data we just received from the queue. */ if( ulLoopCounter != ulData ) { xErrorDetected = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */ for( ulData = 2; ulData < 5; ulData++ ) { xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ); } /* Now the order in the queue should be 2, 3, 4, with 2 being the first thing to be read out. Now add 1 then 0 to the front of the queue. */ if( uxQueueMessagesWaiting( xQueue ) != 3 ) { xErrorDetected = pdTRUE; } ulData = 1; xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ); ulData = 0; xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ); /* Now the queue should be full, and when we read the data out we should receive 0, 1, 2, 3, 4. */ if( uxQueueMessagesWaiting( xQueue ) != 5 ) { xErrorDetected = pdTRUE; } if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) { xErrorDetected = pdTRUE; } if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) { xErrorDetected = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif /* Check the data we read out is in the expected order. */ for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ ) { /* Try peeking the data first. */ if( xQueueAltPeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } if( ulData != ulData2 ) { xErrorDetected = pdTRUE; } /* Now try receiving the data for real. The value should be the same. Clobber the value first so we know we really received it. */ ulData2 = ~ulData2; if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } if( ulData != ulData2 ) { xErrorDetected = pdTRUE; } } /* The queue should now be empty again. */ if( uxQueueMessagesWaiting( xQueue ) != 0 ) { xErrorDetected = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif /* Our queue is empty once more, add 10, 11 to the back. */ ulData = 10; if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } ulData = 11; if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } if( uxQueueMessagesWaiting( xQueue ) != 2 ) { xErrorDetected = pdTRUE; } /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the front. */ for( ulData = 9; ulData >= 7; ulData-- ) { if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } } /* Now check that the queue is full, and that receiving data provides the expected sequence of 7, 8, 9, 10, 11. */ if( uxQueueMessagesWaiting( xQueue ) != 5 ) { xErrorDetected = pdTRUE; } if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) { xErrorDetected = pdTRUE; } if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) { xErrorDetected = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif /* Check the data we read out is in the expected order. */ for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ ) { if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } if( ulData != ulData2 ) { xErrorDetected = pdTRUE; } } if( uxQueueMessagesWaiting( xQueue ) != 0 ) { xErrorDetected = pdTRUE; } ulLoopCounter++; } }
static portTASK_FUNCTION( prvSemaphoreTest, pvParameters ) { xSemaphoreParameters *pxParameters; volatile uint32_t *pulSharedVariable, ulExpectedValue; uint32_t ulCounter; short sError = pdFALSE, sCheckVariableToUse; /* See which check variable to use. sNextCheckVariable is not semaphore protected! */ portENTER_CRITICAL(); sCheckVariableToUse = sNextCheckVariable; sNextCheckVariable++; portEXIT_CRITICAL(); /* A structure is passed in as the parameter. This contains the shared variable being guarded. */ pxParameters = ( xSemaphoreParameters * ) pvParameters; pulSharedVariable = pxParameters->pulSharedVariable; /* If we are blocking we use a much higher count to ensure loads of context switches occur during the count. */ if( pxParameters->xBlockTime > ( TickType_t ) 0 ) { ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE; } else { ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE; } for( ;; ) { /* Try to obtain the semaphore. */ if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS ) { /* We have the semaphore and so expect any other tasks using the shared variable to have left it in the state we expect to find it. */ if( *pulSharedVariable != ulExpectedValue ) { sError = pdTRUE; } /* Clear the variable, then count it back up to the expected value before releasing the semaphore. Would expect a context switch or two during this time. */ for( ulCounter = ( uint32_t ) 0; ulCounter <= ulExpectedValue; ulCounter++ ) { *pulSharedVariable = ulCounter; if( *pulSharedVariable != ulCounter ) { sError = pdTRUE; } } /* Release the semaphore, and if no errors have occurred increment the check variable. */ if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE ) { sError = pdTRUE; } if( sError == pdFALSE ) { if( sCheckVariableToUse < semtstNUM_TASKS ) { ( sCheckVariables[ sCheckVariableToUse ] )++; } } /* If we have a block time then we are running at a priority higher than the idle priority. This task takes a long time to complete a cycle (deliberately so to test the guarding) so will be starving out lower priority tasks. Block for some time to allow give lower priority tasks some processor time. */ vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR ); } else { if( pxParameters->xBlockTime == ( TickType_t ) 0 ) { /* We have not got the semaphore yet, so no point using the processor. We are not blocking when attempting to obtain the semaphore. */ taskYIELD(); } } } }
static void vPrimaryBlockTimeTestTask( void *pvParameters ) { portBASE_TYPE xItem, xData; TickType_t xTimeWhenBlocking; TickType_t xTimeToBlock, xBlockedTime; ( void ) pvParameters; for( ;; ) { /********************************************************************* Test 1 Simple block time wakeup test on queue receives. */ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) { /* The queue is empty. Attempt to read from the queue using a block time. When we wake, ensure the delta in time is as expected. */ xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem ); xTimeWhenBlocking = xTaskGetTickCount(); /* We should unblock after xTimeToBlock having not received anything on the queue. */ if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY ) { xErrorOccurred = pdTRUE; } /* How long were we blocked for? */ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; if( xBlockedTime < xTimeToBlock ) { /* Should not have blocked for less than we requested. */ xErrorOccurred = pdTRUE; } if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) ) { /* Should not have blocked for longer than we requested, although we would not necessarily run as soon as we were unblocked so a margin is allowed. */ xErrorOccurred = pdTRUE; } } /********************************************************************* Test 2 Simple block time wakeup test on queue sends. First fill the queue. It should be empty so all sends should pass. */ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) { if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS ) { xErrorOccurred = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif } for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) { /* The queue is full. Attempt to write to the queue using a block time. When we wake, ensure the delta in time is as expected. */ xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem ); xTimeWhenBlocking = xTaskGetTickCount(); /* We should unblock after xTimeToBlock having not received anything on the queue. */ if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL ) { xErrorOccurred = pdTRUE; } /* How long were we blocked for? */ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; if( xBlockedTime < xTimeToBlock ) { /* Should not have blocked for less than we requested. */ xErrorOccurred = pdTRUE; } if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) ) { /* Should not have blocked for longer than we requested, although we would not necessarily run as soon as we were unblocked so a margin is allowed. */ xErrorOccurred = pdTRUE; } } /********************************************************************* Test 3 Wake the other task, it will block attempting to post to the queue. When we read from the queue the other task will wake, but before it can run we will post to the queue again. When the other task runs it will find the queue still full, even though it was woken. It should recognise that its block time has not expired and return to block for the remains of its block time. Wake the other task so it blocks attempting to post to the already full queue. */ xRunIndicator = 0; vTaskResume( xSecondary ); /* We need to wait a little to ensure the other task executes. */ while( xRunIndicator != bktRUN_INDICATOR ) { /* The other task has not yet executed. */ vTaskDelay( bktSHORT_WAIT ); } /* Make sure the other task is blocked on the queue. */ vTaskDelay( bktSHORT_WAIT ); xRunIndicator = 0; for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) { /* Now when we make space on the queue the other task should wake but not execute as this task has higher priority. */ if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) { xErrorOccurred = pdTRUE; } /* Now fill the queue again before the other task gets a chance to execute. If the other task had executed we would find the queue full ourselves, and the other task have set xRunIndicator. */ if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS ) { xErrorOccurred = pdTRUE; } if( xRunIndicator == bktRUN_INDICATOR ) { /* The other task should not have executed. */ xErrorOccurred = pdTRUE; } /* Raise the priority of the other task so it executes and blocks on the queue again. */ vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 ); /* The other task should now have re-blocked without exiting the queue function. */ if( xRunIndicator == bktRUN_INDICATOR ) { /* The other task should not have executed outside of the queue function. */ xErrorOccurred = pdTRUE; } /* Set the priority back down. */ vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY ); } /* Let the other task timeout. When it unblockes it will check that it unblocked at the correct time, then suspend itself. */ while( xRunIndicator != bktRUN_INDICATOR ) { vTaskDelay( bktSHORT_WAIT ); } vTaskDelay( bktSHORT_WAIT ); xRunIndicator = 0; /********************************************************************* Test 4 As per test 3 - but with the send and receive the other way around. The other task blocks attempting to read from the queue. Empty the queue. We should find that it is full. */ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) { if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) { xErrorOccurred = pdTRUE; } } /* Wake the other task so it blocks attempting to read from the already empty queue. */ vTaskResume( xSecondary ); /* We need to wait a little to ensure the other task executes. */ while( xRunIndicator != bktRUN_INDICATOR ) { vTaskDelay( bktSHORT_WAIT ); } vTaskDelay( bktSHORT_WAIT ); xRunIndicator = 0; for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) { /* Now when we place an item on the queue the other task should wake but not execute as this task has higher priority. */ if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS ) { xErrorOccurred = pdTRUE; } /* Now empty the queue again before the other task gets a chance to execute. If the other task had executed we would find the queue empty ourselves, and the other task would be suspended. */ if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) { xErrorOccurred = pdTRUE; } if( xRunIndicator == bktRUN_INDICATOR ) { /* The other task should not have executed. */ xErrorOccurred = pdTRUE; } /* Raise the priority of the other task so it executes and blocks on the queue again. */ vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 ); /* The other task should now have re-blocked without exiting the queue function. */ if( xRunIndicator == bktRUN_INDICATOR ) { /* The other task should not have executed outside of the queue function. */ xErrorOccurred = pdTRUE; } vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY ); } /* Let the other task timeout. When it unblockes it will check that it unblocked at the correct time, then suspend itself. */ while( xRunIndicator != bktRUN_INDICATOR ) { vTaskDelay( bktSHORT_WAIT ); } vTaskDelay( bktSHORT_WAIT ); xPrimaryCycles++; } }
//------------------------------------------------------------------------------------ size_t FF_fwrite( const void *pvBuffer, size_t xSize) { // El archivo es del tipo circular FirstIN-LastOUT. // Escribe un registro en la posicion apuntada por el HEAD. // El registro que se pasa en pvBuffer es del tipo 'frameData_t' de 38 bytes // pero en la memoria voy a escribir de a paginas de 64 bytes. // Retorna el nro.de bytes escritos y setea la variable 'errno' del FCB // En la posicion 63 grabo un tag con el valor 0xC5 para poder luego // determinar si el registro esta ocupado o vacio. // TESTING: // Memoria vacia: OK // Memoria llena: OK // Memoria con HEAD(10) > TAIL(4), Free(10) OK // Memoria con HEAD(3) < TAIL(8), Free(5) OK // Condicion de borde 1: HEAD(15), TAIL(0), Free(1) OK // Condicion de borde 2: HEAD(0), TAIL(1), Free(1) OK u16 val = 0; size_t xReturn = 0U; u16 tryes; // Lo primero es obtener el semaforo del I2C FreeRTOS_ioctl(&pdI2C,ioctlOBTAIN_BUS_SEMPH, NULL); FCB.ff_stat.errno = pdFF_ERRNO_NONE; // Si la memoria esta llena no puedo escribir: salgo if ( FCB.ff_stat.rcdsFree == 0 ) { FCB.ff_stat.errno = pdFF_ERRNO_MEMFULL; goto quit; } // inicializo la estructura lineal temporal en el FCB para copiar ahi los datos y // calcular el checksum antes de grabarlo en memoria. memset( FCB.ff_buffer,0, sizeof(FCB.ff_buffer) ); // copio los datos recibidos del frame al buffer ( 0..(xSize-1)) memcpy ( FCB.ff_buffer, pvBuffer, xSize ); // Calculo y grabo el checksum a continuacion del frame (en la pos.xSize) // El checksum es solo del dataFrame por eso paso dicho size. FCB.ff_buffer[xSize] = pv_memChecksum(FCB.ff_buffer, xSize ); // Grabo el tag para indicar que el registro esta escrito. FCB.ff_buffer[sizeof(FCB.ff_buffer) - 1] = FF_WRTAG; // EE WRITE: // Luego indicamos el periferico i2c en el cual queremos leer val = EE_ADDR; FreeRTOS_ioctl(&pdI2C,ioctl_I2C_SET_DEVADDRESS, &val); // Luego indicamos la direccion a escribir del dispositivo: largo ( en la ee son 2 bytes ) val = 2; FreeRTOS_ioctl(&pdI2C,ioctl_I2C_SET_BYTEADDRESSLENGTH, &val); // y direccion interna en la EE.(comienzo del registro / frontera) val = FF_ADDR_START + FCB.ff_stat.HEAD * FF_RECD_SIZE; FreeRTOS_ioctl(&pdI2C,ioctl_I2C_SET_BYTEADDRESS,&val); // Por ultimo escribo la memoria. Escribo un pagina entera, 64 bytes. // Reintento hasta 3 veces. for ( tryes = 0; tryes < 3; tryes++ ) { // Write xReturn = FreeRTOS_write(&pdI2C, &FCB.ff_buffer, FF_RECD_SIZE); taskYIELD(); // Verify FreeRTOS_read(&pdI2C, &FCB.check_buffer, FF_RECD_SIZE); if ( memcmp (&FCB.check_buffer, &FCB.ff_buffer, FF_RECD_SIZE) == 0 ) break; if ( tryes == 3 ) { snprintf_P( debug_printfBuff,sizeof(debug_printfBuff),PSTR("FS WR ERR: [%d]\r\n\0"), val); FreeRTOS_write( &pdUART1, debug_printfBuff, sizeof(debug_printfBuff) ); FCB.ff_stat.errno = pdFF_ERRNO_MEMWR; xReturn = 0U; goto quit; } } if (xReturn != FF_RECD_SIZE ) { // Errores de escritura ? FCB.ff_stat.errno = pdFF_ERRNO_MEMWR; xReturn = 0U; goto quit; } else { xReturn = xSize; // Avanzo el puntero de WR en modo circular FCB.ff_stat.HEAD = (++FCB.ff_stat.HEAD == FF_MAX_RCDS) ? 0 : FCB.ff_stat.HEAD; FCB.ff_stat.rcdsFree--; } quit: // libero los semaforos FreeRTOS_ioctl(&pdI2C,ioctlRELEASE_BUS_SEMPH, NULL); return(xReturn); }
static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ) { /* Take the mutex. It should be available now. */ if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } /* Set the guarded variable to a known start value. */ ulGuardedVariable = 0; /* This task's priority should be as per that assigned when the task was created. */ if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) { xErrorDetected = pdTRUE; } /* Now unsuspend the high priority task. This will attempt to take the mutex, and block when it finds it cannot obtain it. */ vTaskResume( xHighPriorityMutexTask ); #if configUSE_PREEMPTION == 0 taskYIELD(); #endif /* Ensure the task is reporting its priority as blocked and not suspended (as it would have done in versions up to V7.5.3). */ #if( INCLUDE_eTaskGetState == 1 ) { configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked ); } #endif /* INCLUDE_eTaskGetState */ /* The priority of the high priority task should now have been inherited as by now it will have attempted to get the mutex. */ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) { xErrorDetected = pdTRUE; } /* Now unsuspend the medium priority task. This should not run as the inherited priority of this task is above that of the medium priority task. */ vTaskResume( xMediumPriorityMutexTask ); /* If the medium priority task did run then it will have incremented the guarded variable. */ if( ulGuardedVariable != 0 ) { xErrorDetected = pdTRUE; } /* Take the local mutex too, so two mutexes are now held. */ if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } /* When the local semaphore is given back the priority of this task should not yet be disinherited because the shared mutex is still held. This is a simplification to allow FreeRTOS to be integrated with middleware that attempts to hold multiple mutexes without bloating the code with complex algorithms. It is possible that the high priority mutex task will execute as it shares a priority with this task. */ if( xSemaphoreGive( xLocalMutex ) != pdPASS ) { xErrorDetected = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif /* The guarded variable is only incremented by the medium priority task, which still should not have executed as this task should remain at the higher priority, ensure this is the case. */ if( ulGuardedVariable != 0 ) { xErrorDetected = pdTRUE; } if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) { xErrorDetected = pdTRUE; } /* Now also give back the shared mutex, taking the held count back to 0. This time the priority of this task should be disinherited back to the priority at which it was created. This means the medium priority task should execute and increment the guarded variable. When this task next runs both the high and medium priority tasks will have been suspended again. */ if( xSemaphoreGive( xMutex ) != pdPASS ) { xErrorDetected = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif /* Check the guarded variable did indeed increment... */ if( ulGuardedVariable != 1 ) { xErrorDetected = pdTRUE; } /* ... and that the priority of this task has been disinherited to genqMUTEX_LOW_PRIORITY. */ if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) { xErrorDetected = pdTRUE; } }
/*FUNCTION********************************************************************** * * Function Name : OSA_TaskYield * Description : When a task calls this function, it will give up CPU and put * itself to the tail of ready list. * *END**************************************************************************/ osa_status_t OSA_TaskYield(void) { taskYIELD(); return kStatus_OSA_Success; }
portBASE_TYPE xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort ) { xListItem *pxListItem; portBASE_TYPE xReturn = pdPASS; xFreeRTOS_Socket_t *pxSocket; portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; vTaskSuspendAll(); { /* See if there is a list item associated with the port number on the list of bound sockets. */ pxListItem = pxListFindListItemWithValue( &xBoundSocketsList, ( portTickType ) usPort ); } xTaskResumeAll(); if( pxListItem != NULL ) { /* The owner of the list item is the socket itself. */ pxSocket = ( xFreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem ); vTaskSuspendAll(); { #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) { /* Is the socket a member of a select() group? */ if( pxSocket->xSelectQueue != NULL ) { /* Can the select group be notified that the socket is ready to be read? */ if( xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, &xHigherPriorityTaskWoken ) != pdPASS ) { /* Could not notify the select group. */ xReturn = pdFAIL; iptraceFAILED_TO_NOTIFY_SELECT_GROUP( pxSocket ); } } } #endif if( xReturn == pdPASS ) { taskENTER_CRITICAL(); { /* Add the network packet to the list of packets to be processed by the socket. */ vListInsertEnd( &( pxSocket->xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) ); } taskEXIT_CRITICAL(); /* The socket's counting semaphore records how many packets are waiting to be processed by the socket. */ xSemaphoreGiveFromISR( pxSocket->xWaitingPacketSemaphore, &xHigherPriorityTaskWoken ); } } if( xTaskResumeAll() == pdFALSE ) { if( xHigherPriorityTaskWoken != pdFALSE ) { taskYIELD(); } } } else { xReturn = pdFAIL; } return xReturn; }
/*--------------------------------------------------------------------------------------- Name: osal_task_yield Purpose: Forces a context switch. Parameters: void Returns void ---------------------------------------------------------------------------------------*/ void osal_task_yield( void ) { taskYIELD(); }
void vCheckTask(void *pvParameters) { char buf[50]; char pcBrewElapsedTime[50], pcStepElapsedTime[50]; char pcBrewElapsedHours[50], pcBrewElapsedMinutes[50], pcBrewElapsedSeconds[50], pcBrewStep[50]; char pcBrewStepElapsedHours[50], pcBrewStepElapsedMinutes[50], pcBrewStepElapsedSeconds[50], pcMashTemp[50], pcHLTTemp[50]; char pcChillerPumpState[50], pcBoilState[50], pcHeapRemaining[50], pcBrewState[50], pcBoilDuty[50], pcLitresDelivered[50]; int ii = 0; char upper_limit = 255, lower_limit = 255; unsigned int touch, hops, ds1820, timer, litres, check, low_level = 90, heap, print, serial, serialcontrol; unsigned int display_applet, stats_applet, res_applet, graph_applet, brew_task; static char cBuf[80]; for (;;){ touch = uxTaskGetStackHighWaterMark(xTouchTaskHandle); ds1820 = uxTaskGetStackHighWaterMark(xDS1820TaskHandle); timer = uxTaskGetStackHighWaterMark(xTimerSetupHandle); litres = uxTaskGetStackHighWaterMark(xLitresToBoilHandle); print = uxTaskGetStackHighWaterMark(xPrintTaskHandle); hops = uxTaskGetStackHighWaterMark(xHopsTaskHandle); check = uxTaskGetStackHighWaterMark(NULL); serial = uxTaskGetStackHighWaterMark(xSerialHandlerTaskHandle); serialcontrol = uxTaskGetStackHighWaterMark(xSerialControlTaskHandle); heap = xPortGetFreeHeapSize(); display_applet = uiGetBrewAppletDisplayHWM(); res_applet = uiGetBrewResAppletHWM(); stats_applet = uiGetBrewStatsAppletHWM(); graph_applet = uiGetBrewGraphAppletHWM(); brew_task = uiGetBrewTaskHWM(); sprintf(pcBrewElapsedHours, "4D51E338F02649DFA173631622024A90:%02u\r\n\0", ucGetBrewHoursElapsed()); vConsolePrint(pcBrewElapsedHours); vTaskDelay(80); sprintf(pcBrewElapsedMinutes, "99A2038A62BF47E7BFB1922A43C0825C:%02u\r\n\0", ucGetBrewMinutesElapsed()); vConsolePrint(pcBrewElapsedMinutes); vTaskDelay(80); sprintf(pcBrewElapsedSeconds, "E9C4FDDEDEBC41D7AC3A3F4C636759A2:%02u\r\n\0", ucGetBrewSecondsElapsed()); vConsolePrint(pcBrewElapsedSeconds); vTaskDelay(80); sprintf(pcBrewStep, "1308CA31CAEE4A9A8AC5B353F5ACB594:%02u\r\n\0", ucGetBrewStep()); vConsolePrint(pcBrewStep); vTaskDelay(80); sprintf(pcBrewStepElapsedSeconds, "02BA9C74C1384C069ECB648C3CEFFCBA:%02u\r\n\0", ucGetBrewStepSecondsElapsed()); vConsolePrint(pcBrewStepElapsedSeconds); vTaskDelay(80); sprintf(pcBrewStepElapsedMinutes, "35C22A915227449C8F2A740F2C26B344:%02u\r\n\0", ucGetBrewStepMinutesElapsed()); vConsolePrint(pcBrewStepElapsedMinutes); vTaskDelay(80); sprintf(pcMashTemp, "E21DFC36AFB24226A323D7931B6A1F30:%02u\r\n\0", (unsigned int)floor(ds1820_get_temp(MASH))); vConsolePrint(pcMashTemp); vTaskDelay(50); sprintf(pcHLTTemp, "81A73894E64546868F39EE1758D459AD:%02u\r\n\0", (unsigned int)floor(ds1820_get_temp(HLT))); vConsolePrint(pcHLTTemp); vTaskDelay(50); sprintf(pcChillerPumpState, "461F715060F5468883F6F8500CEAA4BC:%02u\r\n\0", ucGetChillerPumpState()); vConsolePrint(pcChillerPumpState); vTaskDelay(80); sprintf(pcBoilState, "60140A1EB194439B8C9A198355FD93AA:%02u\r\n\0", ucGetBoilState()); vConsolePrint(pcBoilState); vTaskDelay(80); sprintf(pcBrewState, "FB46F7E5DF914AF1816035EC02DEE0DC:%02u\r\n\0", ucGetBrewState()); vConsolePrint(pcBrewState); vTaskDelay(80); sprintf(pcBoilDuty, "F066509116CA43F7B6845C8E2EBA69FA:%02u\r\n\0", uiGetBoilDuty()); vConsolePrint(pcBoilDuty); vTaskDelay(80); sprintf(pcLitresDelivered, "3AEE6966D7664AA4BE05BBBBF48E2836:%02u\r\n\0", uiGetActualLitresDelivered()); vConsolePrint(pcLitresDelivered); vTaskDelay(80); lower_limit = cI2cGetInput(CRANE_LOWER_LIMIT_PORT, CRANE_LOWER_LIMIT_PIN); upper_limit = cI2cGetInput(CRANE_UPPER_LIMIT_PORT, CRANE_UPPER_LIMIT_PIN); sprintf(buf, "BD52AA172CAE4F58A11EC35872EFEB99:%d \r \n", ii++%1024); sprintf(pcHeapRemaining, "*Heap:%u*low=%d,up=%d\r\n\0", heap, lower_limit, upper_limit); vConsolePrint(pcHeapRemaining); vTaskDelay(80); vConsolePrint(buf); if (touch < low_level || timer < low_level || litres < low_level|| print < low_level || hops < low_level || check < low_level|| display_applet < low_level || res_applet < low_level || stats_applet < low_level || graph_applet < low_level || brew_task < low_level) { //vTaskSuspendAll(); vConsolePrint("=============================\r\n"); sprintf(cBuf,"check task: idle ticks = %d\r\n", ulIdleCycleCount); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "touchwm = %d\r\n", touch); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "DS1820wm = %d\r\n", ds1820); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "TimerSetupwm = %d\r\n", timer); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "litreswm = %d\r\n", litres); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "hopswm = %d\r\n", hops); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "check = %d\r\n", check); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "serial = %d\r\n", serial); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "serialcontrol = %d\r\n", serialcontrol); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "brewtask = %d\r\n", brew_task); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "stats = %d\r\n", stats_applet); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "res = %d\r\n", res_applet); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "graph = %d\r\n", graph_applet); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "brew_display = %d\r\n", display_applet); vConsolePrint(cBuf); vTaskDelay(80); sprintf(cBuf, "print = %d\r\n", print); vConsolePrint(cBuf); vConsolePrint("=============================\r\n"); //xTaskResumeAll(); vTaskDelay(800); } vTaskDelay(800); taskYIELD(); } }
void CmdCheck() { #if MAX_UDP_SOCKETS_FREERTOS>0 //UDP Stack activeUdpSocket=0; while (activeUdpSocket < MAX_UDP_SOCKETS_FREERTOS) { //Ring Buffer if(udpSocket[activeUdpSocket] != INVALID_UDP_SOCKET) { //reads udp data and adds in ring buffer udpRxLen[activeUdpSocket] = UDPIsGetReady(udpSocket[activeUdpSocket]); if(udpRxLen[activeUdpSocket] > (BUFFER_UDP_LEN[activeUdpSocket] - udpRxLenGlobal[activeUdpSocket])) { // Since there is not enough space to store the packet, // discard all the transceiver RAM content related to UDP datadiscard = udpRxLen[activeUdpSocket]; // Set the Overflow Flags UDPoverflow = 1; UDPoverflowFlag[activeUdpSocket] = 1; // Now discard all remaining data in Udp Rx: // Create a dummy array BYTE removeArray[BUFFER_UDP_FIXED_LEN]; // update the datadiscard value while(datadiscard > 0) { datadiscard -= UDPGetArray(removeArray, BUFFER_UDP_FIXED_LEN); } } if (udpRxLen[activeUdpSocket] > 0) { if( (p_udp_wifiram[activeUdpSocket]+udpRxLen[activeUdpSocket]) <= (udpBuffer[activeUdpSocket]+BUFFER_UDP_LEN[activeUdpSocket]) ) //append to buffer { UDPGetArray(p_udp_wifiram[activeUdpSocket], udpRxLen[activeUdpSocket]); //data p_udp_wifiram[activeUdpSocket] += udpRxLen[activeUdpSocket]; } else //append to buffer near end, or add to buffer from start { tmp_len[activeUdpSocket] = ((udpBuffer[activeUdpSocket]+BUFFER_UDP_LEN[activeUdpSocket]) - p_udp_wifiram[activeUdpSocket]); //free space on ring buffer if(tmp_len[activeUdpSocket] > 0) //fill buffer and add data from start { UDPGetArray(p_udp_wifiram[activeUdpSocket], tmp_len[activeUdpSocket]); p_udp_wifiram[activeUdpSocket] = udpBuffer[activeUdpSocket]; UDPGetArray(p_udp_wifiram[activeUdpSocket], udpRxLen[activeUdpSocket] - tmp_len[activeUdpSocket] ); p_udp_wifiram[activeUdpSocket] += (udpRxLen[activeUdpSocket] - tmp_len[activeUdpSocket]); } else //add data to buffer from start { p_udp_wifiram[activeUdpSocket] = udpBuffer[activeUdpSocket]; UDPGetArray(p_udp_wifiram[activeUdpSocket], udpRxLen[activeUdpSocket]); p_udp_wifiram[activeUdpSocket] += udpRxLen[activeUdpSocket]; } } udpRxLenGlobal[activeUdpSocket] += udpRxLen[activeUdpSocket]; } //end ring buffer } activeUdpSocket++; } #endif //UDP STACK if (Cmd != 0) { int fresult = 0; while (xSemaphoreTake(xSemFrontEnd,0) != pdTRUE); if (xFrontEndStat == 1) { fresult = FP[Cmd](); xFrontEndStat = xFrontEndStatRet; xSemaphoreGive(xSemFrontEnd); Cmd = 0; taskYIELD(); } } }
void Task::yield() { taskYIELD(); }
/** * @brief Menu Task. * * This function allows the user to select which task to start: * Record a program or Play a program. * * On initial launch, the arm may be in an unknown state so the first * function called is used to reset the arm into a known position. * * Upon return to the menu task, from the record and play tasks, * the arm may be in an unknown position, so the reset task may * be called appropriately. * * @param [in] pvParameter Standard FreeRTOS method of passing parameters. * @return Void. */ void vTaskMenu( void *pvParameters ) { portSHORT sReceivedValue; portBASE_TYPE xKeyPadQueueStatus; const portTickType xTicksToWait = 1000 / portTICK_RATE_MS; enum xChoice_t {RECORD_A_PROGRAM, PLAY_A_PROGRAM} xChoice; portCHAR *pcChoices[] = { "Record a Program", "Play a Program" }; xChoice = RECORD_A_PROGRAM; printf("Menu\n"); if (xSystemState != MENU_SELECT) { vWaitForReset(); } vPrintToLCD(1,"Select Option:"); vPrintToLCD(2,pcChoices[xChoice]); for(;;) { if( uxQueueMessagesWaiting( xKeyPadQueue ) != 0) { printf( "Queue should have been empty!\r\n" ); } xKeyPadQueueStatus = xQueueReceive( xKeyPadQueue, &sReceivedValue, xTicksToWait ); if( xKeyPadQueueStatus == pdPASS ) { // printf( "Received = %d \t", sReceivedValue); switch (sReceivedValue) { case RESET: break; case PLAY: break; case PAUSE: break; case STOP: break; case ENTER: switch (xChoice) { case RECORD_A_PROGRAM: printf("%s\n",pcChoices[xChoice]); xSystemState = RECORDING; xTaskCreate(vTaskRecord, "Record Task", 2000, NULL, 1, &xRecordHandle); /* Get out of here */ vTaskDelete( NULL); break; case PLAY_A_PROGRAM: printf("%s\n",pcChoices[xChoice]); xSystemState = PLAYING; xTaskCreate(vTaskPlay, "Play Task", PLAY_TASK_STACK_SIZE, NULL, 1, &xPlayHandle); /* Get out of here */ vTaskDelete( NULL); break; default: break; } break; case CANCEL: break; case XUP: case UP: case XRIGHT: case RIGHT: if (++xChoice >= NUMBER_OF_CHOICES) { xChoice = 0; } break; case XDOWN: case DOWN: case XLEFT: case LEFT: /* enum is an unsigned int, checking below zero doesn't work * so check if value is above the max number aswell */ --xChoice; if (xChoice < 0 || xChoice > NUMBER_OF_CHOICES) { xChoice = NUMBER_OF_CHOICES - 1; } break; default: break; } vPrintToLCD(2,pcChoices[xChoice]); } else { //printf( "Could not receive from the queue.\r\n"); } taskYIELD(); } for (;;) { /* Catch a problem - Do nothing */ } vTaskDelete(NULL); }
static void prvQueueOverwriteTask( void *pvParameters ) { QueueHandle_t xTaskQueue; const unsigned portBASE_TYPE uxQueueLength = 1; unsigned long ulValue, ulStatus = pdPASS, x; /* The parameter is not used. */ ( void ) pvParameters; /* Create the queue. xQueueOverwrite() should only be used on queues that have a length of 1. */ xTaskQueue = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( unsigned long ) ); configASSERT( xTaskQueue ); for( ;; ) { /* The queue is empty. Writing to the queue then reading from the queue should return the item written. */ ulValue = 10; xQueueOverwrite( xTaskQueue, &ulValue ); ulValue = 0; xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK ); if( ulValue != 10 ) { ulStatus = pdFAIL; } /* Now try writing to the queue several times. Each time the value in the queue should get overwritten. */ for( x = 0; x < qoLOOPS; x++ ) { /* Write to the queue. */ xQueueOverwrite( xTaskQueue, &x ); /* Check the value in the queue is that written, even though the queue was not necessarily empty. */ xQueuePeek( xTaskQueue, &ulValue, qoDONT_BLOCK ); if( ulValue != x ) { ulStatus = pdFAIL; } /* There should always be one item in the queue. */ if( uxQueueMessagesWaiting( xTaskQueue ) != uxQueueLength ) { ulStatus = pdFAIL; } } /* Empty the queue again. */ xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK ); if( uxQueueMessagesWaiting( xTaskQueue ) != 0 ) { ulStatus = pdFAIL; } if( ulStatus != pdFAIL ) { /* Increment a counter to show this task is still running without error. */ ulLoopCounter++; } #if( configUSE_PREEMPTION == 0 ) taskYIELD(); #endif } }
s32 TERMINAL_PrintSdCardInfo(void *_output_function) { void (*out)(char *format, ...) = _output_function; FRESULT res; FILINFO fno; DIR dir; char *fn; char str_buffer[128]; MUTEX_MIDIOUT_TAKE; out("SD Card Informations\n"); out("====================\n"); #if !defined(MIOS32_FAMILY_EMULATION) // this yield ensures, that Debug Messages are sent before we continue the execution // Since MIOS Studio displays the time at which the messages arrived, this allows // us to measure the delay of following operations taskYIELD(); MUTEX_SDCARD_TAKE; FILE_PrintSDCardInfos(); MUTEX_SDCARD_GIVE; #endif out("\n"); out("Reading Root Directory\n"); out("======================\n"); taskYIELD(); if( !FILE_SDCardAvailable() ) { sprintf(str_buffer, "not connected"); } else if( !FILE_VolumeAvailable() ) { sprintf(str_buffer, "Invalid FAT"); } else { out("Retrieving SD Card informations - please wait!\n"); MUTEX_MIDIOUT_GIVE; MUTEX_SDCARD_TAKE; FILE_UpdateFreeBytes(); MUTEX_SDCARD_GIVE; MUTEX_MIDIOUT_TAKE; sprintf(str_buffer, "'%s': %u of %u MB free", FILE_VolumeLabel(), (unsigned int)(FILE_VolumeBytesFree()/1000000), (unsigned int)(FILE_VolumeBytesTotal()/1000000)); } out("SD Card: %s\n", str_buffer); taskYIELD(); #if _USE_LFN static char lfn[_MAX_LFN * (_DF1S ? 2 : 1) + 1]; fno.lfname = lfn; fno.lfsize = sizeof(lfn); #endif MUTEX_SDCARD_TAKE; if( (res=f_opendir(&dir, "/")) != FR_OK ) { out("Failed to open root directory - error status: %d\n", res); } else { while( (f_readdir(&dir, &fno) == FR_OK) && fno.fname[0] ) { #if _USE_LFN fn = *fno.lfname ? fno.lfname : fno.fname; #else fn = fno.fname; #endif char date[10]; ShowFatDate(fno.fdate,(char*)&date); char time[12]; ShowFatTime(fno.ftime,(char*)&time); out("[%s%s%s%s%s%s%s] %s %s %s %u %s\n", (fno.fattrib & AM_RDO ) ? "r" : ".", (fno.fattrib & AM_HID ) ? "h" : ".", (fno.fattrib & AM_SYS ) ? "s" : ".", (fno.fattrib & AM_VOL ) ? "v" : ".", (fno.fattrib & AM_LFN ) ? "l" : ".", (fno.fattrib & AM_DIR ) ? "d" : ".", (fno.fattrib & AM_ARC ) ? "a" : ".", date,time, (fno.fattrib & AM_DIR) ? "<DIR>" : " ", fno.fsize,fn); } } MUTEX_SDCARD_GIVE; taskYIELD(); out("done.\n"); MUTEX_MIDIOUT_GIVE; return 0; // no error }
void TASK_Bluetooth( void *pvParameters ) { UNUSED( pvParameters ); static char rxBuffer[BLUETOOTH_MAX_RX_LEN]; static char *Rx = rxBuffer; char Tx[BLUETOOTH_TX_BUFFER_LEN]; /* Create a semaphore */ rxSemaphoreBluetooth = xSemaphoreCreateBinary(); /* Ensure that semaphore is valid */ Assert( rxSemaphoreBluetooth ); /* Create a queue */ xBluetoothTxQueue = xQueueCreate( 3, BLUETOOTH_TX_BUFFER_LEN * sizeof( char ) ); xBluetoothRxQueue = xQueueCreate( BLUETOOTH_MAX_RX_LEN, sizeof( uint16_t ) ); /* Ensure that the queue is valid */ Assert( xBluetoothTxQueue ); Assert( xBluetoothRxQueue ); /* Start reading */ dma_start_transfer_job( &zDMA_BluetoothResourceRx ); for(;;) { if( xQueueReceive( xBluetoothTxQueue, Tx, ( TickType_t ) 0 ) == pdTRUE ) { strncpy((char *)Bluetooth_TxBuffer, Tx, sizeof(FTDI_TxBuffer)); dma_start_transfer_job(&zDMA_BluetoothResourceTx); while( !( DMA_Status & _LS(BLUETOOTH_TX_DONE) ) ) { taskYIELD(); } DMA_Status &= !(_LS(BLUETOOTH_TX_DONE)); } /* Block task until DMA read complete */ if( xSemaphoreTake( rxSemaphoreBluetooth, 5 ) == pdTRUE ) { if( xBluetoothTxQueue != 0) { xQueueSend( xBluetoothTxQueue, Bluetooth_RxBuffer, ( TickType_t ) 0 ); } /* Look for backspace character */ if( *Bluetooth_RxBuffer == 127 ) { if( Rx != rxBuffer ) { Rx--; *Rx = 0; } } else if( *Bluetooth_RxBuffer == 13 ) // Carriage return { memcpy( Rx, "\0", sizeof( char ) ); /* Pass command to the main parser */ if( xParserQueue != 0 ) { xQueueSend( xParserQueue, rxBuffer, ( TickType_t ) 10 ); } Rx = rxBuffer; } else if( !strcmp( ( const char * ) Bluetooth_RxBuffer, "\027[D" ) ) // Left arrow ANSI { /* Move pointer around */ } else if( !strcmp( ( const char * ) Bluetooth_RxBuffer, "\027[C" ) ) // Right arrow ANSI { /* Move pointer around */ } else if( !strcmp( ( const char * ) Bluetooth_RxBuffer, "\027[A" ) ) // Up arrow ANSI { /* Previous command */ } else if( !strcmp( ( const char * ) Bluetooth_RxBuffer, "\027[B" ) ) // Down arrow ANSI { /* Next command, if available */ } else { /* Copy byte into buffer */ *Rx = ( char ) *Bluetooth_RxBuffer; /* Reset buffer pointer on overflow */ if( Rx == &rxBuffer[BLUETOOTH_MAX_RX_LEN-1] ) { Rx = rxBuffer; } else { Rx++; } } dma_start_transfer_job( &zDMA_BluetoothResourceRx ); } taskYIELD(); } }
//------------------------------------------------------------------------------------ size_t FreeRTOS_UART_write( Peripheral_Descriptor_t const pxPeripheral, const void *pvBuffer, const size_t xBytes ) { // Esta funcion debe poner los caracteres apuntados en pvBuffer en la cola de trasmision. // Actua como si fuese rprintfStr. // Debe tomar el semaforo antes de trasmitir. Los semaforos los manejamos en la capa FreeRTOS // y no en la de los drivers. char cChar; char *p; size_t bytes2tx; Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral; UART_device_control_t *pUart; size_t wBytes = 0; pUart = pxPeripheralControl->phDevice; // Controlo no hacer overflow en la cola de trasmision bytes2tx = xBytes; // Espero el semaforo en forma persistente. while ( xSemaphoreTake(pxPeripheralControl->xBusSemaphore, ( TickType_t ) 1 ) != pdTRUE ) taskYIELD(); // Trasmito. // Espero que los buffers esten vacios. ( La uart se va limpiando al trasmitir ) if ( pUart->txBufferType == QUEUE ) { while ( uxQueueMessagesWaiting( pUart->txStruct ) > 0 ) taskYIELD(); } else { while ( uxFifoMessagesWaiting( pUart->txStruct ) > 0 ) taskYIELD(); } // Cargo el buffer en la cola de trasmision. p = (char *)pvBuffer; while (*p && (bytes2tx-- > 0) ) { // Voy cargando la cola de a uno. cChar = *p; pv_enqueue( pUart, &cChar ); p++; wBytes++; // Cuento los bytes que voy trasmitiendo // Si la cola esta llena, empiezo a trasmitir y espero que se vacie. if ( pv_queueReachHighWaterMark(pUart) ) { // Habilito a trasmitir para que se vacie vUartInterruptOn(pxPeripheralControl->portId); // Y espero que se haga mas lugar. while ( ! pv_queueReachLowWaterMark(pUart) ) taskYIELD(); } } // Luego inicio la trasmision invocando la interrupcion. vUartInterruptOn(pxPeripheralControl->portId); xSemaphoreGive( pxPeripheralControl->xBusSemaphore ); //return xBytes; // Puse todos los caracteres en la cola. return (wBytes); }
//----------------------------------------------------------------------------- // процедура общения с шиной 1-wire // sendReset - посылать RESET в начале общения. // OW_SEND_RESET или OW_NO_RESET // command - массив байт, отсылаемых в шину. Если нужно чтение - отправляем OW_READ_SLOTH // cLen - длина буфера команд, столько байт отошлется в шину // data - если требуется чтение, то ссылка на буфер для чтения // dLen - длина буфера для чтения. Прочитается не более этой длины // readStart - с какого символа передачи начинать чтение (нумеруются с 0) // можно указать OW_NO_READ, тогда можно не задавать data и dLen //----------------------------------------------------------------------------- uint8_t OW_Send(uint8_t sendReset, uint8_t *command, uint8_t cLen, uint8_t *data, uint8_t dLen, uint8_t readStart) { // если требуется сброс - сбрасываем и проверяем на наличие устройств if (sendReset == OW_SEND_RESET) { if (OW_Reset() == OW_NO_DEVICE) { return OW_NO_DEVICE; } } while (cLen > 0) { OW_toBits(*command, ow_buf); command++; cLen--; DMA_InitTypeDef DMA_InitStructure; // DMA на чтение DMA_DeInit(OW_DMA_CH_RX); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) ow_buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 8; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Low; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(OW_DMA_CH_RX, &DMA_InitStructure); // DMA на запись DMA_DeInit(OW_DMA_CH_TX); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) ow_buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = 8; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Low; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(OW_DMA_CH_TX, &DMA_InitStructure); // старт цикла отправки USART_ClearFlag(OW_USART, USART_FLAG_RXNE | USART_FLAG_TC | USART_FLAG_TXE); USART_DMACmd(OW_USART, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE); DMA_Cmd(OW_DMA_CH_RX, ENABLE); DMA_Cmd(OW_DMA_CH_TX, ENABLE); // Ждем, пока не примем 8 байт while (DMA_GetFlagStatus(OW_DMA_FLAG) == RESET){ #ifdef OW_GIVE_TICK_RTOS taskYIELD(); IWDG_ReloadCounter(); #endif } // отключаем DMA DMA_Cmd(OW_DMA_CH_TX, DISABLE); DMA_Cmd(OW_DMA_CH_RX, DISABLE); USART_DMACmd(OW_USART, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE); // если прочитанные данные кому-то нужны - выкинем их в буфер if (readStart == 0 && dLen > 0) { *data = OW_toByte(ow_buf); data++; dLen--; } else { if (readStart != OW_NO_READ) { readStart--; } } } return OW_OK; }
//------------------------------------------------------------------------------------ s08 FF_rewind(void) { // Borra el archivo y lo lleva a su condicion inicial. // Inicializa la memoria. Como lleva bastante tiempo, tenemos problemas con el // watchdog. Por esto desde donde la invocamos debemos desactivarlo y esta // funcion SOLO debe usarse desde CMD. u16 val = 0; u16 tryes; u16 xPos; wdt_reset(); // Lo primero es obtener el semaforo del I2C FreeRTOS_ioctl(&pdI2C,ioctlOBTAIN_BUS_SEMPH, NULL); // inicializo la estructura lineal temporal del FCB. memset( FCB.ff_buffer,0, sizeof(FCB.ff_buffer) ); // EE WRITE: // Luego indicamos el periferico i2c en el cual queremos leer val = EE_ADDR; FreeRTOS_ioctl(&pdI2C,ioctl_I2C_SET_DEVADDRESS, &val); // Luego indicamos la direccion a escribir del dispositivo: largo ( en la ee son 2 bytes ) val = 2; FreeRTOS_ioctl(&pdI2C,ioctl_I2C_SET_BYTEADDRESSLENGTH, &val); // Ciclo de borrado for ( xPos = 0; xPos < FF_MAX_RCDS; xPos++) { // direccion interna en la EE.(comienzo del registro / frontera) val = FF_ADDR_START + xPos * FF_RECD_SIZE; FreeRTOS_ioctl(&pdI2C,ioctl_I2C_SET_BYTEADDRESS,&val); for ( tryes = 0; tryes < 3; tryes++ ) { // Borro: escribo un pagina entera, 64 bytes con los '\0' FreeRTOS_write(&pdI2C, &FCB.ff_buffer, FF_RECD_SIZE); taskYIELD(); // Leo y verifico FreeRTOS_read(&pdI2C, &FCB.check_buffer, FF_RECD_SIZE); if ( memcmp (&FCB.check_buffer, &FCB.ff_buffer, FF_RECD_SIZE) == 0 ) break; if ( tryes == 3 ) { snprintf_P( debug_printfBuff,sizeof(debug_printfBuff),PSTR("FFrew ERR: %d,%d\r\n\0"),xPos, val); FreeRTOS_write( &pdUART1, debug_printfBuff, sizeof(debug_printfBuff) ); } } // Imprimo realimentacion c/32 recs. if ( (xPos % 32) == 0 ) { FreeRTOS_write( &pdUART1, ".\0", sizeof(".\0") ); } // Para no salir por wdg reset if ( (xPos % 64) == 0 ) { wdt_reset(); } } FreeRTOS_write( &pdUART1, "\r\n\0", sizeof("\r\n\0") ); FreeRTOS_ioctl(&pdI2C,ioctlRELEASE_BUS_SEMPH, NULL); // RESET u_reset(); }
/* * Controller task as described above. */ static void vCounterControlTask( void * pvParameters ) { unsigned long ulLastCounter; short sLoops; short sError = pdFALSE; const char * const pcTaskStartMsg = "Priority manipulation tasks started.\r\n"; const char * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n"; /* Just to stop warning messages. */ ( void ) pvParameters; /* Queue a message for printing to say the task has started. */ vPrintDisplayMessage( &pcTaskStartMsg ); for( ;; ) { /* Start with the counter at zero. */ ulCounter = ( unsigned long ) 0; /* First section : */ /* Check the continuous count task is running. */ for( sLoops = 0; sLoops < priLOOPS; sLoops++ ) { /* Suspend the continuous count task so we can take a mirror of the shared variable without risk of corruption. */ vTaskSuspend( xContinuousIncrementHandle ); ulLastCounter = ulCounter; vTaskResume( xContinuousIncrementHandle ); /* Now delay to ensure the other task has processor time. */ vTaskDelay( priSLEEP_TIME ); /* Check the shared variable again. This time to ensure mutual exclusion the whole scheduler will be locked. This is just for demo purposes! */ vTaskSuspendAll(); { if( ulLastCounter == ulCounter ) { /* The shared variable has not changed. There is a problem with the continuous count task so flag an error. */ sError = pdTRUE; xTaskResumeAll(); vPrintDisplayMessage( &pcTaskFailMsg ); vTaskSuspendAll(); } } xTaskResumeAll(); } /* Second section: */ /* Suspend the continuous counter task so it stops accessing the shared variable. */ vTaskSuspend( xContinuousIncrementHandle ); /* Reset the variable. */ ulCounter = ( unsigned long ) 0; /* Resume the limited count task which has a higher priority than us. We should therefore not return from this call until the limited count task has suspended itself with a known value in the counter variable. The scheduler suspension is not necessary but is included for test purposes. */ vTaskSuspendAll(); vTaskResume( xLimitedIncrementHandle ); xTaskResumeAll(); /* Does the counter variable have the expected value? */ if( ulCounter != priMAX_COUNT ) { sError = pdTRUE; vPrintDisplayMessage( &pcTaskFailMsg ); } if( sError == pdFALSE ) { /* If no errors have occurred then increment the check variable. */ portENTER_CRITICAL(); usCheckVariable++; portEXIT_CRITICAL(); } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif /* Resume the continuous count task and do it all again. */ vTaskResume( xContinuousIncrementHandle ); } }
static void prvLowPriorityMutexTask( void *pvParameters ) { xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters; #ifdef USE_STDIO void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend ); const portCHAR * const pcTaskStartMsg = "Fast mutex with priority inheritance test started.\r\n"; /* Queue a message for printing to say the task has started. */ vPrintDisplayMessage( &pcTaskStartMsg ); #endif ( void ) pvParameters; for( ;; ) { /* Take the mutex. It should be available now. */ if( xSemaphoreAltTake( xMutex, genqNO_BLOCK ) != pdPASS ) { xErrorDetected = pdTRUE; } /* Set our guarded variable to a known start value. */ ulGuardedVariable = 0; /* Our priority should be as per that assigned when the task was created. */ if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) { xErrorDetected = pdTRUE; } /* Now unsuspend the high priority task. This will attempt to take the mutex, and block when it finds it cannot obtain it. */ vTaskResume( xHighPriorityMutexTask ); /* We should now have inherited the prioritoy of the high priority task, as by now it will have attempted to get the mutex. */ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) { xErrorDetected = pdTRUE; } /* We can attempt to set our priority to the test priority - between the idle priority and the medium/high test priorities, but our actual prioroity should remain at the high priority. */ vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY ); if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) { xErrorDetected = pdTRUE; } /* Now unsuspend the medium priority task. This should not run as our inherited priority is above that of the medium priority task. */ vTaskResume( xMediumPriorityMutexTask ); /* If the did run then it will have incremented our guarded variable. */ if( ulGuardedVariable != 0 ) { xErrorDetected = pdTRUE; } /* When we give back the semaphore our priority should be disinherited back to the priority to which we attempted to set ourselves. This means that when the high priority task next blocks, the medium priority task should execute and increment the guarded variable. When we next run both the high and medium priority tasks will have been suspended again. */ if( xSemaphoreAltGive( xMutex ) != pdPASS ) { xErrorDetected = pdTRUE; } /* Check that the guarded variable did indeed increment... */ if( ulGuardedVariable != 1 ) { xErrorDetected = pdTRUE; } /* ... and that our priority has been disinherited to genqMUTEX_TEST_PRIORITY. */ if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY ) { xErrorDetected = pdTRUE; } /* Set our priority back to our original priority ready for the next loop around this test. */ vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY ); /* Just to show we are still running. */ ulLoopCounter2++; #if configUSE_PREEMPTION == 0 taskYIELD(); #endif } }
signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) { signed portBASE_TYPE xReturn = pdTRUE; xTimeOutType xTimeOut; do { /* If xTicksToWait is zero then we are not going to block even if there is no room in the queue to post. */ if( xTicksToWait > ( portTickType ) 0 ) { vTaskSuspendAll(); prvLockQueue( pxQueue ); if( xReturn == pdTRUE ) { /* This is the first time through - we need to capture the time while the scheduler is locked to ensure we attempt to block at least once. */ vTaskSetTimeOutState( &xTimeOut ); } if( prvIsQueueFull( pxQueue ) ) { /* Need to call xTaskCheckForTimeout again as time could have passed since it was last called if this is not the first time around this loop. */ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { traceBLOCKING_ON_QUEUE_SEND( pxQueue ); vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); /* Unlocking the queue means queue events can effect the event list. It is possible that interrupts occurring now remove this task from the event list again - but as the scheduler is suspended the task will go onto the pending ready last instead of the actual ready list. */ prvUnlockQueue( pxQueue ); /* Resuming the scheduler will move tasks from the pending ready list into the ready list - so it is feasible that this task is already in a ready list before it yields - in which case the yield will not cause a context switch unless there is also a higher priority task in the pending ready list. */ if( !xTaskResumeAll() ) { taskYIELD(); } } else { prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); } } else { /* The queue was not full so we can just unlock the scheduler and queue again before carrying on. */ prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); } } /* Higher priority tasks and interrupts can execute during this time and could possible refill the queue - even if we unblocked because space became available. */ taskENTER_CRITICAL(); { /* Is there room on the queue now? To be running we must be the highest priority task wanting to access the queue. */ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { traceQUEUE_SEND( pxQueue ); prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); xReturn = pdPASS; /* If there was a task waiting for data to arrive on the queue then unblock it now. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) { /* The unblocked task has a priority higher than our own so yield immediately. */ taskYIELD(); } } } else { /* Setting xReturn to errQUEUE_FULL will force its timeout to be re-evaluated. This is necessary in case interrupts and higher priority tasks accessed the queue between this task being unblocked and subsequently attempting to write to the queue. */ xReturn = errQUEUE_FULL; } } taskEXIT_CRITICAL(); if( xReturn == errQUEUE_FULL ) { if( xTicksToWait > ( portTickType ) 0 ) { if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { xReturn = queueERRONEOUS_UNBLOCK; } else { traceQUEUE_SEND_FAILED( pxQueue ); } } else { traceQUEUE_SEND_FAILED( pxQueue ); } } } while( xReturn == queueERRONEOUS_UNBLOCK ); return xReturn; }
signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) { signed portBASE_TYPE xReturn; xTimeOutType xTimeOut; /* Make sure other tasks do not access the queue. */ vTaskSuspendAll(); /* Capture the current time status for future reference. */ vTaskSetTimeOutState( &xTimeOut ); /* It is important that this is the only thread/ISR that modifies the ready or delayed lists until xTaskResumeAll() is called. Places where the ready/delayed lists are modified include: + vTaskDelay() - Nothing can call vTaskDelay as the scheduler is suspended, vTaskDelay() cannot be called from an ISR. + vTaskPrioritySet() - Has a critical section around the access. + vTaskSwitchContext() - This will not get executed while the scheduler is suspended. + prvCheckDelayedTasks() - This will not get executed while the scheduler is suspended. + xTaskCreate() - Has a critical section around the access. + vTaskResume() - Has a critical section around the access. + xTaskResumeAll() - Has a critical section around the access. + xTaskRemoveFromEventList - Checks to see if the scheduler is suspended. If so then the TCB being removed from the event is removed from the event and added to the xPendingReadyList. */ /* Make sure interrupts do not access the queue event list. */ prvLockQueue( pxQueue ); /* It is important that interrupts to not access the event list of the queue being modified here. Places where the event list is modified include: + xQueueSendFromISR(). This checks the lock on the queue to see if it has access. If the queue is locked then the Tx lock count is incremented to signify that a task waiting for data can be made ready once the queue lock is removed. If the queue is not locked then a task can be moved from the event list, but will not be removed from the delayed list or placed in the ready list until the scheduler is unlocked. + xQueueReceiveFromISR(). As per xQueueSendFromISR(). */ /* If the queue is already full we may have to block. */ do { if( prvIsQueueFull( pxQueue ) ) { /* The queue is full - do we want to block or just leave without posting? */ if( xTicksToWait > ( portTickType ) 0 ) { /* We are going to place ourselves on the xTasksWaitingToSend event list, and will get woken should the delay expire, or space become available on the queue. As detailed above we do not require mutual exclusion on the event list as nothing else can modify it or the ready lists while we have the scheduler suspended and queue locked. It is possible that an ISR has removed data from the queue since we checked if any was available. If this is the case then the data will have been copied from the queue, and the queue variables updated, but the event list will not yet have been checked to see if anything is waiting as the queue is locked. */ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); /* Force a context switch now as we are blocked. We can do this from within a critical section as the task we are switching to has its own context. When we return here (i.e. we unblock) we will leave the critical section as normal. It is possible that an ISR has caused an event on an unrelated and unlocked queue. If this was the case then the event list for that queue will have been updated but the ready lists left unchanged - instead the readied task will have been added to the pending ready list. */ taskENTER_CRITICAL(); { /* We can safely unlock the queue and scheduler here as interrupts are disabled. We must not yield with anything locked, but we can yield from within a critical section. Tasks that have been placed on the pending ready list cannot be tasks that are waiting for events on this queue. See in comment xTaskRemoveFromEventList(). */ prvUnlockQueue( pxQueue ); /* Resuming the scheduler may cause a yield. If so then there is no point yielding again here. */ if( !xTaskResumeAll() ) { taskYIELD(); } /* Before leaving the critical section we have to ensure exclusive access again. */ vTaskSuspendAll(); prvLockQueue( pxQueue ); } taskEXIT_CRITICAL(); } } /* When we are here it is possible that we unblocked as space became available on the queue. It is also possible that an ISR posted to the queue since we left the critical section, so it may be that again there is no space. This would only happen if a task and ISR post onto the same queue. */ taskENTER_CRITICAL(); { if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { /* There is room in the queue, copy the data into the queue. */ prvCopyQueueData( pxQueue, pvItemToQueue ); xReturn = pdPASS; /* Update the TxLock count so prvUnlockQueue knows to check for tasks waiting for data to become available in the queue. */ ++( pxQueue->xTxLock ); } else { xReturn = errQUEUE_FULL; } } taskEXIT_CRITICAL(); if( xReturn == errQUEUE_FULL ) { if( xTicksToWait > 0 ) { if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { xReturn = queueERRONEOUS_UNBLOCK; } } } } while( xReturn == queueERRONEOUS_UNBLOCK ); prvUnlockQueue( pxQueue ); xTaskResumeAll(); return xReturn; }
signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) { signed portBASE_TYPE xReturn = pdPASS; xTimeOutType xTimeOut; /* The source code that implements the alternative (Alt) API is simpler because it makes more use of critical sections. This is the approach taken by many other RTOSes, but FreeRTOS.org has the preferred fully featured API too. The fully featured API has more complex code that takes longer to execute, but makes less use of critical sections. */ do { /* If xTicksToWait is zero then we are not going to block even if there is no room in the queue to post. */ if( xTicksToWait > ( portTickType ) 0 ) { portENTER_CRITICAL(); { if( xReturn == pdPASS ) { /* This is the first time through - capture the time inside the critical section to ensure we attempt to block at least once. */ vTaskSetTimeOutState( &xTimeOut ); } if( prvIsQueueFull( pxQueue ) ) { /* Need to call xTaskCheckForTimeout again as time could have passed since it was last called if this is not the first time around this loop. */ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { traceBLOCKING_ON_QUEUE_SEND( pxQueue ); vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); /* This will exit the critical section, then re-enter when the task next runs. */ taskYIELD(); } } } portEXIT_CRITICAL(); } /* Higher priority tasks and interrupts can execute during this time and could possible refill the queue - even if we unblocked because space became available. */ taskENTER_CRITICAL(); { /* Is there room on the queue now? To be running we must be the highest priority task wanting to access the queue. */ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { traceQUEUE_SEND( pxQueue ); prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); xReturn = pdPASS; /* If there was a task waiting for data to arrive on the queue then unblock it now. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) { /* The unblocked task has a priority higher than our own so yield immediately. */ taskYIELD(); } } } else { /* Setting xReturn to errQUEUE_FULL will force its timeout to be re-evaluated. This is necessary in case interrupts and higher priority tasks accessed the queue between this task being unblocked and subsequently attempting to write to the queue. */ xReturn = errQUEUE_FULL; } } taskEXIT_CRITICAL(); if( xReturn == errQUEUE_FULL ) { if( xTicksToWait > ( portTickType ) 0 ) { if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { xReturn = queueERRONEOUS_UNBLOCK; } else { traceQUEUE_SEND_FAILED( pxQueue ); } } else { traceQUEUE_SEND_FAILED( pxQueue ); } } } while( xReturn == queueERRONEOUS_UNBLOCK ); return xReturn; }
/* * Controller task as described above. */ static portTASK_FUNCTION( vCounterControlTask, pvParameters ) { uint32_t ulLastCounter; short sLoops; short sError = pdFALSE; /* Just to stop warning messages. */ ( void ) pvParameters; for( ;; ) { /* Start with the counter at zero. */ ulCounter = ( uint32_t ) 0; /* First section : */ /* Check the continuous count task is running. */ for( sLoops = 0; sLoops < priLOOPS; sLoops++ ) { /* Suspend the continuous count task so we can take a mirror of the shared variable without risk of corruption. This is not really needed as the other task raises its priority above this task's priority. */ vTaskSuspend( xContinuousIncrementHandle ); { #if( INCLUDE_eTaskGetState == 1 ) { configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eSuspended ); } #endif /* INCLUDE_eTaskGetState */ ulLastCounter = ulCounter; } vTaskResume( xContinuousIncrementHandle ); #if( configUSE_PREEMPTION == 0 ) taskYIELD(); #endif #if( INCLUDE_eTaskGetState == 1 ) { configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eReady ); } #endif /* INCLUDE_eTaskGetState */ /* Now delay to ensure the other task has processor time. */ vTaskDelay( priSLEEP_TIME ); /* Check the shared variable again. This time to ensure mutual exclusion the whole scheduler will be locked. This is just for demo purposes! */ vTaskSuspendAll(); { if( ulLastCounter == ulCounter ) { /* The shared variable has not changed. There is a problem with the continuous count task so flag an error. */ sError = pdTRUE; } } xTaskResumeAll(); } /* Second section: */ /* Suspend the continuous counter task so it stops accessing the shared variable. */ vTaskSuspend( xContinuousIncrementHandle ); /* Reset the variable. */ ulCounter = ( uint32_t ) 0; #if( INCLUDE_eTaskGetState == 1 ) { configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended ); } #endif /* INCLUDE_eTaskGetState */ /* Resume the limited count task which has a higher priority than us. We should therefore not return from this call until the limited count task has suspended itself with a known value in the counter variable. */ vTaskResume( xLimitedIncrementHandle ); #if( configUSE_PREEMPTION == 0 ) taskYIELD(); #endif /* This task should not run again until xLimitedIncrementHandle has suspended itself. */ #if( INCLUDE_eTaskGetState == 1 ) { configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended ); } #endif /* INCLUDE_eTaskGetState */ /* Does the counter variable have the expected value? */ if( ulCounter != priMAX_COUNT ) { sError = pdTRUE; } if( sError == pdFALSE ) { /* If no errors have occurred then increment the check variable. */ portENTER_CRITICAL(); usCheckVariable++; portEXIT_CRITICAL(); } /* Resume the continuous count task and do it all again. */ vTaskResume( xContinuousIncrementHandle ); #if( configUSE_PREEMPTION == 0 ) taskYIELD(); #endif } }
signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) { signed portBASE_TYPE xReturn = pdTRUE; xTimeOutType xTimeOut; signed portCHAR *pcOriginalReadPosition; do { /* If there are no messages in the queue we may have to block. */ if( xTicksToWait > ( portTickType ) 0 ) { vTaskSuspendAll(); prvLockQueue( pxQueue ); if( xReturn == pdTRUE ) { /* This is the first time through - we need to capture the time while the scheduler is locked to ensure we attempt to block at least once. */ vTaskSetTimeOutState( &xTimeOut ); } if( prvIsQueueEmpty( pxQueue ) ) { /* Need to call xTaskCheckForTimeout again as time could have passed since it was last called if this is not the first time around this loop. */ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); #if ( configUSE_MUTEXES == 1 ) { if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { portENTER_CRITICAL(); vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); portEXIT_CRITICAL(); } } #endif vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); prvUnlockQueue( pxQueue ); if( !xTaskResumeAll() ) { taskYIELD(); } } else { prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); } } else { prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); } } taskENTER_CRITICAL(); { if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { /* Remember our read position in case we are just peeking. */ pcOriginalReadPosition = pxQueue->pcReadFrom; prvCopyDataFromQueue( pxQueue, pvBuffer ); if( xJustPeeking == pdFALSE ) { traceQUEUE_RECEIVE( pxQueue ); /* We are actually removing data. */ --( pxQueue->uxMessagesWaiting ); #if ( configUSE_MUTEXES == 1 ) { if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { /* Record the information required to implement priority inheritance should it become necessary. */ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle(); } } #endif if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) { taskYIELD(); } } } else { traceQUEUE_PEEK( pxQueue ); /* We are not removing the data, so reset our read pointer. */ pxQueue->pcReadFrom = pcOriginalReadPosition; /* The data is being left in the queue, so see if there are any other tasks waiting for the data. */ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) { /* Tasks that are removed from the event list will get added to the pending ready list as the scheduler is still suspended. */ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { /* The task waiting has a higher priority that this task. */ taskYIELD(); } } } xReturn = pdPASS; } else { xReturn = errQUEUE_EMPTY; } } taskEXIT_CRITICAL(); if( xReturn == errQUEUE_EMPTY ) { if( xTicksToWait > ( portTickType ) 0 ) { if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { xReturn = queueERRONEOUS_UNBLOCK; } else { traceQUEUE_RECEIVE_FAILED( pxQueue ); } } else { traceQUEUE_RECEIVE_FAILED( pxQueue ); } } } while( xReturn == queueERRONEOUS_UNBLOCK ); return xReturn; }
static portTASK_FUNCTION( vCompetingMathTask3, pvParameters ) { volatile portDOUBLE *pdArray, dTotal1, dTotal2, dDifference; volatile unsigned long *pulTaskCheckVariable; const size_t xArraySize = 10; size_t xPosition; short sError = pdFALSE; /* Must be called before any hardware floating point operations are performed to let the RTOS portable layer know that this task requires a floating point context. */ #if __TI_VFP_SUPPORT__ vPortTaskUsesFPU(); #endif /* The variable this task increments to show it is still running is passed in as the parameter. */ pulTaskCheckVariable = ( unsigned long * ) pvParameters; pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) ); /* Keep filling an array, keeping a running total of the values placed in the array. Then run through the array adding up all the values. If the two totals do not match, stop the check variable from incrementing. */ for( ;; ) { dTotal1 = 0.0; dTotal2 = 0.0; for( xPosition = 0; xPosition < xArraySize; xPosition++ ) { pdArray[ xPosition ] = ( portDOUBLE ) xPosition + 5.5; dTotal1 += ( portDOUBLE ) xPosition + 5.5; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif for( xPosition = 0; xPosition < xArraySize; xPosition++ ) { dTotal2 += pdArray[ xPosition ]; } dDifference = dTotal1 - dTotal2; if( fabs( dDifference ) > 0.001 ) { sError = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif if( sError == pdFALSE ) { /* If the calculation has always been correct, increment the check variable so we know this task is still running okay. */ ( *pulTaskCheckVariable )++; } } }
static void prvRecursiveMutexControllingTask( void *pvParameters ) { unsigned portBASE_TYPE ux; /* Just to remove compiler warning. */ ( void ) pvParameters; for( ;; ) { /* Should not be able to 'give' the mutex, as we have not yet 'taken' it. The first time through, the mutex will not have been used yet, subsequent times through, at this point the mutex will be held by the polling task. */ if( xSemaphoreGiveRecursive( xMutex ) == pdPASS ) { xErrorOccurred = pdTRUE; } for( ux = 0; ux < recmuMAX_COUNT; ux++ ) { /* We should now be able to take the mutex as many times as we like. The first time through the mutex will be immediately available, on subsequent times through the mutex will be held by the polling task at this point and this Take will cause the polling task to inherit the priority of this task. In this case the block time must be long enough to ensure the polling task will execute again before the block time expires. If the block time does expire then the error flag will be set here. */ if( xSemaphoreTakeRecursive( xMutex, recmuFIVE_TICK_DELAY ) != pdPASS ) { xErrorOccurred = pdTRUE; } /* Ensure the other task attempting to access the mutex (and the other demo tasks) are able to execute to ensure they either block (where a block time is specified) or return an error (where no block time is specified) as the mutex is held by this task. */ vTaskDelay( recmuSHORT_DELAY ); } /* For each time we took the mutex, give it back. */ for( ux = 0; ux < recmuMAX_COUNT; ux++ ) { /* Ensure the other task attempting to access the mutex (and the other demo tasks) are able to execute. */ vTaskDelay( recmuSHORT_DELAY ); /* We should now be able to give the mutex as many times as we took it. When the mutex is available again the Blocking task should be unblocked but not run because it has a lower priority than this task. The polling task should also not run at this point as it too has a lower priority than this task. */ if( xSemaphoreGiveRecursive( xMutex ) != pdPASS ) { xErrorOccurred = pdTRUE; } #if configUSE_PREEMPTION == 0 taskYIELD(); #endif } /* Having given it back the same number of times as it was taken, we should no longer be the mutex owner, so the next give should fail. */ if( xSemaphoreGiveRecursive( xMutex ) == pdPASS ) { xErrorOccurred = pdTRUE; } /* Keep count of the number of cycles this task has performed so a stall can be detected. */ uxControllingCycles++; /* Suspend ourselves so the blocking task can execute. */ xControllingIsSuspended = pdTRUE; vTaskSuspend( NULL ); xControllingIsSuspended = pdFALSE; } }