feat(com_router): bind_app 协议绑定路由 — 端口→规约直投
## 设计 通道配置新增 bind_app 字段: - bind_app="" (空) → 现有帧内容分路 (FTU串口) - bind_app="iec" → 整帧直投 libiec (TCP :2404 主站) - bind_app="self_ptl" → 整帧直投 self_ptl (备用) 新增 com_router_register_dispatch(bind_app, cb): - 协议模块在 app_wiring() 注册回调 - recv_cb 发现通道 bind_app 匹配, 直接调用 dispatch - 不需要帧解析 — 协议模块自行解码 ## 路由优先级 1. forward_rule → 维护透传 2. bind_app 非空 → dispatch 投递 3. bind_app 空 → 帧内容分路 (ICP67 dev=0/IEC/ICP67 dev≠0) ## 配置示例 channel_cfg.json: tcp_master(:2404) bind_app="iec" → 外部主站连接 :2404 → com_router → libiec 回调
This commit is contained in:
parent
9560ea7653
commit
8cf00ad14d
|
|
@ -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": [
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
/* =========================== 前向声明 =========================== */
|
||||
|
||||
/* 来自 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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue