FreeRTOS202212‐xTaskNotifyWait()与xTaskNotifyWaitIndexed()
xTaskNotifyWait()与xTaskNotifyWaitIndexed()函数用于实现全功能版的等待任务通知,根据用户指定的参
数的不同,可以灵活的用于实现轻量级的消息队列队列、二值信号量、计数信号量和事件组功能,并带有超时等待.
(引用自野火)
#define xTaskNotifyWait( ulBitsToClearOnEntry , ulBitsToClearOnExit , pulNotificationValue , xTicksToWait ) \
xTaskGenericNotifyWait (tskDEFAULT_INDEX_TO_NOTIFY,(ulBitsToClearOnEntry),(ulBitsToClearOnExit),(pulNotificationValue),(xTicksToWait))
#define xTaskNotifyWaitIndexed( uxIndexToWaitOn , ulBitsToClearOnEntry , ulBitsToClearOnExit , pulNotificationValue , xTicksToWait ) \
xTaskGenericNotifyWait ((uxIndexToWaitOn),(ulBitsToClearOnEntry),(ulBitsToClearOnExit),(pulNotificationValue),(xTicksToWait))
/*‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐*/
#if (configUSE_TASK_NOTIFICATIONS == 1 )
/*返回值pdTRUE:等待任务通知成功pdFALSE:等待任务通知失败*/
BaseType_t xTaskGenericNotifyWait ( UBaseType_t uxIndexToWait , /*任务通知数组的索引值(任务通知相关数组下标)*/
uint32_t ulBitsToClearOnEntry , /*等待前指定清零的任务通知通知值比特位*/
uint32_t ulBitsToClearOnExit , /*成功等待后指定清零的任务通知通知值比特位*/
uint32_t * pulNotificationValue , /*要获取的通知值(队列消息或者事件组)*/
TickType_t xTicksToWait ) /*阻塞状态下等待接收通知的最长时间*/
{
BaseType_t xReturn ;
/*数组越界检测*/
configASSERT ( uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES );
taskENTER_CRITICAL ();
{
/*Onlyblockifanotificationisnotalreadypending.*/ /*仅当通知尚未挂起时阻止*/
/*若不为等待接收通知状态,说明其他任务没有发送通知给该任务.如果设置了超时时间,则任务需要进入阻塞态*/
if ( pxCurrentTCB ‐> ucNotifyState [ uxIndexToWait ]!= taskNOTIFICATION_RECEIVED )
{
/*Clearbitsinthetask'snotificationvalueasbitsmaygetsetbythenotifyingtaskorinterrupt.
Thiscanbeusedtoclearthevaluetozero.*/
/*等待通知前清除任务通知值中的位,因为通知任务或中断可能会设置位。这可用于将值清除为零。*/
pxCurrentTCB ‐> ulNotifiedValue [ uxIndexToWait ]&=~ ulBitsToClearOnEntry ;
/*Markthistaskaswaitingforanotification.*/
/*设置任务通知的状态为等待通知状态*/
pxCurrentTCB ‐> ucNotifyState [ uxIndexToWait ]= taskWAITING_NOTIFICATION ;
/*如果允许阻塞*/
if ( xTicksToWait >( TickType_t ) 0 )
{
/*设置任务通知的状态为等待通知状态*/
prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE );
traceTASK_NOTIFY_WAIT_BLOCK ( uxIndexToWait );
/*Allportsarewrittentoallowayieldinacriticalsection(somewillyieldimmediately,otherswaituntilthecriticalsectionexits)‐butitisnotsomethingthatapplicationcodeshouldeverdo.*/
/*所有端口都被编写为允许在临界段中进行屈服(有些端口将立即屈服,另一些端口则等待关键部分退出),但这不是应用程序代码应该做的事情*/
/*悬起PendSv中断,准备进行任务切换*/
portYIELD_WITHIN_API ();
}
else
{
mtCOVERAGE_TEST_MARKER ();
}
}
else
{
mtCOVERAGE_TEST_MARKER ();
}
}
taskEXIT_CRITICAL ();
/*如果该任务被阻塞了,解除阻塞后继续从这往下执行*/
taskENTER_CRITICAL ();
{
traceTASK_NOTIFY_WAIT ( uxIndexToWait );
/*当代码执行到这里可能是以下三种情况:
1.前面的判断不成立,一进来就有通知任务不需要进入阻塞
2.前面的判断成立,任务进入阻塞,但是有其他任务向该任务发送通知并将该任务唤醒
3.前面的判断成立,任务进入阻塞,但是阻塞超时任务被迫唤醒*/
if ( pulNotificationValue != NULL )
{
/*Outputthecurrentnotificationvalue,whichmayormaynothavechanged.*/
/*输出当前通知值,该值可能已更改,也可能未更改.
未更改说明是任务是超时被唤醒的此时虽然能获取通知值,但是通知值是上次的,其实是获取通知值失败的*/
* pulNotificationValue = pxCurrentTCB ‐> ulNotifiedValue [ uxIndexToWait ];
}
/*IfucNotifyValueissettheneitherthetaskneverenteredtheblockedstate(becauseanotificationwasalreadypending)orthetaskunblockedbecauseofanotification.
Otherwisethetaskunblockedbecauseofatimeout.*/
/*如果设置了ucNotifyValue,则任务从未进入阻止状态(因为通知已挂起),或者由于通知到达而取消任务阻塞。
否则,由于超时,任务被取消阻止*/
/*如果任务通知的状态还不等于等待接收通知状态的话,说明任务还是没有接收到通知任务只不过是超时被唤醒*/
if ( pxCurrentTCB ‐> ucNotifyState [ uxIndexToWait ]!= taskNOTIFICATION_RECEIVED )
{
/*Anotificationwasnotreceived.*/ /*未收到通知*/
xReturn = pdFALSE ;
}
else
{
/*Anotificationwasalreadypendingoranotificationwasreceivedwhilethetaskwaswaiting.*/
/*通知已挂起,或者在任务等待时收到通知*/
/*在成功接收到通知后将通知值的指定比特位清零*/
pxCurrentTCB ‐> ulNotifiedValue [ uxIndexToWait ]&=~ ulBitsToClearOnExit ;
xReturn = pdTRUE ;
}
/*不论接收通知成功或者失败都将任务通知的状态标记为未等待通知状态*/
pxCurrentTCB ‐> ucNotifyState [ uxIndexToWait ]= taskNOT_WAITING_NOTIFICATION ;
}
taskEXIT_CRITICAL ();
return xReturn ;
}
#endif /*configUSE_TASK_NOTIFICATIONS*/
/*‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐*/
#define xTaskNotifyWait( ulBitsToClearOnEntry , ulBitsToClearOnExit , pulNotificationValue , xTicksToWait ) \
xTaskGenericNotifyWait (tskDEFAULT_INDEX_TO_NOTIFY,(ulBitsToClearOnEntry),(ulBitsToClearOnExit),(pulNotificationValue),(xTicksToWait))
#define xTaskNotifyWaitIndexed( uxIndexToWaitOn , ulBitsToClearOnEntry , ulBitsToClearOnExit , pulNotificationValue , xTicksToWait ) \
xTaskGenericNotifyWait ((uxIndexToWaitOn),(ulBitsToClearOnEntry),(ulBitsToClearOnExit),(pulNotificationValue),(xTicksToWait))
/*返回值pdTRUE:等待任务通知成功pdFALSE:等待任务通知失败*/
BaseType_t xTaskGenericNotifyWait ( UBaseType_t uxIndexToWait , /*任务的指定通知(任务通知相关数组下标)*/
uint32_t ulBitsToClearOnEntry , /*等待前指定清零的任务通知通知值比特位*/
uint32_t ulBitsToClearOnExit , /*成功等待后指定清零的任务通知通知值比特位*/
uint32_t * pulNotificationValue , /*要获取的通知值(队列消息或者事件组)*/
TickType_t xTicksToWait ) /*阻塞等待任务通知值的最大时间*/
功能
xTaskNotifyWait()会等待调用任务接收通知,并有可选的超时。
如果等待的通知到达时,相关的接收RTOS任务已被阻塞且正在等待通知,则接收RTOS任务将解除阻塞,通知也将清除。
参数
uxIndexToWaitOn
调用任务的数组中通知值的索引,调用任务将在该通知值上等待接收通知。
uxIndexToWaitOn必须小于configTASK_NOTIFICATION_ARRAY_ENTRIES。
xTaskNotifyWait()没有此参数,总是在索引0处等待通知。
ulBitsToClearOnEntry
在xTaskNotifyWait()函数入口,ulBitsToClearOnEntry中设置的任何位都将在调用RTOS任务通知值中被清除(在任务等待新通知之前),前提是在
调用xTaskNotifyWait()时通知尚未挂起。
例如,如果ulBitsToClearOnEntry为0x01,则任务通知值的位0将在函数入口被清除。
将ulBitsToClearOnEntry设置为0xffffffff(ULONG_MAX)将清除任务通知值中的所有位,有效将值清除为0。
ulBitsToClearOnExit
在xTaskNotifyWait()函数退出之前,ulBitsToClearOnExit中设置的任何位都将在调用RTOS任务通知值中被清除,前提是接收到通知。
在RTOS任务通知值保存到*pulNotificationValue中之后清除位(请参阅下面的pulNotificationValue的说明)。
例如,如果ulBitsToClearOnExit为0x03,则位0和位1将在函数退出之前清除。
将ulBitsToClearOnExit设置为0xffffffff(ULONG_MAX)将清除任务通知值中的所有位,有效将值清除为0。
pulNotificationValue
用于传出RTOS任务的通知值。
在由于ulBitsToClearOnExit的设置清除任何位之前,复制到*pulNotificationValue的值是RTOS任务的通知值。
如果不需要通知值,则设置pulNotificationValue为NULL。
xTicksToWait
在阻塞状态下等待接收通知的最长时间,前提是在调用xTaskNotifyWait()时通知尚未挂起。
处于阻塞状态的RTOS任务不会消耗任何CPU时间。
时间以RTOStick周期为单位。宏pdMS_TO_TICKS()可以将以毫秒为单位的时间转换为以tick为单位的时间。
返回值
pdTRUE:发送命令成功
pdFAIL:发送命令失败
假设当我们要在某个任务或任务中去启动一个定时器,我们需要往定时器消息队列发送一个命令(即写一个消息到队列中),而守护任务则时刻读取队列消息,然后执行这些命令,因为定时器的命令不止一
个,则每个消息都有一个命令ID,以便守护任务读取到消息之后判断需要执行什么命令。
定时器的启动、复位、停止、更改周期、删除的宏函数,它们最终都是调用了xTimerGenericCommand()函数。进一步细分为任务中调用,中断中调用的这些函数(FromISR后缀)。
xTaskGenericNotifyWait ()
定义返回值变量
BaseType_t xReturn ;
进入临界段
taskENTER_CRITICAL ();
栈顶*pxTopOfStack
volatile(portSTACK_TYPE)uint32_t(StackType_t)
xStateListItem
xEventListItem
任务栈起始地址*pxStack
任务名称,仅用于调试,字符串形式pcTaskName[configMAX_TASK_NAME_LEN]
uint8_t(char)
ulNotifiedValue [configTASK_NOTIFICATION_ARRAY_ENTRIES]
任务通知功能
volatileuint32_t
ucNotifyState [configTASK_NOTIFICATION_ARRAY_ENTRIES]
任务通知功能
volatileuint8_t
ucStaticallyAllocated
支持静态&动态内存
uint8_t
*pxTopOfStack
xLIST_ITEM(ListItem_t)
xStateListItem
xLIST_ITEM(ListItem_t)
xEventListItem
UBaseType_t(unsignedlong)
优先级
uxPriority=
*pxStack
volatile(portSTACK_TYPE)uint32_t(StackType_t)
pcTaskName [configMAX_TASK_NAME_LEN]
xItemValue
*pxNext
*pxPrevious
*pvOwner
*pvContainer
内核对象
链表对象
void
void
structxLIST_ITEM
structxLIST_ITEM
uint32_t/uint16_t(TickType_t)
节点排序值
tskTaskControlBlock(tskTCB)(TCB_t)
xMPUSettings
#if(portUSING_MPU_WRAPPERS==1)
xItemValue
*pxNext
*pxPrevious
*pvOwner
*pvContainer
内核对象
链表对象
void
void
structxLIST_ITEM
structxLIST_ITEM
uint32_t/uint16_t(TickType_t)
节点排序值
指向堆栈的最高有效地址
volatile(portSTACK_TYPE)uint32_t(StackType_t)
*pxEndOfStack
#if(portSTACK_GROWTH>0)
UBaseType_t(unsignedlong)
uxCriticalNesting
portCRITICAL_NESTING_IN_TCB==1
UBaseType_t(unsignedlong)
uxTCBNumber
#if(configUSE_TRACE_FACILITY==1)
UBaseType_t(unsignedlong)
uxTaskNumber
#if(configUSE_TRACE_FACILITY==1)
UBaseType_t(unsignedlong)
uxBasePriority
#if(configUSE_MUTEXES==1)
UBaseType_t(unsignedlong)
xxx
uxMutexesHeld
#if(configUSE_MUTEXES==1)
函数指针
(*)pxTaskTag
#if(configUSE_APPLICATION_TASK_TAG==1)
typedefBaseType_t(*TaskHookFunction_t)(void*)
xxx
*pvThreadLocalStoragePointers[configNUM_THREAD_LOCAL_STORAGE_POINTERS]
#if(configNUM_THREAD_LOCAL_STORAGE_POINTERS>0)
void
存储任务在“正在运行”状态下花费的时间
ulRunTimeCounter
#if(configGENERATE_RUN_TIME_STATS==1)
uint32_t
xxx
configTLS_BLOCK_TYPE xTLSBlock; /*
为任务分配一个
Newlibreent
结构体变量。
Newlib
是一个
C
库函数,并非
FreeRTOS
维护,
FreeRTOS
也不对使用结果负责。如果用户使用
Newlib
,必须熟知
Newlib
的细节
*/
#if((configUSE_NEWLIB_REENTRANT==1)||(configUSE_C_RUNTIME_TLS_SUPPORT==1))
struct_reent
xNewLib_reent
#if(configUSE_TASK_NOTIFICATIONS==1)
#if(configUSE_TASK_NOTIFICATIONS==1)
#if(tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE!=0)
ucDelayAborted
xxx
uint8_t
#if(INCLUDE_xTaskAbortDelay==1)
ulRLAR
ulRBAR
structMPURegionSettings(MPURegionSettings_t)
uint32_t
structMPU_SETTINGS(xMPU_SETTINGS)
ulMAIR0
uint32_t
uint32_t
xRegionsSettings[portTOTAL_NUM_REGIONS]
指向链表下一个节点
指向链表前一个节点
指向链表下一个节点
指向链表前一个节点
临界区嵌套深度
存储每次创建TCB时递增的数字
存储专门供第三方跟踪代码使用的数字
上次分配给任务的优先级‐由优先级继承机制使用
iTaskErrno
xxx
int
#if(configUSE_POSIX_ERRNO==1)
*
pxCurrentTCB
当前任务没有收到任务通知 ?
if ( pxCurrentTCB ‐> ucNotifyState [ uxIndexToWait ]!= taskNOTIFICATION_RECEIVED )
没收到通知
收到通知
清除当前任务等待通知变量的等待位
pxCurrentTCB ‐> ulNotifiedValue [ uxIndexToWait ]&=~ ulBitsToClearOnEntry ;
设置任务通知的状态为等待通知状态
pxCurrentTCB ‐> ucNotifyState [ uxIndexToWait ]= taskWAITING_NOTIFICATION ;
任务允许阻塞 ?
if ( xTicksToWait >( TickType_t ) 0 )
允许
不允许
当前任务移动到延时(挂起)链表
prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE );
悬起PendSv中断,准备进行任务切换
portYIELD_WITHIN_API ();
退出临界区
taskEXIT_CRITICAL ();
进入临界段
taskENTER_CRITICAL ();
要获取的通知值非空 ?
if ( pulNotificationValue != NULL )
非空
空
输出当前任务重的通知值
* pulNotificationValue = pxCurrentTCB ‐> ulNotifiedValue [ uxIndexToWait ];
当前任务没有收到任务通知 ?
if ( pxCurrentTCB ‐> ucNotifyState [ uxIndexToWait ]!= taskNOTIFICATION_RECEIVED )
没收到通知
收到通知
复位返回值
xReturn = pdFALSE ;
将通知值的指定比特位清零
pxCurrentTCB ‐> ulNotifiedValue [ uxIndexToWait ]&=~ ulBitsToClearOnExit ;
置位返回值
xReturn = pdTRUE ;
任务通知的状态标记为未等待通知状态
pxCurrentTCB ‐> ucNotifyState [ uxIndexToWait ]= taskNOT_WAITING_NOTIFICATION ;
退出临界区
taskEXIT_CRITICAL ();
结束返回
return xReturn ;