在**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_headlink_tail:这是一个链表结构,存储了所有订阅该主题的订阅者节点(McnNode)。通过这两个指针,uMCN 可以高效地管理订阅者。
  • link_num:表示当前订阅该主题的订阅者数量。
  • published:标志主题是否已经发布过数据。如果为 1,表示主题已经有数据发布过。
  • suspend:标志主题是否被暂停发布。设置为 1 时,主题将不会接收新的发布数据。
  • event:在实时操作系统(RTOS)中用于订阅者等待事件通知,表示主题的发布事件。
  • freq:保存发布频率的估算值。
  • freq_est_windowwindow_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_DECLAREMCN_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通过这些结构实现了一个高效的发布-订阅系统,保证了发布者和订阅者之间的松耦合和数据的一致性。

10-09 01:49