关于RTOS的全部真相。 第十八条 事件标志组:助手服务和数据结构



本文继续介绍事件标志组。

该系列中的先前文章:

第十七条 事件标志组:简介和基本服务
第十六条 讯号
第十五条 内存分区:服务和数据结构
第十四条 内存部分:简介和基本服务
第十三条 任务数据结构和不受支持的API调用
第十二条 任务处理服务
第11条 任务:API的配置和介绍
第10条 计划程序:高级功能和上下文保留
第9条。 调度程序:实施
第8条 Nucleus SE:内部设计和部署
第7条 Nucleus SE:简介
第6条。 其他RTOS服务
第5条 任务交互和同步
第4条 任务,上下文切换和中断
第3条 任务与计划
第2条。 RTOS:结构和实时模式
第1条 RTOS:简介。


事件标志组助手服务


Nucleus RTOS具有三个API调用,它们为事件标志组提供帮助功能:检索组信息,检索有关应用程序中事件标志组数量的信息以及检索指向所有事件标志组的指针。 前两个挑战是在Nucleus SE中实现的。

检索事件标志组信息


该实用程序调用返回有关事件标志组的信息。 Nucleus SE中此调用的实现与Nucleus RTOS中的实现的不同之处在于,返回的信息较少,因为不支持对象的命名和暂停任务的顺序,并且可以停用任务本身的挂起。

在Nucleus RTOS中检索事件组信息的调用
服务电话原型:
状态NU_Event_Group_Information(NU_EVENT_GROUP *组,CHAR *名称,UNSIGNED * event_flags,UNSIGNED * task_waiting,NU_TASK ** first_task);

参数:
group-指向一组事件标志的用户提供的控制块的指针;
name-指向事件标志组名称的8个字符区域的指针,其中还包括结尾的零;
event_flags-指向将采用指定事件标志组的当前值的变量的指针;
task_waiting-指向一个变量的指针,该变量将使用此事件标志组中已挂起的任务数;
first_task-指向NU_TASK类型的变量的指针,它将使用指向第一个挂起任务的指针。

返回值:
NU_SUCCESS-调用成功完成;
NU_INVALID_GROUP-指向一组事件标志的无效指针。

在Nucleus SE中检索事件组信息的调用
该调用支持Nucleus RTOS API的核心功能。

服务电话原型:
状态NUSE_Event_Group_Information(NUSE_EVENT_GROUP组,U8 *事件标志,U8 *任务等待中,NUSE_TASK *第一任务);

参数:
group-事件标志的索引,有关该标志的信息被请求;
event_flags-指向将采用指定事件标志组的当前值的变量的指针;
task_waiting-指向一个变量的指针,该变量将使用此事件标志组中已挂起的任务数(如果停用任务挂起,则不会返回任何内容);
first_task-指向类型为NUSE_TASK的变量的指针,该变量将获取第一个被挂起的任务的索引(如果停用任务的挂起,则不会返回任何内容)。

返回值:
NUSE_SUCCESS-呼叫已成功完成;
NUSE_INVALID_GROUP-无效的事件标志组索引。

在Nucleus SE中实现事件组信息
实现此API调用非常简单:

*event_flags = NUSE_Event_Group_Data[group]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Event_Group_Blocking_Count[group]; if (NUSE_Event_Group_Blocking_Count[group] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_EVENT_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == group)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif return NUSE_SUCCESS; 

该函数返回事件标志组的值。 然后,如果激活了任务阻止API调用,则将返回挂起的任务数和它们中第一个的索引(否则,这两个参数将设置为零)。

获取事件标志组的数量


该实用程序调用返回应用程序中事件标志组的数量。 在Nucleus RTOS中,该值随时间变化,返回值显示当前组数,而在Nucleus SE中,该值在组装过程中确定,并且不会随时间变化。

在Nucleus RTOS中调用事件标志组的计数器
服务电话原型:
未签名的NU_Establised_Event_Groups(VOID);

参数:
缺席。

返回值:
当前创建的事件标志组的数量。

在Nucleus SE中调用事件标志组的计数器
服务电话原型:
U8 NUSE_Event_Group_Count(无效);

参数:
缺席。

返回值:
已配置的事件标志组的数量。

在Nucleus SE中实现事件标志组计数器
此API调用的实现非常简单: 返回 #define NUSE_EVENT_GROUP_NUMBER符号的值。

资料结构


像所有其他Nucleus SE对象一样,事件标志组使用一个或两个数据结构数组(均位于RAM中),数组的大小取决于设置中定义的组数。

我强烈建议应用程序代码不要直接访问这些数据结构,而是通过提供的API函数引用它们。 这将避免与Nucleus SE的未来版本不兼容以及不必要的副作用,并简化了将应用程序移植到Nucleus RTOS的过程。 为了更好地理解服务调用代码和调试,下面提供了数据结构的详细概述。

RAM数据


该数据具有以下结构:
NUSE_Event_Group_Data [] -类型为U8的数据数组,对于每个配置的标志组都有一个记录; 它存储事件标志数据。
NUSE_Event_Group_Blocking_Count []-U8类型的数组,在每组事件标志中均包含一个已阻止任务的计数器。 仅当激活API中的锁定功能时,此数组才存在。

Nucleus SE启动时,这些数据结构在NUSE_Init_Event_Group()函数中以零初始化。 以下文章之一将提供对Nucleus SE启动过程的完整描述。

以下是nuse_init.c文件中这些数据结构的描述:

 RAM U8 NUSE_Event_Group_Data[NUSE_EVENT_GROUP_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Event_Group_Blocking_Count[NUSE_EVENT_GROUP_NUMBER]; #endif 

ROM数据


为了实现事件标志组,不使用ROM中的数据。

事件标志组的内存大小


与所有Nucleus SE内核对象一样,事件标志组所需的内存量是可以预测的。

应用程序中所有事件标志组的ROM中的数据量为0。

具有激活的API锁定功能的所有事件标志组在RAM中的内存量为NUSE_EVENT_GROUP_NUMBER * 2

否则为NUSE_EVENT_GROUP_NUMBER

未实现的API调用


Nucleus SE中未实现可在Nucleus RTOS中找到的三个事件标志组的API调用。

创建事件标志组


此API调用将创建一组事件标志。 Nucleus SE不需要此调用,因为事件标志组是静态创建的。

服务电话原型:
状态NU_Create_Event_Group(NU_EVENT_GROUP *组,CHAR *名称);

参数:

group-指向一组事件标志的用户提供的控制块的指针; 用作在其他API调用中管理事件标志组的描述符
name-指向事件标志组的8个字符名称的指针,该区域中包含一个终止的空字节。

返回值:

NU_SUCCESS-调用成功完成;
NU_INVALID_GROUP-指向事件标志组( NULL )或已在使用的控制单元的空指针。

删除一组事件标志


此API调用将删除先前创建的事件标志组。 Nucleus SE不需要此调用,因为事件标志组是静态创建的,无法删除。

服务电话原型:

状态NU_Delete_Event_Group(NU_EVENT_GROUP *组);

参数:

group-指向事件标志组控制块的指针。

返回值:

NU_SUCCESS-调用成功完成;
NU_INVALID_GROUP-指向一组事件标志的无效指针。

事件标志组指针


该API调用构成了指向系统中所有事件标志组的指针的顺序列表。 Nucleus SE不需要此调用,因为事件标志组具有简单的索引,而不是指针。

服务电话原型:

UNSIGNED NU_Event_Group_Pointers(NU_EVENT_GROUP *指针列表,UNSIGNED maximum_pointers);

参数:

pointer_list-指向NU_EVENT_GROUP指针数组的指针,该数组充满了指向系统中创建的事件标志组的指针;
maximum_pointers-数组中的最大指针数。

返回值:

数组中NU_EVENT_GROUP指针的数量。

兼容Nucleus RTOS


开发Nucleus SE时,我的目标是确保与Nucleus RTOS的代码兼容性达到最高水平。 事件标志组也不例外,从开发人员的角度来看,它们的实现方式与Nucleus RTOS中几乎相同。 考虑到最终代码在所需的内存量方面将变得更加易懂和高效,因此我认为有些不兼容是有效的。 否则,Nucleus RTOS API调用几乎可以直接用作Nucleus SE调用。

对象标识符


在Nucleus RTOS中,所有对象均由特定类型的数据结构(控制单元)描述。 指向该控制单元的指针是一组事件标志的标识符。 我决定在Nucleus SE中需要一种不同的方法来有效地使用内存:RAM和/或ROM中的几个表描述了所有内核对象。 这些表的大小由每种类型的已配置对象的数量确定。 特定对象的标识符是此表中的索引。 因此,我将NUSE_EVENT_GROUP定义为与U8等效,此类型的变量(而非指针)用作事件标志组的标识符。 如果将代码从Nucleus SE移植到Nucleus RTOS,反之亦然,则这种轻微的不兼容性很容易处理。 通常,除了移动和存储之外,不对对象标识符执行任何操作。

Nucleus RTOS还支持命名事件标志组。 这些名称仅用于调试。 我从Nucleus SE中排除了它们以节省内存。

组中的标志数


在Nucleus RTOS中,事件标志组每个包含32个标志,在Nucleus SE I中,事件标志组的数目减少到八个,因为这对于简单的应用程序是足够的,并节省了RAM。 如果需要更大组的事件标志,则可以轻松修改Nucleus SE。

标志吸收功能


Nucleus RTOS具有在读取事件标志后清除(吸收)事件标志的功能。 我决定从Nucleus SE中排除此功能,以简化系统,因为当所有阻塞的任务都接收到要读取的标志时,才会发生标志的吸收(删除)操作,而这将很难实现。 如有必要,标记读取任务可以始终使用单独的API调用清除它们。

未实现的API调用


Nucleus RTOS支持七个用于事件标志组的实用程序调用。 其中,三个在Nucleus SE中未实现。 上面已经描述了这些挑战的详细信息以及将其排除在Nucleus SE之外的决定。
下一篇文章将讨论信号量。

关于作者: Colin Walls在电子行业工作了30多年,大部分时间用于固件。 他现在是Mentor Embedded(Mentor Graphics的一个部门)的固件工程师。 Colin Walls经常在会议和研讨会上发表演讲,他撰写了许多技术文章并撰写了两本有关固件的书。 居住在英国。 Colin的专业博客 ,电子邮件:colin_walls@mentor.com。

Source: https://habr.com/ru/post/zh-CN428890/


All Articles