硬汉嵌入式论坛

 找回密码
 立即注册
查看: 10884|回复: 9
收起左侧

[FreeRTOS] 【ERIC2013原创】FreeRTOS  V7.4.2 详细源码分析之(1)-----------消息

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106982
QQ
发表于 2013-6-18 14:43:31 | 显示全部楼层 |阅读模式
创建消息队列
说明:(1)FreeRTOS的源码风格看起来好难受,不便于阅读,没有UCOS的风格好。
            (2)这段时间要做一下各个OS的对比数据,比较烦人,而且很麻烦,顺便就做一下源码的分析
/**
* queue. h
* <pre>
xQueueHandle xQueueCreate(
                              unsigned portBASE_TYPE uxQueueLength,
                              unsigned portBASE_TYPE uxItemSize
                          );
* </pre>
*
* Creates a new queue instance.  This allocates the storage required by the
* new queue and returns a handle for the queue.
*
* @param uxQueueLength The maximum number of items that the queue can contain.
*
* @param uxItemSize The number of bytes each item in the queue will require.
* Items are queued by copy, not by reference, so this is the number of bytes
* that will be copied for each posted item.  Each item on the queue must be
* the same size.
*
* @return If the queue is successfully create then a handle to the newly
* created queue is returned.  If the queue cannot be created then 0 is
* returned.
*
* Example usage:
   <pre>
struct AMessage
{
    char ucMessageID;
    char ucData[ 20 ];
};

void vATask( void *pvParameters )
{
xQueueHandle xQueue1, xQueue2;

    // Create a queue capable of containing 10 unsigned long values.
    xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );
    if( xQueue1 == 0 )
    {
        // Queue was not created and must not be used.
    }

    // Create a queue capable of containing 10 pointers to AMessage structures.
    // These should be passed by pointer as they contain a lot of data.
    xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
    if( xQueue2 == 0 )
    {
        // Queue was not created and must not be used.
    }

    // ... Rest of task code.
}

xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, //The maximum number of items that the queue can contain
                                  unsigned portBASE_TYPE uxItemSize,                                     //The number of bytes each item in the queue will require
                                  unsigned char ucQueueType )
{
xQUEUE *pxNewQueue;
size_t xQueueSizeInBytes;
xQueueHandle xReturn = NULL;   //创建失败返回 NULL

    /* Remove compiler warnings about unused parameters should
    configUSE_TRACE_FACILITY not be set to 1. */
    /*  防止编译警告  */
    ( void ) ucQueueType;

    /* Allocate the new queue structure. */
    /* 从动态内存申请新的队列和队列所需的内存空间 */
    if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
    {
       /* 从内存申请xQUEUE结构体所需的内存 */
        pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
        if( pxNewQueue != NULL )
        {
            /* Create the list of pointers to queue items.  The queue is one byte
            longer than asked for to make wrap checking easier/faster. */
            /* 计算申请队列大小内存+1*/
            xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;

            /* 申请内存 */
            pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes );

            if( pxNewQueue->pcHead != NULL )
            {
                /* Initialise the queue members as described above where the
                queue type is defined. */
                pxNewQueue->uxLength = uxQueueLength;
                pxNewQueue->uxItemSize = uxItemSize;
                初始化队列结构体的一些参数
                xQueueGenericReset( pxNewQueue, pdTRUE );

                #if ( configUSE_TRACE_FACILITY == 1 )
                {
                    pxNewQueue->ucQueueType = ucQueueType;
                }
                #endif /* configUSE_TRACE_FACILITY */

                #if( configUSE_QUEUE_SETS == 1 )
                {
                    pxNewQueue->pxQueueSetContainer = NULL;
                }
                #endif /* configUSE_QUEUE_SETS */

                traceQUEUE_CREATE( pxNewQueue );
                创建成功,返回队列句柄。
                xReturn = pxNewQueue;
            }
            /* 如果申请失败,释放刚才申请的队列结构体需要的内存 */
            else
            {
                traceQUEUE_CREATE_FAILED( ucQueueType );
                vPortFree( pxNewQueue );
            }
        }
    }
    configASSERT( xReturn )
    return xReturn;
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106982
QQ
 楼主| 发表于 2013-6-18 15:06:38 | 显示全部楼层
/*
* Definition of the queue used by the scheduler.
* Items are queued by copy, not reference.

*/
typedef struct QueueDefinition
{
    signed char *pcHead;                /*< Points to the beginning of the queue storage area. */
    signed char *pcTail;                    /*< Points to the byte at the end of the queue storage area.  Once more byte is allocated than necessary to store the queue items,
                                                             this is used as a marker. */

    signed char *pcWriteTo;             /*< Points to the free next place in the storage area. */
    signed char *pcReadFrom;        /*< Points to the last place that a queued item was read from. */

    xList xTasksWaitingToSend;       /*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */
    xList xTasksWaitingToReceive;   /*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */

    volatile unsigned portBASE_TYPE uxMessagesWaiting; /*< The number of items currently in the queue. */
    unsigned portBASE_TYPE uxLength;                               /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
    unsigned portBASE_TYPE uxItemSize;                            /*< The size of each items that the queue will hold. */
    volatile signed portBASE_TYPE xRxLock;                        /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked.  
                                                                                                 Set to queueUNLOCKED when the queue is not locked. */
    volatile signed portBASE_TYPE xTxLock;                        /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked.
                                                                                                 Set to queueUNLOCKED when the queue is not locked. */
    #if ( configUSE_TRACE_FACILITY == 1 )
        unsigned char ucQueueNumber;
        unsigned char ucQueueType;
    #endif
    #if ( configUSE_QUEUE_SETS == 1 )
        struct QueueDefinition *pxQueueSetContainer;
    #endif
} xQUEUE;

portBASE_TYPE xQueueGenericReset( xQueueHandle xQueue, portBASE_TYPE xNewQueue )
{
xQUEUE *pxQueue;
    pxQueue = ( xQUEUE * ) xQueue;
    configASSERT( pxQueue );
    taskENTER_CRITICAL();
    {
        初始化队列结构体中相应的项
        pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize );
        pxQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;
        pxQueue->pcWriteTo = pxQueue->pcHead;
        pxQueue->pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( unsigned portBASE_TYPE ) 1U ) * pxQueue->uxItemSize );
        pxQueue->xRxLock = queueUNLOCKED;
        pxQueue->xTxLock = queueUNLOCKED;
       //如果有任务要写队列或读对了,要进入到这个里面
        if( xNewQueue == pdFALSE )
        {
            /* If there are tasks blocked waiting to read from the queue, then
            the tasks will remain blocked as after this function exits the queue
            will still be empty.  If there are tasks blocked waiting to    write to
            the queue, then one should be unblocked as after this function exits
            it will be possible to write to it. */
            if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
            {
                if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
                {
                    portYIELD_WITHIN_API();
                }
            }
        }
        else
        {
            //消息队列创建后,要进入到这个里面
            /* Ensure the event queues start in the correct state. */
            vListInitialise( &( pxQueue->xTasksWaitingToSend ) );
            vListInitialise( &( pxQueue->xTasksWaitingToReceive ) );
        }
    }
    taskEXIT_CRITICAL();
    /* A value is returned for calling semantic consistency with previous
    versions. */
    return pdPASS;
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106982
QQ
 楼主| 发表于 2013-6-18 18:34:40 | 显示全部楼层
向队列发送消息
signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue,
                                        const void * const pvItemToQueue,
                                        portTickType xTicksToWait,
                                        portBASE_TYPE xCopyPosition )     //queueSEND_TO_BACK  固定的
{
signed portBASE_TYPE xEntryTimeSet = pdFALSE;
xTimeOutType xTimeOut;
xQUEUE *pxQueue;
    pxQueue = ( xQUEUE * ) xQueue;
    configASSERT( pxQueue );
    configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
    /* 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 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 );

                #if ( configUSE_QUEUE_SETS == 1 )
                {
                    if( pxQueue->pxQueueSetContainer != NULL )
                    {
                        if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE )
                        {
                            /* The queue is a member of a queue set, and posting
                            to the queue set caused a higher priority task to
                            unblock. A context switch is required. */
                            portYIELD_WITHIN_API();
                        }
                    }
                    else
                    {
                        /* 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.  Yes it is ok to
                                do this from within the critical section - the
                                kernel takes care of that. */
                                portYIELD_WITHIN_API();
                            }
                        }
                    }
                }
                #else /* configUSE_QUEUE_SETS */
                {
                    /* 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.  Yes it is ok to do
                            this from within the critical section - the kernel
                            takes care of that. */
                            portYIELD_WITHIN_API();
                        }
                    }
                }
                #endif /* configUSE_QUEUE_SETS */
                taskEXIT_CRITICAL();
                /* Return to the original privilege level before exiting the
                function. */
                return pdPASS;
            }
            //如果消息队列已经满了,进入到这里
            else
            {
                if( xTicksToWait == ( portTickType ) 0 )
                {
                    /* The queue was full and no block time is specified (or
                    the block time has expired) so leave now. */
                    taskEXIT_CRITICAL();

                    /* Return to the original privilege level before exiting
                    the function. */
                    traceQUEUE_SEND_FAILED( pxQueue );
                    return errQUEUE_FULL;
                }
                else if( xEntryTimeSet == pdFALSE )
                {
                    /* The queue was full 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( prvIsQueueFull( pxQueue ) != 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() == pdFALSE )
                {
                    portYIELD_WITHIN_API();
                }
            }
            //队列没有满
            else
            {
                /* Try again. */
                prvUnlockQueue( pxQueue );
                ( void ) xTaskResumeAll();
            }
        }
        //时间到期
        else
        {
            /* The timeout has expired. */
            prvUnlockQueue( pxQueue );
            ( void ) xTaskResumeAll();
            /* Return to the original privilege level before exiting the
            function. */
            traceQUEUE_SEND_FAILED( pxQueue );
            return errQUEUE_FULL;
        }
    }
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106982
QQ
 楼主| 发表于 2013-6-18 18:50:48 | 显示全部楼层
/*
* xQueueAltGenericSend() is an alternative version of xQueueGenericSend().
* Likewise xQueueAltGenericReceive() is an alternative version of
* xQueueGenericReceive().
*
* The source code that implements the alternative (Alt) API is much
* simpler    because it executes everything from within a critical section.
* 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 much less use of
* critical sections.  Therefore the alternative API sacrifices interrupt
* responsiveness to gain execution speed, whereas the fully featured API
* sacrifices execution speed to ensure better interrupt responsiveness.

*/
xQueueAltGenericSend 和前面那个全功能的Send API差不多
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106982
QQ
 楼主| 发表于 2013-6-18 19:19:00 | 显示全部楼层
从ISR中向消息队列里面发送数据
/**
* queue. h
* <pre>
portBASE_TYPE xQueueGenericSendFromISR(
                                           xQueueHandle        xQueue,
                                           const    void    *pvItemToQueue,
                                           portBASE_TYPE    *pxHigherPriorityTaskWoken,
                                           portBASE_TYPE    xCopyPosition
                                       );
</pre>
*
* It is preferred that the macros xQueueSendFromISR(),
* xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place
* of calling this function directly.
*
* Post an item on a queue.  It is safe to use this function from within an
* interrupt service routine.
*
* Items are queued by copy not reference so it is preferable to only
* queue small items, especially when called from an ISR.  In most cases
* it would be preferable to store a pointer to the item being queued.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvItemToQueue A pointer to the item that is to be placed on the
* queue.  The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from pvItemToQueue
* into the queue storage area.
*
* @param pxHigherPriorityTaskWoken xQueueGenericSendFromISR() will set
* *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task
* to unblock, and the unblocked task has a priority higher than the currently
* running task.  If xQueueGenericSendFromISR() sets this value to pdTRUE then
* a context switch should be requested before the interrupt is exited.
*
* @param xCopyPosition Can take the value queueSEND_TO_BACK to place the
* item at the back of the queue, or queueSEND_TO_FRONT to place the item
* at the front of the queue (for high priority messages).
*
* @return pdTRUE if the data was successfully sent to the queue, otherwise
* errQUEUE_FULL.
*
* Example usage for buffered IO (where the ISR can obtain more than one value
* per call):
   <pre>
程序里面带的例子
void vBufferISR( void )
{
char cIn;
portBASE_TYPE xHigherPriorityTaskWokenByPost;

    // We have not woken a task at the start of the ISR.
    xHigherPriorityTaskWokenByPost = pdFALSE;

    // Loop until the buffer is empty.
    do
    {
        // Obtain a byte from the buffer.
        cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
        // Post each byte.
        xQueueGenericSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWokenByPost, queueSEND_TO_BACK );
    } while( portINPUT_BYTE( BUFFER_COUNT ) );

    // Now the buffer is empty we can switch context if necessary.  Note that the
    // name of the yield function required is port specific.
    if( xHigherPriorityTaskWokenByPost )
    {
        taskYIELD_YIELD_FROM_ISR();
    }
}

signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle xQueue,
                                               const void * const pvItemToQueue,
                                               signed portBASE_TYPE *pxHigherPriorityTaskWoken,
                                               portBASE_TYPE xCopyPosition )
{
signed portBASE_TYPE xReturn;
unsigned portBASE_TYPE uxSavedInterruptStatus;
xQUEUE *pxQueue;

    pxQueue = ( xQUEUE * ) xQueue;
    configASSERT( pxQueue );
    configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );

    /* Similar to xQueueGenericSend, except we don't block if there is no room
    in the queue.  Also we don't directly wake a task that was blocked on a
    queue read, instead we return a flag to say whether a context switch is
    required or not (i.e. has a task with a higher priority than us been woken
    by this    post). */
    //和xQueueGenericSend类似,只是没有可用的队列空间的时候,不会阻塞
    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
        {
            traceQUEUE_SEND_FROM_ISR( pxQueue );      
            //将数据复制到相应的队列里面
            prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
            //如果xTxLock被锁了,那么队列解锁以后再执行
            /* If the queue is locked we do not alter the event list.  This will
            be done when the queue is unlocked later. */
            if( pxQueue->xTxLock == queueUNLOCKED )
            {
                #if ( configUSE_QUEUE_SETS == 1 )
                {
                    if( pxQueue->pxQueueSetContainer != NULL )
                    {
                        if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE )
                        {
                            /* The queue is a member of a queue set, and posting
                            to the queue set caused a higher priority task to
                            unblock.  A context switch is required. */
                            if( pxHigherPriorityTaskWoken != NULL )
                            {
                                *pxHigherPriorityTaskWoken = pdTRUE;
                            }
                        }
                    }
                    else
                    {
                        if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                        {
                            if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                            {
                                /* The task waiting has a higher priority so record that a
                                context    switch is required. */
                                if( pxHigherPriorityTaskWoken != NULL )
                                {
                                    *pxHigherPriorityTaskWoken = pdTRUE;
                                }
                            }
                        }
                    }
                }
                #else /* configUSE_QUEUE_SETS */
                {
                    if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                    {
                        if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                        {
                            /* The task waiting has a higher priority so record that a
                            context    switch is required. */
                            if( pxHigherPriorityTaskWoken != NULL )
                            {
                                *pxHigherPriorityTaskWoken = pdTRUE;
                            }
                        }
                    }
                }
                #endif /* configUSE_QUEUE_SETS */
            }
            else
            {
                //
                /* Increment the lock count so the task that unlocks the queue
                knows that data was posted while it was locked. */
                ++( pxQueue->xTxLock );
            }

            xReturn = pdPASS;
        }
       //队列已经满了
        else
        {
            traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
            xReturn = errQUEUE_FULL;
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
    return xReturn;
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106982
QQ
 楼主| 发表于 2013-6-18 21:17:10 | 显示全部楼层
/**
* queue. h
* <pre>
portBASE_TYPE xQueueGenericReceive(
                                       xQueueHandle    xQueue,
                                       void    *pvBuffer,
                                       portTickType    xTicksToWait
                                       portBASE_TYPE    xJustPeek
                                    );</pre>
*
* It is preferred that the macro xQueueReceive() be used rather than calling
* this function directly.
*
* Receive an item from a queue.  The item is received by copy so a buffer of
* adequate size must be provided.  The number of bytes copied into the buffer
* was defined when the queue was created.
*
* This function must not be used in an interrupt service routine.  See
* xQueueReceiveFromISR for an alternative that can.
*
* @param xQueue The handle to the queue from which the item is to be
* received.
*
* @param pvBuffer Pointer to the buffer into which the received item will
* be copied.
*
* @param xTicksToWait The maximum amount of time the task should block
* waiting for an item to receive should the queue be empty at the time
* of the call.     The time is defined in tick periods so the constant
* portTICK_RATE_MS should be used to convert to real time if this is required.
* xQueueGenericReceive() will return immediately if the queue is empty and
* xTicksToWait is 0.
*
* @param xJustPeek When set to true, the item received from the queue is not
* actually removed from the queue - meaning a subsequent call to
* xQueueReceive() will return the same item.  When set to false, the item
* being received from the queue is also removed from the queue.
*
* @return pdTRUE if an item was successfully received from the queue,
* otherwise pdFALSE.
*
* Example usage:
   <pre>
struct AMessage
{
    char ucMessageID;
    char ucData[ 20 ];
} xMessage;

xQueueHandle xQueue;

// Task to create a queue and post a value.
void vATask( void *pvParameters )
{
struct AMessage *pxMessage;
    // Create a queue capable of containing 10 pointers to AMessage structures.
    // These should be passed by pointer as they contain a lot of data.
    xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
    if( xQueue == 0 )
    {
        // Failed to create the queue.
    }
    // ...
    // Send a pointer to a struct AMessage object.  Don't block if the
    // queue is already full.
    pxMessage = & xMessage;
    xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );

    // ... Rest of task code.
}

// Task to receive from the queue.
void vADifferentTask( void *pvParameters )
{
struct AMessage *pxRxedMessage;

    if( xQueue != 0 )
    {
        // Receive a message on the created queue.  Block for 10 ticks if a
        // message is not immediately available.
        if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
        {
            // pcRxedMessage now points to the struct AMessage variable posted
            // by vATask.
        }
    }
    // ... Rest of task code.
}

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

    pxQueue = ( xQUEUE * ) xQueue;
    configASSERT( pxQueue );
    configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );

    /* 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 data in 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 );               
                //下面的xJustPeeking设置将从队列中删除读取后的数据
                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 )
                        {
                            portYIELD_WITHIN_API();
                        }
                    }
                }
                else
                {
                    traceQUEUE_PEEK( pxQueue );

                    /* The data is not being removed, so reset the 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 ) ) == pdFALSE )
                    {
                        /* 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. */
                            portYIELD_WITHIN_API();
                        }
                    }
                }

                taskEXIT_CRITICAL();
                return pdPASS;
            }
            //队列中没有数据
            else
            {
                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 ) != 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() == pdFALSE )
                {
                    portYIELD_WITHIN_API();
                }
            }
            else
            {
                /* Try again. */
                prvUnlockQueue( pxQueue );
                ( void ) xTaskResumeAll();
            }
        }
        //超时
        else
        {
            prvUnlockQueue( pxQueue );
            ( void ) xTaskResumeAll();
            traceQUEUE_RECEIVE_FAILED( pxQueue );
            return errQUEUE_EMPTY;
        }
    }
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106982
QQ
 楼主| 发表于 2013-6-18 21:19:07 | 显示全部楼层
/*
* xQueueAltGenericSend() is an alternative version of xQueueGenericSend().
* Likewise xQueueAltGenericReceive() is an alternative version of
* xQueueGenericReceive().
*
* The source code that implements the alternative (Alt) API is much
* simpler    because it executes everything from within a critical section.
* 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 much less use of
* critical sections.  Therefore the alternative API sacrifices interrupt
* responsiveness to gain execution speed, whereas the fully featured API
* sacrifices execution speed to ensure better interrupt responsiveness.

*/
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106982
QQ
 楼主| 发表于 2013-6-18 21:34:01 | 显示全部楼层
从中断中发送消息
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle xQueue, void * const pvBuffer, signed portBASE_TYPE *pxHigherPriorityTaskWoken )
{
signed portBASE_TYPE xReturn;
unsigned portBASE_TYPE uxSavedInterruptStatus;
xQUEUE *pxQueue;

    pxQueue = ( xQUEUE * ) xQueue;
    configASSERT( pxQueue );
    configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );

    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. */
            //如果xRxLock锁住了,那么将在后面再执行
            if( pxQueue->xRxLock == queueUNLOCKED )
            {
                if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
                {
                    if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
                    {
                        /* The task waiting has a higher priority than us so
                        force a context switch. */
                        if( pxHigherPriorityTaskWoken != NULL )
                        {
                            *pxHigherPriorityTaskWoken = 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;
}
回复

使用道具 举报

4

主题

81

回帖

4

积分

初级会员

积分
4
发表于 2014-4-5 08:25:52 | 显示全部楼层
版主好好研究下,也写本类似“邵贝贝ucos“的经典书。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106982
QQ
 楼主| 发表于 2014-4-5 08:54:57 | 显示全部楼层

回 astudent 的帖子

astudent:版主好好研究下,也写本类似“邵贝贝ucos“的经典书。 (2014-04-05 08:25) 
那本书是翻译的官方手册
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-13 09:08 , Processed in 0.203697 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表