diff --git a/config/CHANNEL/channel_cfg.json b/config/CHANNEL/channel_cfg.json index 34f698c..7fa8001 100644 --- a/config/CHANNEL/channel_cfg.json +++ b/config/CHANNEL/channel_cfg.json @@ -15,7 +15,8 @@ "type": "tcp_server", "local_ip": "0.0.0.0", "local_port": 2404, - "desc": "主站通道 (libiec直管, 不走com_router路由)" + "bind_app": "iec", + "desc": "IEC-104主站通道 (:2404) — com_router直接投递给libiec" } ], "forward_rules": [ diff --git a/src/system/libcom_router/inc/com_router.h b/src/system/libcom_router/inc/com_router.h index 63f42a6..ccecc13 100644 --- a/src/system/libcom_router/inc/com_router.h +++ b/src/system/libcom_router/inc/com_router.h @@ -21,6 +21,18 @@ extern "C" { #endif +/* =========================== 协议分发回调 =========================== */ + +#define MAX_DISPATCH_APPS 8 + +/** + * @brief 协议模块数据接收回调 — 通道绑定 bind_app 后, 整帧投递 + * @param interface 通道标识 (ch_id<<16)|fd + * @param data 原始数据 (整帧, 不解包) + * @param len 数据长度 + */ +typedef void (*com_router_dispatch_cb)(uint32_t interface, const unsigned char *data, int len); + /* =========================== 通道配置结构 =========================== */ /** @@ -76,6 +88,18 @@ uint32_t com_router_interface_get(const char *key); int com_router_fd_get(const char *key); int com_router_id_get_by_bind(const char *bind_app); +/** + * @brief 协议模块注册分发回调 — 通道 bind_app 匹配时直接投递 + * @param bind_app 协议标识 (如 "iec", "self_ptl", "iec61850") + * @param cb 数据接收回调, 通道收到数据时调用 + * @return 0 成功, -1 失败 (表满) + * + * @note 调用时机: app_wiring() 中, 在 app_com_router_init1 之后 + * 若通道配置中 bind_app 非空, 该通道的原始数据直接投递给注册的回调 + * 不再经过帧内容分路逻辑 (帧解析由协议模块自行完成) + */ +int com_router_register_dispatch(const char *bind_app, com_router_dispatch_cb cb); + /* =========================== 应用线程入口 =========================== */ int app_com_router_init1(void *arg); diff --git a/src/system/libcom_router/src/com_router.cpp b/src/system/libcom_router/src/com_router.cpp index f061b69..f85fb7c 100644 --- a/src/system/libcom_router/src/com_router.cpp +++ b/src/system/libcom_router/src/com_router.cpp @@ -29,6 +29,53 @@ int g_forward_count = 0; static int g_config_loaded = 0; +/* =========================== 协议分发注册表 =========================== */ + +typedef struct +{ + char bind_app[16]; + com_router_dispatch_cb cb; +} dispatch_entry_t; + +static dispatch_entry_t g_dispatch_table[MAX_DISPATCH_APPS]; +static int g_dispatch_count = 0; + +int com_router_register_dispatch(const char *bind_app, com_router_dispatch_cb cb) +{ + if(NULL == bind_app || NULL == cb || g_dispatch_count >= MAX_DISPATCH_APPS) + { + return -1; + } + + strncpy(g_dispatch_table[g_dispatch_count].bind_app, bind_app, 15); + g_dispatch_table[g_dispatch_count].cb = cb; + g_dispatch_count++; + + LOG_I("com_router: registered dispatch for [%s]", bind_app); + return 0; +} + +/* 内部查找: 按 bind_app 取回调, 未找到返回 NULL */ +com_router_dispatch_cb com_router_dispatch_find(const char *bind_app) +{ + int i; + + if(NULL == bind_app || '\0' == bind_app[0]) + { + return NULL; + } + + for(i = 0; i < g_dispatch_count; i++) + { + if(0 == strcmp(g_dispatch_table[i].bind_app, bind_app)) + { + return g_dispatch_table[i].cb; + } + } + + return NULL; +} + /* =========================== 前向声明 =========================== */ extern void com_router_recv_cb(int id, int fd, const unsigned char *data, int len); @@ -59,11 +106,14 @@ static int com_router_parse_channels(cJSON *arr) cJSON *key = cJSON_GetObjectItem(item, "key"); cJSON *type = cJSON_GetObjectItem(item, "type"); + cJSON *bind = cJSON_GetObjectItem(item, "bind_app"); cJSON *desc = cJSON_GetObjectItem(item, "desc"); if(NULL == key || NULL == type) continue; strncpy(ch->key, key->valuestring, 31); + if(NULL != bind) { strncpy(ch->bind_app, bind->valuestring, 15); } + else { ch->bind_app[0] = '\0'; } if(0 == strcmp(type->valuestring, "uart")) { diff --git a/src/system/libcom_router/src/com_router_dispatch.cpp b/src/system/libcom_router/src/com_router_dispatch.cpp index 05c5c40..7205601 100644 --- a/src/system/libcom_router/src/com_router_dispatch.cpp +++ b/src/system/libcom_router/src/com_router_dispatch.cpp @@ -11,6 +11,11 @@ #include +/* =========================== 前向声明 =========================== */ + +/* 来自 com_router.cpp 的内部函数 */ +extern com_router_dispatch_cb com_router_dispatch_find(const char *bind_app); + /* =========================== 全局变量引用 =========================== */ extern com_channel_t g_channels[]; @@ -119,6 +124,13 @@ static int com_router_fwd_send_back(int serial_ch_id, /* =========================== 核心: 数据接收回调 =========================== */ +/* + * 路由优先级: + * 1. 匹配 forward_rule.sock_fd → 透传到目标通道 (维护透传) + * 2. 通道 bind_app 非空 → 整帧投递给注册的协议模块回调 + * 3. bind_app 为空 (FTU 串口) → 按帧内容分路 (ICP67/IEC 帧识别) + */ + void com_router_recv_cb(int id, int fd, const unsigned char *p_rx, int rx_len) { com_channel_t *ch = NULL; @@ -155,7 +167,24 @@ void com_router_recv_cb(int id, int fd, const unsigned char *p_rx, int rx_len) return; } - /* Step 2: FTU 串口接收 → 按帧分路 */ + /* Step 2: bind_app 协议绑定 → 直接投递给注册的协议模块 */ + if('\0' != ch->bind_app[0]) + { + com_router_dispatch_cb dispatch = com_router_dispatch_find(ch->bind_app); + + if(NULL != dispatch) + { + uint32_t interface = ((uint32_t)id << 16) | (uint32_t)fd; + + dispatch(interface, p_rx, rx_len); + return; + } + + LOG_E("com_router: bind_app [%s] has no dispatch registered", ch->bind_app); + return; + } + + /* Step 3: bind_app 为空 → FTU 串口按帧内容分路 */ /* a) ICP67 维护软件回复 (dev_addr=0) */ if(rx_len >= (int)sizeof(stru_head)