RTOS事件标志组
概述
事件标志组是为了方便在ISR与任务之间传递事件标志,事件标志就是一个bool值,来指示事件是否发生。例如:一个任务运行一段时间后需要等待一个按键输入(事件标志)才能继续运行,而ISR中则可以检测到这个按键输入(事件标志),我们需要一种功能,将这样的事件标志进行传递。(信号量,邮箱的合理使用也是可以实现这种功能的) 有些任务可能需要等待多个事件标志才能继续运行,这个时候就需要一组事件标志。
设计原理
- 每个任务都持有它需要等待的任务的集合
- 事件未发生时(事件标志为0)则任务在事件标志组的等待队列上进行等待
- 若所需的事件发生,则释放对应等待的任务
获取事件标志组时,可以选择的条件有四种:
- 要求所等待的事件标志全部置位则继续运行
- 要求所等待的事件标志任中一一位置位即可继续运行
- 要求所等待的事件标志全部复位则继续运行
- 要求所等待的事件标志中任意一位复位即可继续运行
当然,也可以选择将等待成功的标志位消耗掉(取反)
实现
定义
1
2
3
4
typedef struct _eflaggroup {
uint32_t flags; // 最多包含32个事件标志
eventCtrlBlock_t event;
}eFlagGroup_t;
初始化
1
2
3
4
void eFlagGroupInit(eFlagGroup_t* eflaggroup, uint32_t flags) {
eventInit(&eflaggroup->event, EVENT_TYPE_EFLAGGROUP);
eflaggroup->flags = flags;
}
判断标志位是否满足条件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 被改变的flags表示的是哪些标志位是被满足的
uint32_t eFlagGroupCheckExpected(eFlagGroup_t* eFlagGroup, uint32_t waitEFlagType, uint32_t* flags) {
uint32_t srcFlag = *flags;
uint32_t isWaitSet = waitEFlagType & EFLAGGROUP_SET;
uint32_t isWaitAll = waitEFlagType & EFLAGGROUP_ALL;
uint32_t isClear = waitEFlagType & EFLAGGROUP_CLEAR_AFTER;
uint32_t calFlag = isWaitSet ? (eFlagGroup->flags & srcFlag) : (~eFlagGroup->flags & srcFlag);
if (((isWaitAll != 0) && (calFlag == srcFlag)) || ((isWaitAll == 0) && (calFlag != 0))) {
if (isClear) {
if (isWaitSet) {
eFlagGroup->flags &= ~calFlag;
} else {
eFlagGroup->flags |= calFlag;
}
}
*flags = calFlag;
return 0;
}
*flags = calFlag;
return 1;
}
等待事件标志位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
uint32_t eFlagGroupWait(eFlagGroup_t* eflaggroup, uint32_t waitFlagType, uint32_t expectedFlag,
uint32_t* resultFlag, uint32_t waitTime)
{
uint32_t result;
uint32_t flags = expectedFlag;
uint32_t st = enterCritical();
result = eFlagGroupCheckExpected(eflaggroup, waitFlagType, &flags);
// 不满足条件
if(result == 1) {
currentTask->waitEventFlagType = waitFlagType;
currentTask->waitEventFlags = expectedFlag;
eventWait(&eflaggroup->event, currentTask, NULL, TASK_STATUS_WAIT_EFLAGGROUP, waitTime);
taskSched();
leaveCritical(st);
*resultFlag = currentTask->waitEventFlags;
return currentTask->eventWaitResult;
}
*resultFlag = flags;
leaveCritical(st);
return NO_ERROR;
}
获取事件标志位,获取失败也不等待
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
uint32_t eFlagGroupGetWithNoWait(eFlagGroup_t* eflaggroup, uint32_t waitFlagType, uint32_t expectedFlag,
uint32_t* resultFlag)
{
uint32_t result;
uint32_t flags = expectedFlag;
uint32_t st = enterCritical();
result = eFlagGroupCheckExpected(eflaggroup, waitFlagType, &flags);
// 如果满足条件
if(!result) {
*resultFlag = flags;
leaveCritical(st);
return NO_ERROR;
}
*resultFlag = flags;
leaveCritical(st);
return ERROR_RESOURCE_UNAVAILABLE;
}
将事件标志组中某些位置位或复位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void eFlagGroupPost(eFlagGroup_t* eFlagGroup, uint32_t flags, uint32_t isSet){
if (isSet) {
eFlagGroup->flags |= flags;
} else {
eFlagGroup->flags &= ~flags;
}
uint32_t schedFlag = 0;
uint32_t st = enterCritical();
for(listNode* node = eFlagGroup->event.waitlist.firstNode; node != &eFlagGroup->event.waitlist.headNode;) {
task_t* task = getListNodeParent(node, task_t, linkNode);
node = node->next;
uint32_t flags = task->waitEventFlags;
if (!eFlagGroupCheckExpected(eFlagGroup, task->waitEventFlagType, &flags)) {
task->waitEventFlags = flags;
eventWakeUpGivenTask(&eFlagGroup->event, task, NULL, NO_ERROR);
if(task->priority < currentTask->priority) {
schedFlag = 1;
}
}
}
if (schedFlag) {
taskSched();
}
leaveCritical(st);
}
销毁事件标志组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
uint32_t eFlagGroupDestory(eFlagGroup_t* eFlagGroup) {
uint32_t count;
uint32_t st = enterCritical();
if ((count = eventRemoveAllTask(&eFlagGroup->event, NULL, ERROR_DELETED)) > 0) {
taskSched();
}
leaveCritical(st);
return count;
}
END
本文由作者按照 CC BY 4.0 进行授权