diff --git a/src/protocol/libicp67/inc/icp67.h b/src/protocol/libicp67/inc/icp67.h index 0c13c69..e8bc370 100644 --- a/src/protocol/libicp67/inc/icp67.h +++ b/src/protocol/libicp67/inc/icp67.h @@ -460,14 +460,14 @@ void icp67_timer_handler(stru_icp67 *p_icp67); /** * @brief 构造 ICP67 帧头 - * @param src 源设备 + * @param dst 目标设备 * @param ti 类型标识 * @param cot 传输原因 * @param info_addr 信息地址 * @param p_tx 发送缓冲区 (输入输出) * @param tx_len 发送长度 (输入输出) */ -void icp67_make_head(uint8_t src, uint8_t ti, uint8_t cot, uint16_t info_addr, uint8_t *p_tx, uint16_t *tx_len); +void icp67_make_head(uint8_t dst, uint8_t ti, uint8_t cot, uint16_t info_addr, uint8_t *p_tx, uint16_t *tx_len); /** * @brief 构造 ICP67 帧尾 (CRC + 0x16) diff --git a/src/protocol/libicp67/src/icp67_core.c b/src/protocol/libicp67/src/icp67_core.c index 4ddcf79..debfade 100644 --- a/src/protocol/libicp67/src/icp67_core.c +++ b/src/protocol/libicp67/src/icp67_core.c @@ -128,7 +128,6 @@ void icp67_init(stru_icp67 *p_icp67, icp67_send_cb send_cb, void *arg, p_icp67->tm_out_ms = (0 == tm_out_ms) ? ICP67_TM_OUT_DEF_MS : tm_out_ms; p_icp67->tm_out = p_icp67->tm_out_ms / ICP67_TM_TICK_MS; p_icp67->resend_cnt = 0; - p_icp67->tm_out = p_icp67->tm_out_ms / ICP67_TM_TICK_MS; p_icp67->tm_cnt = 0; /* 初始化 sender 回调为内部函数 (方向: self_ptl → icp67) */ @@ -182,86 +181,103 @@ int icp67_set_ao_cfg_md5(stru_icp67 *p_icp67, uint8_t *p_md5) void icp67_set_ao_pop_out_cb(stru_icp67 *p_icp67, icp67_ao_pop_out_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.ao_pop_out_cb = cb; } void icp67_set_iec_point_tbl_pop_out_cb(stru_icp67 *p_icp67, icp67_iec_point_tbl_pop_out_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.iec_point_tbl_pop_out_cb = cb; } void icp67_set_self_check_pop_out_cb(stru_icp67 *p_icp67, icp67_self_check_pop_out_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.self_check_pop_out_cb = cb; } void icp67_set_dir_pop_out_cb(stru_icp67 *p_icp67, icp67_dir_pop_out_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.dir_pop_out_cb = cb; } void icp67_set_file_read_act_confirm_cb(stru_icp67 *p_icp67, icp67_file_read_act_confirm_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.file_read_act_confirm_cb = cb; } void icp67_set_file_read_cb(stru_icp67 *p_icp67, icp67_file_read_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.file_read_cb = cb; } void icp67_set_file_write_act_confirm_cb(stru_icp67 *p_icp67, icp67_file_write_act_confirm_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.file_write_act_confirm_cb = cb; } void icp67_set_file_write_confirm_cb(stru_icp67 *p_icp67, icp67_file_write_confirm_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.file_write_confirm_cb = cb; } void icp67_set_file_write_end_cb(stru_icp67 *p_icp67, icp67_file_write_end_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.file_write_end_cb = cb; } void icp67_set_zip_dir_pop_out_cb(stru_icp67 *p_icp67, icp67_zip_dir_pop_out_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.zip_dir_pop_out_cb = cb; } void icp67_set_zip_file_pop_out_cb(stru_icp67 *p_icp67, icp67_zip_file_pop_out_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.zip_file_pop_out_cb = cb; } void icp67_set_mx_trans_cb(stru_icp67 *p_icp67, icp67_mx_trans_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.mx_trans_cb = cb; } void icp67_set_st_trans_cb(stru_icp67 *p_icp67, icp67_st_trans_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.st_trans_cb = cb; } void icp67_set_dd_trans_cb(stru_icp67 *p_icp67, icp67_dd_trans_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.dd_trans_cb = cb; } void icp67_set_soe_trans_cb(stru_icp67 *p_icp67, icp67_soe_trans_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.soe_trans_cb = cb; } void icp67_set_fault_trans_cb(stru_icp67 *p_icp67, icp67_fault_trans_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.fault_trans_cb = cb; } void icp67_set_mx_change_cb(stru_icp67 *p_icp67, icp67_mx_change_cb cb) { + if(NULL == p_icp67) return; p_icp67->method.mx_change_cb = cb; } diff --git a/src/protocol/libicp67/src/icp67_decode.c b/src/protocol/libicp67/src/icp67_decode.c index fcfa192..dc67a24 100644 --- a/src/protocol/libicp67/src/icp67_decode.c +++ b/src/protocol/libicp67/src/icp67_decode.c @@ -203,6 +203,7 @@ int icp67_decode(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len) { stru_head *p_head; icp67_decode_cb func; + int ret; if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len) { @@ -218,9 +219,9 @@ int icp67_decode(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len) return -1; } - func(p_icp67, p_rx, rx_len); + ret = func(p_icp67, p_rx, rx_len); - return 0; + return ret; } /* =========================== TI_1: 读独立编码参数响应 =========================== */ @@ -266,15 +267,33 @@ static int icp67_decode_ti_1(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len return -1; } - pos = 0; - for(i = 0; p_icp67->method.ao_pop_out_cb && i < p_asdu->num; i++) { - stru_ti_1_2_data_info *p_info = (stru_ti_1_2_data_info *)&p_asdu->data[pos]; + uint16_t asdu_len = (uint16_t)(rx_len - ICP67_FRAME_OVERHEAD); /* 减去帧头开销 */ - pos += sizeof(stru_ti_1_2_data_info) + p_info->data_len; + pos = 0; + for(i = 0; p_icp67->method.ao_pop_out_cb && i < p_asdu->num; i++) + { + stru_ti_1_2_data_info *p_info; - p_icp67->method.ao_pop_out_cb(p_icp67, p_info->data_addr, - p_info->data_type, p_info->data_len, p_info->data); + if(pos + sizeof(stru_ti_1_2_data_info) > asdu_len) + { + LOG_E("icp67_decode_ti_1: frame too short for entry header, pos=%d", pos); + break; + } + + p_info = (stru_ti_1_2_data_info *)&p_asdu->data[pos]; + + if(pos + sizeof(stru_ti_1_2_data_info) + p_info->data_len > asdu_len) + { + LOG_E("icp67_decode_ti_1: data_len overflow, pos=%d, data_len=%d", pos, p_info->data_len); + break; + } + + pos += sizeof(stru_ti_1_2_data_info) + p_info->data_len; + + p_icp67->method.ao_pop_out_cb(p_icp67, p_info->data_addr, + p_info->data_type, p_info->data_len, p_info->data); + } } icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0); @@ -379,7 +398,7 @@ static int icp67_decode_ti_3(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len p_tx_asdu->total = p_asdu->total; p_tx_asdu->frame_no = offset; p_tx_asdu->follow = p_asdu->follow; - p_tx_asdu->num = p_asdu->num; + p_tx_asdu->num = 0; /* 续帧请求不携带参数数据 */ tx_len += sizeof(stru_ti_3_follow); } @@ -468,14 +487,32 @@ static int icp67_decode_ti_6(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len p_asdu = (stru_ti_6 *)p_head->data; - pos = 0; - for(i = 0; p_icp67->method.self_check_pop_out_cb && i < p_asdu->st_num; i++) { - stru_data_info *p = (stru_data_info *)&p_asdu->st_data[pos]; + uint16_t asdu_len = (uint16_t)(rx_len - ICP67_FRAME_OVERHEAD); - pos += sizeof(stru_data_info) + p->data_len; + pos = 0; + for(i = 0; p_icp67->method.self_check_pop_out_cb && i < p_asdu->st_num; i++) + { + stru_data_info *p; - p_icp67->method.self_check_pop_out_cb(p_icp67, p, i); + if(pos + sizeof(stru_data_info) > asdu_len) + { + LOG_E("icp67_decode_ti_6: frame too short for entry header, pos=%d", pos); + break; + } + + p = (stru_data_info *)&p_asdu->st_data[pos]; + + if(pos + sizeof(stru_data_info) + p->data_len > asdu_len) + { + LOG_E("icp67_decode_ti_6: data_len overflow, pos=%d, data_len=%d", pos, p->data_len); + break; + } + + pos += sizeof(stru_data_info) + p->data_len; + + p_icp67->method.self_check_pop_out_cb(p_icp67, p, i); + } } icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0); diff --git a/src/protocol/libicp67/src/icp67_frame.c b/src/protocol/libicp67/src/icp67_frame.c index fe15b70..091dc66 100644 --- a/src/protocol/libicp67/src/icp67_frame.c +++ b/src/protocol/libicp67/src/icp67_frame.c @@ -38,7 +38,7 @@ int icp67_search_frame(uint8_t *p_data, uint16_t len, uint16_t *p_pos, uint16_t { stru_head *p_head = (stru_head *)(p_data + i); - if(i + sizeof(uint16_t) + sizeof(stru_head) > len) + if(i + sizeof(stru_head) > len) { break; } @@ -192,8 +192,16 @@ void icp67_show_frame(uint8_t *p_data, uint16_t len) p_head = (stru_head *)p_data; - printf("%s -> %s, len = %d, dev_addr %d\n", - str[p_head->src - 1], str[p_head->dst - 1], len, p_head->dev_addr); + if(p_head->src >= 1 && p_head->src <= 5 && p_head->dst >= 1 && p_head->dst <= 5) + { + printf("%s -> %s, len = %d, dev_addr %d\n", + str[p_head->src - 1], str[p_head->dst - 1], len, p_head->dev_addr); + } + else + { + printf("src=%d -> dst=%d, len = %d, dev_addr %d\n", + p_head->src, p_head->dst, len, p_head->dev_addr); + } for(i = 0; i < len; i++) { diff --git a/src/system/libcom_router/src/com_router_dispatch.cpp b/src/system/libcom_router/src/com_router_dispatch.cpp index 7b7f16a..05c5c40 100644 --- a/src/system/libcom_router/src/com_router_dispatch.cpp +++ b/src/system/libcom_router/src/com_router_dispatch.cpp @@ -173,9 +173,10 @@ void com_router_recv_cb(int id, int fd, const unsigned char *p_rx, int rx_len) return; } - /* c) ICP67 帧 (dev_addr=1) → MQ_COM_TO_SELF_PTL → self_ptl */ + /* c) ICP67 帧 (dev_addr != 维护地址) → MQ_COM_TO_SELF_PTL → self_ptl */ if(rx_len >= (int)sizeof(stru_head) - && 0x67 == p_rx[0] && 0x67 == p_rx[3]) + && 0x67 == p_rx[0] && 0x67 == p_rx[3] + && DEV_MAINTENANCE_ADDR != ((stru_head *)p_rx)->dev_addr) { uint32_t interface = ((uint32_t)id << 16) | (uint32_t)fd; diff --git a/src/system/libself_ptl/src/self_ptl.cpp b/src/system/libself_ptl/src/self_ptl.cpp index 559e559..dd1ec96 100644 --- a/src/system/libself_ptl/src/self_ptl.cpp +++ b/src/system/libself_ptl/src/self_ptl.cpp @@ -5,6 +5,7 @@ #include "mySystem.h" #include "myLog.h" +#include "myCmd.h" #include "myIcp67.h" #include "myDatacenter.h" #include "self_ptl.h" @@ -12,6 +13,8 @@ #include #include +#include +#include #include #include @@ -384,9 +387,10 @@ static void self_ptl_search_frame(uint8_t *p_rx, uint16_t len, stru_icp67 *p_icp if(0 == self_ptl_search_iec_frame(buf, buf_len, &pos, &valid_len)) { LOG_I("self_ptl: found IEC-104 frame at pos=%d, len=%d", pos, valid_len); + /* TODO: 将 IEC-104 帧转发到 libiec 解码模块 (待实现) */ + } } } -} /* =========================== 信号注册 =========================== */ @@ -627,3 +631,254 @@ void *app_self_ptl(void *arg) return NULL; } + +/* =========================== 测试命令 =========================== */ +/* + * self_ptl 测试命令 — 手动触发 ICP67 各类协议请求。 + * 在真实 FTU 对接前,这些命令是项目主要数据来源。 + * + * TODO: 后续真实数据接入后,这些子命令可转为内部接口或保留调试用。 + */ + +static void cmd_self_ptl_show_info(void) +{ + stru_icp67 *p_icp67 = &g_self_ptl.icp67; + stru_self_ptl_cfg *p_cfg = self_ptl_cfg_get(); + + printf("===== Self-PTL Info =====\n"); + printf("Interface : 0x%08X\n", g_self_ptl.interface); + printf("ICP67 : send_cb=%p, tx_len=%d\n", + (void*)p_icp67->send_cb, p_icp67->tx_len); + printf("RTX : flag=%d, cnt=%d/%d, tm_out=%d ms\n", + p_icp67->rtx_flag, p_icp67->resend_cnt, p_icp67->resend_max, + p_icp67->tm_out_ms); + printf("MD5 : "); + for(int i = 0; i < 16; i++) printf("%02X", p_icp67->md5[i]); + printf("\nCB table : ao_get=%p ao_set=%p iec_get=%p time=%p chk=%p upg=%p\n", + (void*)p_icp67->method.ao_get_cb, + (void*)p_icp67->method.ao_set_cb, + (void*)p_icp67->method.iec_point_tbl_get_cb, + (void*)p_icp67->method.time_set_cb, + (void*)p_icp67->method.self_check_get_cb, + (void*)p_icp67->method.upgrade_start_cb); + printf(" dir=%p f_rd_act=%p f_wr_act=%p\n", + (void*)p_icp67->method.dir_read_cb, + (void*)p_icp67->method.file_read_act_cb, + (void*)p_icp67->method.file_write_act_cb); + + if(NULL != p_cfg) + { + printf("XML CFG : ST=%d MX=%d CO=%d DD=%d AO=%d Param=%d\n", + (int)p_cfg->st_vec.size(), (int)p_cfg->mx_vec.size(), + (int)p_cfg->co_vec.size(), (int)p_cfg->dd_vec.size(), + (int)p_cfg->ao_vec.size(), (int)p_cfg->param_vec.size()); + } +} + +LOCAL void cmd_self_ptl(int argc, char *argv[]) +{ + stru_icp67 *p_icp67 = &g_self_ptl.icp67; + const char *str = + "self_ptl info 查看自协议和 ICP67 状态\n" + "self_ptl ao_get [num=1] 触发读内部参数\n" + "self_ptl ao_get_all 触发读全部 AO 参数 (来自 XML 配置)\n" + "self_ptl iec_get 触发读 IEC 点表 (分帧传输)\n" + "self_ptl time_sync 触发对时\n" + "self_ptl self_check 触发自检读取\n" + "self_ptl dir_read 触发读目录 (可选时间范围)\n" + "self_ptl file_read 触发读文件激活\n" + "self_ptl file_write 触发写文件激活\n"; + + if(argc < 2) + { + printf("%s", str); + return; + } + + if(0 == strcmp(argv[1], "info")) + { + cmd_self_ptl_show_info(); + } + else if(0 == strcmp(argv[1], "ao_get")) + { + uint16_t addr = (argc >= 3) ? (uint16_t)atoi(argv[2]) : 0; + uint8_t type = (argc >= 4) ? (uint8_t)atoi(argv[3]) : 0; + uint16_t num = (argc >= 5) ? (uint16_t)atoi(argv[4]) : 1; + + if(NULL == p_icp67->method.ao_get_cb) + { + LOG_E("cmd_self_ptl: ao_get_cb not set"); + return; + } + + stru_ti_1_2_data ao_data[16] = {}; + for(uint16_t i = 0; i < num && i < 16; i++) + { + ao_data[i].data_addr = addr + i; + ao_data[i].data_type = type; + ao_data[i].data_len = 0; + } + + p_icp67->method.ao_get_cb(p_icp67, ao_data, num); + LOG_I("cmd_self_ptl: ao_get addr=%d type=%d num=%d", addr, type, num); + } + else if(0 == strcmp(argv[1], "ao_get_all")) + { + /* 读全部 AO 参数: 遍历 XML 配置的所有 AO,构造完整参数列表 */ + stru_self_ptl_cfg *p_cfg = self_ptl_cfg_get(); + + if(NULL == p_cfg || p_cfg->ao_vec.empty()) + { + printf("ao_get_all: no AO params in config\n"); + return; + } + if(NULL == p_icp67->method.ao_get_cb) + { + LOG_E("cmd_self_ptl: ao_get_cb not set"); + return; + } + + uint16_t num = (uint16_t)p_cfg->ao_vec.size(); + if(num > 240) + { + LOG_E("cmd_self_ptl: too many AO params (%d), max 240", num); + return; + } + + /* 栈上分配参数数组 (每个 sizeof(stru_ti_1_2_data)=4) */ + stru_ti_1_2_data ao_data[240]; + for(uint16_t i = 0; i < num; i++) + { + ao_data[i].data_addr = (uint16_t)p_cfg->ao_vec[i].base.inf; + ao_data[i].data_type = (uint8_t)p_cfg->ao_vec[i].type; + ao_data[i].data_len = 0; /* 读取时不需要填长度,FTU 回复时填充 */ + } + + p_icp67->method.ao_get_cb(p_icp67, ao_data, num); + LOG_I("cmd_self_ptl: ao_get_all num=%d", num); + } + else if(0 == strcmp(argv[1], "iec_get")) + { + uint16_t info_addr = (argc >= 3) ? (uint16_t)atoi(argv[2]) : 0; + + if(NULL == p_icp67->method.iec_point_tbl_get_cb) + { + LOG_E("cmd_self_ptl: iec_point_tbl_get_cb not set"); + return; + } + + p_icp67->method.iec_point_tbl_get_cb(p_icp67, info_addr); + LOG_I("cmd_self_ptl: iec_get info_addr=%d", info_addr); + } + else if(0 == strcmp(argv[1], "time_sync")) + { + if(NULL == p_icp67->method.time_set_cb) + { + LOG_E("cmd_self_ptl: time_set_cb not set"); + return; + } + + /* 构造当前时间 ASDU */ + stru_ti_5 tm = {}; + time_t now = time(NULL); + struct tm *lt = localtime(&now); + + tm.year = (uint16_t)(lt->tm_year + 1900 - 2000); + tm.month = (uint16_t)(lt->tm_mon + 1); + tm.day = (uint16_t)lt->tm_mday; + tm.hour = (uint16_t)lt->tm_hour; + tm.min = (uint16_t)lt->tm_min; + tm.ms = (uint16_t)(lt->tm_sec * 1000); + + p_icp67->method.time_set_cb(p_icp67, &tm); + LOG_I("cmd_self_ptl: time_sync %04d-%02d-%02d %02d:%02d:%02d", + tm.year+2000, tm.month, tm.day, tm.hour, tm.min, tm.ms/1000); + } + else if(0 == strcmp(argv[1], "self_check")) + { + if(NULL == p_icp67->method.self_check_get_cb) + { + LOG_E("cmd_self_ptl: self_check_get_cb not set"); + return; + } + + p_icp67->method.self_check_get_cb(p_icp67); + LOG_I("cmd_self_ptl: self_check"); + } + else if(0 == strcmp(argv[1], "dir_read")) + { + if(argc < 3) + { + printf("usage: self_ptl dir_read \n"); + return; + } + + if(NULL == p_icp67->method.dir_read_cb) + { + LOG_E("cmd_self_ptl: dir_read_cb not set"); + return; + } + + const char *path = argv[2]; + uint8_t len = (uint8_t)strlen(path); + + p_icp67->method.dir_read_cb(p_icp67, (uint8_t *)path, len, NULL, NULL); + LOG_I("cmd_self_ptl: dir_read %s", path); + } + else if(0 == strcmp(argv[1], "file_read")) + { + if(argc < 3) + { + printf("usage: self_ptl file_read \n"); + return; + } + + if(NULL == p_icp67->method.file_read_act_cb) + { + LOG_E("cmd_self_ptl: file_read_act_cb not set"); + return; + } + + const char *name = argv[2]; + uint8_t len = (uint8_t)strlen(name); + + p_icp67->method.file_read_act_cb(p_icp67, (uint8_t *)name, len); + LOG_I("cmd_self_ptl: file_read %s", name); + } + else if(0 == strcmp(argv[1], "file_write")) + { + if(argc < 5) + { + printf("usage: self_ptl file_write \n"); + return; + } + + if(NULL == p_icp67->method.file_write_act_cb) + { + LOG_E("cmd_self_ptl: file_write_act_cb not set"); + return; + } + + const char *name = argv[2]; + uint8_t len = (uint8_t)strlen(name); + uint32_t size = (uint32_t)atoi(argv[3]); + uint16_t crc = (uint16_t)atoi(argv[4]); + + p_icp67->method.file_write_act_cb(p_icp67, (uint8_t *)name, len, 0, size, crc); + LOG_I("cmd_self_ptl: file_write %s size=%d crc=%d", name, size, crc); + } + else + { + printf("unknown subcommand: %s\n", argv[1]); + printf("%s", str); + } +} + +LOCAL void cmd_self_ptl_complete(const char *buf, char ***completions, int *ncomp) +{ + static const char *subs[] = {"info", "ao_get", "ao_get_all", "iec_get", "time_sync", + "self_check", "dir_read", "file_read", "file_write"}; + cmd_sub_complete(buf, completions, ncomp, subs, sizeof(subs)/sizeof(subs[0])); +} + +CMD_REGISTER_C("self_ptl", cmd_self_ptl, "自协议测试命令 (AO/IEC/时间/自检/文件)", cmd_self_ptl_complete); diff --git a/src/system/libself_ptl/src/self_ptl_cb.cpp b/src/system/libself_ptl/src/self_ptl_cb.cpp index b6a23d7..1bde1a6 100644 --- a/src/system/libself_ptl/src/self_ptl_cb.cpp +++ b/src/system/libself_ptl/src/self_ptl_cb.cpp @@ -16,6 +16,7 @@ #include #include #include +#include /* =========================== 文件操作辅助 =========================== */ @@ -24,6 +25,9 @@ static std::string g_file_path; static std::string g_zip_path; static int g_paths_ready = 0; +/* 文件操作全局状态互斥锁 (防止多 FTU 并发传输竞态) */ +static pthread_mutex_t g_file_mutex = PTHREAD_MUTEX_INITIALIZER; + static void file_paths_init(void) { char proc_dir[512] = {0}; @@ -40,8 +44,16 @@ static void file_paths_init(void) g_file_path = g_file_base_path + "file/"; g_zip_path = g_file_base_path + "zip/"; - func_make_dirs(g_file_path.c_str()); - func_make_dirs(g_zip_path.c_str()); + if(0 != func_make_dirs(g_file_path.c_str())) + { + LOG_E("file_paths_init: func_make_dirs(%s) failed", g_file_path.c_str()); + return; + } + if(0 != func_make_dirs(g_zip_path.c_str())) + { + LOG_E("file_paths_init: func_make_dirs(%s) failed", g_zip_path.c_str()); + return; + } g_paths_ready = 1; LOG_I("file_paths_init: file=%s, zip=%s", g_file_path.c_str(), g_zip_path.c_str()); @@ -193,6 +205,8 @@ void dir_pop_out(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, if(NULL == p_icp67 || NULL == p_name) return; + pthread_mutex_lock(&g_file_mutex); + memcpy(dir_info.name, p_name, len); dir_info.name[len] = '\0'; dir_info.len = len; @@ -209,6 +223,8 @@ void dir_pop_out(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, } g_dir_info_vec.clear(); } + + pthread_mutex_unlock(&g_file_mutex); } /* ---- 读文件激活确认 ---- */ @@ -219,6 +235,8 @@ void file_read_act_confirm(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, if(NULL == p_icp67 || NULL == p_name) return; file_paths_init(); + + pthread_mutex_lock(&g_file_mutex); g_file_name = std::string((char *)p_name, len); LOG_I("file_read_act_confirm: name=%s, id=%d, size=%d, crc=0x%04X", @@ -230,6 +248,7 @@ void file_read_act_confirm(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, func_make_dirs((g_file_path + g_dir_name).c_str()); unlink(fpath.c_str()); } + pthread_mutex_unlock(&g_file_mutex); } /* ---- 读文件内容 (FTU → RTU 本地写入) ---- */ @@ -239,6 +258,8 @@ void file_read(stru_icp67 *p_icp67, uint32_t id, uint32_t offset, { if(NULL == p_icp67 || NULL == p_data) return; + pthread_mutex_lock(&g_file_mutex); + if(0 == offset) { LOG_I("file_read: %s start", g_file_name.c_str()); @@ -259,6 +280,8 @@ void file_read(stru_icp67 *p_icp67, uint32_t id, uint32_t offset, { p_icp67->method.file_read_confirm_cb(p_icp67, 0, id, offset + len); } + + pthread_mutex_unlock(&g_file_mutex); } /* ---- 写文件激活确认 (RTU → FTU 发送文件) ---- */ @@ -275,6 +298,8 @@ void file_write_act_confirm(stru_icp67 *p_icp67, uint8_t result, } file_paths_init(); + + pthread_mutex_lock(&g_file_mutex); g_file_name = std::string((char *)p_name, len); { @@ -304,6 +329,8 @@ void file_write_act_confirm(stru_icp67 *p_icp67, uint8_t result, md5_update(&g_file_md5_ctx, file_data, frame_len); g_md5_started = 1; } + + pthread_mutex_unlock(&g_file_mutex); } /* ---- 写文件确认 (继续发送后续帧) ---- */ @@ -313,6 +340,17 @@ void file_write_confirm(stru_icp67 *p_icp67, uint8_t result, { if(NULL == p_icp67) return; + /* 检查 FTU 返回的错误结果 */ + (void)result; /* TODO: FTU error handling — if result != FILE_WRITE_CONT_1/0, abort transfer */ + if(FILE_WRITE_CONT_0 != result && FILE_WRITE_CONT_1 != result) + { + LOG_E("file_write_confirm: FTU error result=%d, abort transfer", result); + g_md5_started = 0; + return; + } + + pthread_mutex_lock(&g_file_mutex); + { std::string fpath = g_file_path + g_dir_name + "/" + g_file_name; uint32_t size = 0; @@ -334,8 +372,6 @@ void file_write_confirm(stru_icp67 *p_icp67, uint8_t result, uint8_t file_data[FILE_TRANS_FRMAE_LEN] = {0}; file_read(fpath.c_str(), offset, file_data, frame_len); - usleep(5000); - if(p_icp67->method.file_write_cb) { p_icp67->method.file_write_cb(p_icp67, id, offset, follow, file_data, frame_len); @@ -347,7 +383,7 @@ void file_write_confirm(stru_icp67 *p_icp67, uint8_t result, } } - (void)result; + pthread_mutex_unlock(&g_file_mutex); } /* ---- 写文件结束 (MD5 校验) ---- */ @@ -360,6 +396,8 @@ void file_write_end(stru_icp67 *p_icp67, uint8_t result, uint32_t id, if(NULL == p_icp67 || NULL == md5) return; + pthread_mutex_lock(&g_file_mutex); + if(g_md5_started) { md5_final(&g_file_md5_ctx, file_md5); @@ -382,6 +420,8 @@ void file_write_end(stru_icp67 *p_icp67, uint8_t result, uint32_t id, LOG_E("file_write_end: %s failed", g_file_name.c_str()); } + pthread_mutex_unlock(&g_file_mutex); + if(p_icp67->method.file_write_end_confirm_cb) { p_icp67->method.file_write_end_confirm_cb(p_icp67, final_result, id, file_md5); @@ -398,6 +438,7 @@ void zip_dir_pop_out(stru_icp67 *p_icp67, uint8_t zip_type, { if(NULL == p_icp67 || NULL == zip_name || NULL == p_file_info) return; + pthread_mutex_lock(&g_file_mutex); g_zip_name = std::string((char *)zip_name, len); LOG_I("zip_dir_pop_out: type=%d, name=%s, files=%d", zip_type, g_zip_name.c_str(), file_num); @@ -405,6 +446,7 @@ void zip_dir_pop_out(stru_icp67 *p_icp67, uint8_t zip_type, { LOG_I(" [%d] %s (size=%d)", p_file_info[i].id, p_file_info[i].name, p_file_info[i].size); } + pthread_mutex_unlock(&g_file_mutex); } /* ---- 压缩文件内容 (FTU → RTU 本地写入 zip/) ---- */ @@ -416,12 +458,14 @@ void zip_file_pop_out(stru_icp67 *p_icp67, uint8_t id, uint32_t offset, file_paths_init(); + pthread_mutex_lock(&g_file_mutex); { std::string zip_fpath = g_zip_path + g_zip_name; file_write(zip_fpath.c_str(), offset, p_data, len); if(0 == offset) LOG_I("zip_file_pop_out: %s start", g_zip_name.c_str()); } + pthread_mutex_unlock(&g_file_mutex); } /* =========================== 实时数据 + 事件队列 =========================== */ diff --git a/src/system/libself_ptl/src/self_ptl_cfg.cpp b/src/system/libself_ptl/src/self_ptl_cfg.cpp index 9b52412..d3ed8d0 100644 --- a/src/system/libself_ptl/src/self_ptl_cfg.cpp +++ b/src/system/libself_ptl/src/self_ptl_cfg.cpp @@ -272,8 +272,39 @@ static int parse_param(XMLElement *root) while(nullptr != signal_ele) { stru_self_ptl_cfg_param cfg_param; + const char *saddr = signal_ele->Attribute(attr_saddr); + const char *desc = signal_ele->Attribute(attr_desc); + int inf = 0; + + if(XML_SUCCESS != signal_ele->QueryIntAttribute(attr_inf, &inf)) + { + LOG_E("parse_param: inf parse failed"); + signal_ele = signal_ele->NextSiblingElement(ele_Signal); + continue; + } + + const char *type = signal_ele->Attribute(attr_type); + const char *unit = signal_ele->Attribute(attr_unit); + const char *min = signal_ele->Attribute(attr_min); + const char *max = signal_ele->Attribute(attr_max); + const char *step = signal_ele->Attribute(attr_step); + const char *value = signal_ele->Attribute(attr_value); + const char *dflt = signal_ele->Attribute(attr_default); + + cfg_param.base.saddr = (nullptr == saddr) ? "" : saddr; + cfg_param.base.desc = (nullptr == desc) ? "" : desc; + cfg_param.base.inf = inf; + cfg_param.type = dc_get_type_id_by_name((nullptr == type) ? "" : type); + cfg_param.unit = (nullptr == unit) ? "" : unit; + cfg_param.min = (nullptr == min) ? "" : min; + cfg_param.max = (nullptr == max) ? "" : max; + cfg_param.step = (nullptr == step) ? "" : step; + + cfg_param.val.push_back((nullptr == value) ? "" : value); + cfg_param.default_value.push_back((nullptr == dflt) ? "" : dflt); + + g_self_ptl_cfg.param_vec.push_back(cfg_param); - /* 与 Ao 使用相同的解析逻辑 */ signal_ele = signal_ele->NextSiblingElement(ele_Signal); }