📄 freertos kernel.c
字号:
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 than 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;
}
/*-----------------------------------------------------------*/
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )
{
signed portBASE_TYPE xReturn;
unsigned portBASE_TYPE uxSavedInterruptStatus;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
/* We cannot block from an ISR, so check there is data available. */
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
prvCopyDataFromQueue( pxQueue, pvBuffer );
--( pxQueue->uxMessagesWaiting );
/* If the queue is locked we will not modify the event list. Instead
we update the lock count so the task that unlocks the queue will know
that an ISR has removed data while the queue was locked. */
if( pxQueue->xRxLock == queueUNLOCKED )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
/* The task waiting has a higher priority than us so
force a context switch. */
*pxTaskWoken = pdTRUE;
}
}
}
else
{
/* Increment the lock count so the task that unlocks the queue
knows that data was removed while it was locked. */
++( pxQueue->xRxLock );
}
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );
}
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
return xReturn;
}
/*-----------------------------------------------------------*/
unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )
{
unsigned portBASE_TYPE uxReturn;
taskENTER_CRITICAL();
uxReturn = pxQueue->uxMessagesWaiting;
taskEXIT_CRITICAL();
return uxReturn;
}
/*-----------------------------------------------------------*/
unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )
{
unsigned portBASE_TYPE uxReturn;
uxReturn = pxQueue->uxMessagesWaiting;
return uxReturn;
}
/*-----------------------------------------------------------*/
void vQueueDelete( xQueueHandle pxQueue )
{
traceQUEUE_DELETE( pxQueue );
vQueueUnregisterQueue( pxQueue );
vPortFree( pxQueue->pcHead );
vPortFree( pxQueue );
}
/*-----------------------------------------------------------*/
static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )
{
if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 )
{
#if ( configUSE_MUTEXES == 1 )
{
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
{
/* The mutex is no longer being held. */
vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );
pxQueue->pxMutexHolder = NULL;
}
}
#endif
}
else if( xPosition == queueSEND_TO_BACK )
{
memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
pxQueue->pcWriteTo += pxQueue->uxItemSize;
if( pxQueue->pcWriteTo >= pxQueue->pcTail )
{
pxQueue->pcWriteTo = pxQueue->pcHead;
}
}
else
{
memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
pxQueue->pcReadFrom -= pxQueue->uxItemSize;
if( pxQueue->pcReadFrom < pxQueue->pcHead )
{
pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
}
}
++( pxQueue->uxMessagesWaiting );
}
/*-----------------------------------------------------------*/
static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )
{
if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )
{
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
}
}
/*-----------------------------------------------------------*/
static void prvUnlockQueue( xQueueHandle pxQueue )
{
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
/* The lock counts contains the number of extra data items placed or
removed from the queue while the queue was locked. When a queue is
locked items can be added or removed, but the event lists cannot be
updated. */
taskENTER_CRITICAL();
{
/* See if data was added to the queue while it was locked. */
while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )
{
/* Data was posted while the queue was locked. Are any tasks
blocked waiting for data to become available? */
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 so record that a
context switch is required. */
vTaskMissedYield();
}
--( pxQueue->xTxLock );
}
else
{
break;
}
}
pxQueue->xTxLock = queueUNLOCKED;
}
taskEXIT_CRITICAL();
/* Do the same for the Rx lock. */
taskENTER_CRITICAL();
{
while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
vTaskMissedYield();
}
--( pxQueue->xRxLock );
}
else
{
break;
}
}
pxQueue->xRxLock = queueUNLOCKED;
}
taskEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )
{
signed portBASE_TYPE xReturn;
taskENTER_CRITICAL();
xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
taskEXIT_CRITICAL();
return xReturn;
}
/*-----------------------------------------------------------*/
signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )
{
signed portBASE_TYPE xReturn;
xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
return xReturn;
}
/*-----------------------------------------------------------*/
static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
{
signed portBASE_TYPE xReturn;
taskENTER_CRITICAL();
xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
taskEXIT_CRITICAL();
return xReturn;
}
/*-----------------------------------------------------------*/
signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )
{
signed portBASE_TYPE xReturn;
xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
return xReturn;
}
/*-----------------------------------------------------------*/
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn;
/* If the queue is already full we may have to block. A critical section
is required to prevent an interrupt removing something from the queue
between the check to see if the queue is full and blocking on the queue. */
portDISABLE_INTERRUPTS();
{
if( prvIsQueueFull( pxQueue ) )
{
/* The queue is full - do we want to block or just leave without
posting? */
if( xTicksToWait > ( portTickType ) 0 )
{
/* As this is called from a coroutine we cannot block directly, but
return indicating that we need to block. */
vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );
portENABLE_INTERRUPTS();
return errQUEUE_BLOCKED;
}
else
{
portENABLE_INTERRUPTS();
return errQUEUE_FULL;
}
}
}
portENABLE_INTERRUPTS();
portNOP();
portDISABLE_INTERRUPTS();
{
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
/* There is room in the queue, copy the data into the queue. */
prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
xReturn = pdPASS;
/* Were any co-routines waiting for data to become available? */
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
/* In this instance the co-routine could be placed directly
into the ready list as we are within a critical section.
Instead the same pending ready list mechanism is used as if
the event were caused from within an interrupt. */
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The co-routine waiting has a higher priority so record
that a yield might be appropriate. */
xReturn = errQUEUE_YIELD;
}
}
}
else
{
xReturn = errQUEUE_FULL;
}
}
portENABLE_INTERRUPTS();
return xReturn;
}
#endif
/*-----------------------------------------------------------*/
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn;
/* If the queue is already empty we may have to block. A critical section
is required to prevent
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -