在**uMCN(Micro Communication Node)**模块中,多个数据结构协同工作,实现发布-订阅机制。下面是uMCN中各个核心数据结构的详细功能解释。
1. McnHub
结构体:消息中心
功能:McnHub
是 uMCN 中的核心结构体,代表一个具体的消息主题(Topic)。它负责管理数据的发布和订阅,以及维护订阅者节点的链表。
struct mcn_hub {
const char* obj_name; // 主题名称,用于唯一标识
const uint32_t obj_size; // 主题数据的大小
void* pdata; // 指向存储发布的数据的指针
McnNode_t link_head; // 订阅者链表的头节点
McnNode_t link_tail; // 订阅者链表的尾节点
uint32_t link_num; // 当前订阅者数量
uint8_t published; // 标志该主题是否已发布数据
uint8_t suspend; // 标志该主题是否暂停发布
rt_event_t event; // 用于事件通知的RTOS事件
int (*echo)(void* parameter); // 打印主题内容的回调函数
float freq; // 发布频率估算值
uint16_t freq_est_window[MCN_FREQ_EST_WINDOW_LEN]; // 发布频率估算窗口
uint16_t window_index; // 当前频率窗口索引
};
详细解释:
obj_name
:表示主题的名字,通过它标识不同的主题。订阅者通过该名称来订阅主题。obj_size
:保存主题数据的大小,定义了该主题发布的数据类型和所需的存储空间。例如,如果发布的数据是float
类型,obj_size
将是sizeof(float)
。pdata
:这是一个指向实际存储发布数据的指针。通过这个指针,发布的数据会存储在该内存区域中,并且当新的数据发布时,旧数据会被覆盖。link_head
和link_tail
:这是一个链表结构,存储了所有订阅该主题的订阅者节点(McnNode
)。通过这两个指针,uMCN 可以高效地管理订阅者。link_num
:表示当前订阅该主题的订阅者数量。published
:标志主题是否已经发布过数据。如果为1
,表示主题已经有数据发布过。suspend
:标志主题是否被暂停发布。设置为1
时,主题将不会接收新的发布数据。event
:在实时操作系统(RTOS)中用于订阅者等待事件通知,表示主题的发布事件。freq
:保存发布频率的估算值。freq_est_window
和window_index
:用于估算发布频率的滑动窗口,记录最近几次的发布时间间隔。
2. McnNode
结构体:订阅者节点
功能:McnNode
代表一个订阅者,它存储与某个主题的订阅信息。每个订阅者节点都会挂在 McnHub
的订阅者链表上。
struct mcn_node {
McnHub_t hub; // 指向订阅的消息中心(主题)
volatile uint8_t renewal; // 标志订阅者是否收到了新的数据
void (*pub_cb)(void* parameter); // 发布数据时的回调函数
McnNode_t next; // 链表中的下一个订阅者节点
};
详细解释:
hub
:指向当前订阅的主题(McnHub
),即该订阅者关注的消息中心。renewal
:这是一个标志位,表示该订阅者是否接收到了新的数据。当mcn_publish()
函数发布数据时,所有订阅者的renewal
标志都会被设置为1
。pub_cb
:发布数据时调用的回调函数。当主题发布新的数据时,系统会遍历订阅者链表,调用每个订阅者的回调函数以通知它们数据更新。next
:指向下一个订阅者节点,实现订阅者链表。
3. McnList
结构体:消息中心链表
功能:McnList
用于维护系统中所有的 McnHub
,即消息中心的链表。每个消息中心(主题)都会作为一个节点保存在该链表中。
struct mcn_list {
McnHub_t hub; // 指向当前链表节点的消息中心(主题)
McnList_t next; // 指向下一个消息中心
};
详细解释:
hub
:指向链表中的一个McnHub
,即一个具体的主题。next
:指向下一个链表节点,实现所有主题的管理。通过这个链表,uMCN可以访问系统中的所有已定义的消息中心。
4. 辅助宏与常量
-
MCN_DECLARE
和MCN_DEFINE
:MCN_DECLARE
:用于在代码的其他部分声明一个消息主题。MCN_DEFINE
:用于定义一个消息主题,并为其分配内存。
例如:
MCN_DEFINE(temp_sensor, sizeof(float)); // 定义一个浮点类型的主题
5. mcn_publish()
函数:发布数据
功能:数据发布由 mcn_publish()
函数完成。它将数据复制到消息中心,并遍历订阅者链表,更新每个订阅者的更新标志并调用回调函数。
fmt_err_t mcn_publish(McnHub_t hub, const void* data) {
...
memcpy(hub->pdata, data, hub->obj_size); // 将数据复制到已分配的内存
...
// 遍历所有订阅者并更新其 renewal 标志
McnNode_t node = hub->link_head;
while (node != NULL) {
node->renewal = 1; // 标志订阅者接收到新数据
if (node->pub_cb != NULL) {
node->pub_cb(hub->pdata); // 调用订阅者的回调函数
}
node = node->next;
}
...
}
6. mcn_subscribe()
函数:订阅主题
订阅者通过 mcn_subscribe()
函数订阅消息(将订阅者节点挂在消息中心的订阅者链表中),并注册一个回调函数用于处理数据更新。
McnNode_t mcn_subscribe(McnHub_t hub, void (*pub_cb)(void* parameter)) {
...
node->pub_cb = pub_cb; // 注册订阅者的回调函数
...
hub->link_num++;
return node;
}
7. mcn_copy()
函数:数据复制
功能:订阅者可以通过 mcn_copy()
从消息中心复制最新的数据到订阅者的缓冲区中。这是确保订阅者能获取最新数据的关键步骤。
fmt_err_t mcn_copy(McnHub_t hub, McnNode_t node_t, void* buffer) {
memcpy(buffer, hub->pdata, hub->obj_size); // 将数据复制到订阅者的缓冲区
return FMT_EOK;
}
8. 主题的声明与定义
#define MCN_DECLARE(_name) extern McnHub __mcn_##_name
#define MCN_DEFINE(_name, _size) \
McnHub __mcn_##_name = { \
.obj_name = #_name, \
.obj_size = _size, \
.pdata = NULL, \
.link_head = NULL, \
.link_tail = NULL, \
.link_num = 0, \
.published = 0, \
.suspend = 0, \
.freq = 0.0f \
}
总结
McnHub
是 uMCN 的核心结构,负责管理主题的发布和订阅。McnNode
代表订阅者,管理订阅的主题和数据更新的回调函数。McnList
用于维护所有消息中心的链表。- uMCN通过这些结构实现了一个高效的发布-订阅系统,保证了发布者和订阅者之间的松耦合和数据的一致性。