事件组
事件是用位图来表示存储的
事件位可以用来表明某个事件是否发生,事件的好处是可以一对多,多对一,一对一
一个任务可以同时等待好几个事件,同样也可以好几个任务等待同一个事件
事件组结构体
typedef struct xEventGroupDefinition
{
EventBits_t uxEventBits;
List_t xTasksWaitingForBits; /* 等待某个位变为1的任务列表 */
#if( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxEventGroupNumber;
#endif
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated; /* 静态方法标志位,手动释放内存 */
#endif
} EventGroup_t;
创建事件标志组
EventGroupHandle_t xEventGroupCreate( void )
{
EventGroup_t *pxEventBits;
/* 申请内存 */
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) );
if( pxEventBits != NULL )
{
pxEventBits->uxEventBits = 0;
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
pxEventBits->ucStaticallyAllocated = pdFALSE;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
traceEVENT_GROUP_CREATE_FAILED();
}
return ( EventGroupHandle_t ) pxEventBits;
}
申请内存,事件组的标志位和等待事件组列表初始化
清除事件标志位&获取事件标志组的值
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn;
configASSERT( xEventGroup );
configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
taskENTER_CRITICAL();
{
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
uxReturn = pxEventBits->uxEventBits;
/* 清楚位 */
pxEventBits->uxEventBits &= ~uxBitsToClear;
}
taskEXIT_CRITICAL();
return uxReturn;
}
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
等待事件组
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
{
/* xEventGroup:事件组结构体
uxBitsToWaitFor:等待事件位
xClearOnExit:是否清除事件位,pdTRUE则清除,pdFALSE不清除
xWaitForAllBits:是否等待所有的位,pdTRUE为事件均发生,pdFALSE表示至少一个事件发生
xTicksToWait:等待超时时间 */
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn, uxControlBits = 0;
BaseType_t xWaitConditionMet, xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
configASSERT( xEventGroup );
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 );
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
vTaskSuspendAll(); //关任务调度器
{
const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
/* 查看事件是否已满足 */
xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
if( xWaitConditionMet != pdFALSE )
{
/* 等待事件已经触发,无需等待 */
uxReturn = uxCurrentEventBits;
xTicksToWait = ( TickType_t ) 0;
/* 退出时是否清除位处理 */
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( xTicksToWait == ( TickType_t ) 0 )
{
/* 未满足,但是等待阻塞时间为0 */
uxReturn = uxCurrentEventBits;
}
else
{
/* 任务要阻塞等待事件触发 */
/* 利用uxControlBits的位存储事件位操作和事件的触发要求 */
if( xClearOnExit != pdFALSE )
{
uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( xWaitForAllBits != pdFALSE )
{
uxControlBits |= eventWAIT_FOR_ALL_BITS;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 将TCB中的事件列表项挂在事件组的等待列表下;事件列表项的value值设为uxControlBits
value值中,低24位(0-23)表示等待的事件位,第24位表示退出是否清除事件位,第26位表示是否等待所有事件位,第27位表示等待事件
将状态列表项移动到延时等待列表中 */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
uxReturn = 0;
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
}
}
/* 开启任务调度器 */
xAlreadyYielded = xTaskResumeAll();
if( xTicksToWait != ( TickType_t ) 0 )
{
/* 事件不满足,且有等待时间,任务需要阻塞 */
if( xAlreadyYielded == pdFALSE )
{
/* 确保执行一次任务切换,从当前任务切走 */
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 程序运行到这表示任务切换回来了,即超时了或者等到了事件位 */
/* 重置任务的事件列表项的value值,置为最大优先级-任务优先级 */
uxReturn = uxTaskResetEventItemValue();
/* 判断是因为超时还是等到了事件位 */
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
{
taskENTER_CRITICAL();
{
/* 超时了 */
uxReturn = pxEventBits->uxEventBits;
/* 再判断一下是否满足事件位,事件位可能再任务恢复之间更新 */
if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
{
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
xTimeoutOccurred = pdFALSE;
}
else
{
/* 任务唤醒已唤醒,因为满足了事件位 */
}
/* 任务被阻塞,因此可能设置了控制位 */
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
}
traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );
return uxReturn;
}
设置事件组标志位
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
{
ListItem_t *pxListItem, *pxNext;
ListItem_t const *pxListEnd;
List_t *pxList;
EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
BaseType_t xMatchFound = pdFALSE;
configASSERT( xEventGroup );
configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
pxList = &( pxEventBits->xTasksWaitingForBits );
pxListEnd = listGET_END_MARKER( pxList );
vTaskSuspendAll(); //挂起调度器
{
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
pxListItem = listGET_HEAD_ENTRY( pxList );
/* 设置事件标志位,将存储事件的变量置位 */
pxEventBits->uxEventBits |= uxBitsToSet;
/* 查看是否有因为新的事件位置一而可以取消阻塞的任务 */
while( pxListItem != pxListEnd )
{
pxNext = listGET_NEXT( pxListItem );
uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );
xMatchFound = pdFALSE;
/* 将value值分割,分为等待事件位部分和事件位设置部分 */
uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
{
/* 事件设置:事件是否满足任意一个 */
if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
{
xMatchFound = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
{
/* 事件设置:要求所有事件位均满足 */
xMatchFound = pdTRUE;
}
else
{
/* 不满足事件位要求 */
}
if( xMatchFound != pdFALSE )
{
/* 事件位满足要求 */
if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 ) //判断是否需要清除事件位
{
/* 如果需要清除,将需要清除的位记录下来 */
uxBitsToClear |= uxBitsWaitedFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 存储满足要求在任务事件列表项value值的第25位,同时将任务移到就绪列表中,根据优先级判断是否需要任务切换 */
( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
}
/* 检查下一个等待项 */
pxListItem = pxNext;
}
/* 退出时清除位,如果不需要清除或者无满足事件位组,uxBitsToClear为0 */
pxEventBits->uxEventBits &= ~uxBitsToClear;
}
( void ) xTaskResumeAll(); //开启调度器
return pxEventBits->uxEventBits;
}
任务通知
任务通知是一对一或者多对一的,一个任务可以接收任何任务发的通知,也可以向任何任务发送通知;任务通知是个事件
注:任务通知不能为0
发送任务通知:将TCB中的ulNotifiedValue元素按指定方式修改,同时修改TCB中任务通知小黄太,然后将阻塞的任务恢复到就绪列表中
接收任务通知:根据TCB中任务通知的状态和等待时间,将任务移到延时等待列表;如果切换回来,判断是否因为超时,超时返回0,接收到了通知返回接收到的通知值