FreeRTOS队列接收

来源:互联网 发布:大智慧数据接口 编辑:程序博客网 时间:2024/05/17 22:36

与队列的发送对应,一般的队列接收函数也是由宏来实现,底层用一个函数来实现,队列接收函数有下面两个:

#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdTRUE )

#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdFALSE )

xQueuePeek与xQueueReceive的区别在于前者只接收而不删除条目,后者在成功接收后会删除原来的条目,两者均通过xQueueGenericReceive函数来实现,不能在中断中调用。

下面分析xQueueGenericReceive的实现方式:

signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
{
signed portBASE_TYPE xEntryTimeSet = pdFALSE;
xTimeOutType xTimeOut;
signed portCHAR *pcOriginalReadPosition;

    /* This function relaxes the coding standard somewhat to allow return
    statements within the function itself.  This is done in the interest
    of execution time efficiency. */

    for( ;; )
    {
        taskENTER_CRITICAL();
        {
              /* Is there space on the queue now?  To be running we must be
              the highest priority task wanting to access the queue. */        
            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 than this task. */
                            taskYIELD();
                        }
                    }

                }

                taskEXIT_CRITICAL();
                return pdPASS;
            }
            else  /*条目为空,如果xTicksToWait>0则插入到等待队列,否则直接返回,下面的操作跟队列发送时类似*/
            {
                if( xTicksToWait == ( portTickType ) 0 )
                {
                    /* The queue was empty and no block time is specified (or 
                    the block time has expired) so leave now. */                
                    taskEXIT_CRITICAL();
                    traceQUEUE_RECEIVE_FAILED( pxQueue );
                    return errQUEUE_EMPTY;
                }
                else if( xEntryTimeSet == pdFALSE )
                {
                    /* The queue was empty and a block time was specified so
                    configure the timeout structure. */                
                    vTaskSetTimeOutState( &xTimeOut );
                    xEntryTimeSet = pdTRUE;
                }
            }
        }
        taskEXIT_CRITICAL();

        /* Interrupts and other tasks can send to and receive from the queue
        now the critical section has been exited. */

        vTaskSuspendAll();
        prvLockQueue( pxQueue );

        /* Update the timeout state to see if it has expired yet. */
        if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
        {
            if( prvIsQueueEmpty( pxQueue ) )
            {
                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
            {
                /* Try again. */
                prvUnlockQueue( pxQueue );
                ( void ) xTaskResumeAll();
            }
        }
        else
        {
            prvUnlockQueue( pxQueue );
            ( void ) xTaskResumeAll();
            traceQUEUE_RECEIVE_FAILED( pxQueue );
            return errQUEUE_EMPTY;
        }
    }

}

0 0
原创粉丝点击