From ae1329aacc033afdaf1bd420c85eafbc550294cf Mon Sep 17 00:00:00 2001 From: ypc <15051963820@163.com> Date: Thu, 9 Jul 2026 18:04:00 +0800 Subject: [PATCH] =?UTF-8?q?fix(self=5Fptl):=20=E6=96=87=E4=BB=B6=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=9B=9E=E8=B0=83=E5=AE=9E=E7=8E=B0=20+=20=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E9=98=9F=E5=88=97=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8个文件操作回调从LOG_I stub改为完整实现 文件路径: /file/, /zip/ 依赖: libfunc(func_proc_self_dir/make_dirs), libmd5 支持: FTU→RTU文件接收, RTU→FTU文件发送, MD5校验 - 新增dc_soe/dc_fault/dc_disturb_event_t事件结构 self_ptl_cb填充saddr/status/timestamp后入队 解决void*入队后消费者无法识别数据类型的问题 --- src/public/libdatacenter/inc/myDatacenter.h | 51 ++ src/system/libself_ptl/inc/self_ptl.h | 9 + src/system/libself_ptl/src/self_ptl_cb.cpp | 500 +++++++++++++++----- 3 files changed, 429 insertions(+), 131 deletions(-) diff --git a/src/public/libdatacenter/inc/myDatacenter.h b/src/public/libdatacenter/inc/myDatacenter.h index 6064e77..51b01f7 100644 --- a/src/public/libdatacenter/inc/myDatacenter.h +++ b/src/public/libdatacenter/inc/myDatacenter.h @@ -473,6 +473,57 @@ int dc_get_signal_info_by_id(const char *type_str, uint32_t id, * 事件/扰动/故障队列 * ================================================================== */ +/** + * @brief SOE 事件数据 (推入 dc_event_queue) + * @field saddr 信号短地址 + * @field status 状态值 + * @field tm_sec 时间戳 (秒) + * @field tm_ms 时间戳 (毫秒) + * @field attr 属性 (扩展字段) + */ +typedef struct +{ + char saddr[DC_SADDR_MAX_LEN]; + uint8_t status; + uint32_t tm_sec; + uint16_t tm_ms; + uint8_t attr; +} dc_soe_event_t; + +/** + * @brief 扰动录波数据 (推入 dc_disturb_dd_queue) + * @field saddr 信号短地址 + * @field f_val 扰动值 + * @field tm_sec 时间戳 (秒) + * @field tm_ms 时间戳 (毫秒) + */ +typedef struct +{ + char saddr[DC_SADDR_MAX_LEN]; + float f_val; + uint32_t tm_sec; + uint16_t tm_ms; +} dc_disturb_event_t; + +/** + * @brief 故障事件数据 (推入 dc_fault_queue) + * @field saddr 信号短地址 + * @field fault_id 故障编号 + * @field st_count 包含的遥信数量 + * @field mx_count 包含的遥测数量 + * @field tm_sec 时间戳 (秒) + * @field tm_ms 时间戳 (毫秒) + */ +typedef struct +{ + char saddr[DC_SADDR_MAX_LEN]; + uint32_t fault_id; + uint8_t st_count; + uint8_t mx_count; + uint32_t tm_sec; + uint16_t tm_ms; +} dc_fault_event_t; + /** @brief SOE 事件入队 */ int dc_event_queue_push(void *p_soe); diff --git a/src/system/libself_ptl/inc/self_ptl.h b/src/system/libself_ptl/inc/self_ptl.h index 1ece563..d1de36d 100644 --- a/src/system/libself_ptl/inc/self_ptl.h +++ b/src/system/libself_ptl/inc/self_ptl.h @@ -98,6 +98,15 @@ typedef struct std::vector default_value; }stru_self_ptl_cfg_param; +/* 文件目录条目 (dir_pop_out 回调使用) */ +typedef struct +{ + char name[256]; + uint8_t len; + uint32_t attr; + uint32_t size; +}stru_dir_info; + typedef struct { bool init; diff --git a/src/system/libself_ptl/src/self_ptl_cb.cpp b/src/system/libself_ptl/src/self_ptl_cb.cpp index acaff07..b6a23d7 100644 --- a/src/system/libself_ptl/src/self_ptl_cb.cpp +++ b/src/system/libself_ptl/src/self_ptl_cb.cpp @@ -1,34 +1,157 @@ /** * @file self_ptl_cb.cpp - * @brief 自协议回调实现 — ICP67 decode 输出 → 数据中心 + * @brief 自协议回调实现 — ICP67 decode 输出 → 数据中心 + 文件操作 */ #include "myBase.h" #include "myLog.h" +#include "myFunc.h" +#include "myMd5.h" #include "myIcp67.h" #include "myDatacenter.h" #include "self_ptl.h" #include +#include #include +#include +#include -/* ---- 回调: 内部参数读取出 (ao_pop_out) ---- */ +/* =========================== 文件操作辅助 =========================== */ + +static std::string g_file_base_path; +static std::string g_file_path; +static std::string g_zip_path; +static int g_paths_ready = 0; + +static void file_paths_init(void) +{ + char proc_dir[512] = {0}; + + if(g_paths_ready) return; + + if(0 != func_proc_self_dir(proc_dir, sizeof(proc_dir))) + { + LOG_E("file_paths_init: func_proc_self_dir failed"); + return; + } + + g_file_base_path = std::string(proc_dir); + 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()); + + g_paths_ready = 1; + LOG_I("file_paths_init: file=%s, zip=%s", g_file_path.c_str(), g_zip_path.c_str()); +} + +static FILE *file_open(const char *file_name, const char *mode) +{ + if(NULL == file_name || NULL == mode) return NULL; + return fopen(file_name, mode); +} + +static int file_close(FILE *fp) +{ + if(NULL == fp) return -1; + return fclose(fp); +} + +static int file_write(const char *file_name, uint32_t offset, uint8_t *p_data, uint16_t len) +{ + FILE *fp; + + if(NULL == file_name || NULL == p_data) return -1; + + fp = file_open(file_name, "ab"); + if(NULL == fp) return -1; + + if(0 != fseek(fp, offset, SEEK_SET)) + { + LOG_E("file_write: seek failed"); + file_close(fp); + return -1; + } + + if(len != fwrite(p_data, 1, len, fp)) + { + LOG_E("file_write: write failed"); + file_close(fp); + return -1; + } + + file_close(fp); + return 0; +} + +static int file_read(const char *file_name, uint32_t offset, uint8_t *p_data, uint16_t len) +{ + FILE *fp; + + if(NULL == file_name || NULL == p_data) return -1; + + fp = file_open(file_name, "rb"); + if(NULL == fp) return -1; + + if(0 != fseek(fp, offset, SEEK_SET)) + { + LOG_E("file_read: seek failed"); + file_close(fp); + return -1; + } + + if(len != fread(p_data, 1, len, fp)) + { + LOG_E("file_read: read failed"); + file_close(fp); + return -1; + } + + file_close(fp); + return 0; +} + +static int file_size_get(const char *file_name, uint32_t *p_size) +{ + FILE *fp; + + if(NULL == file_name || NULL == p_size) return -1; + + fp = file_open(file_name, "rb"); + if(NULL == fp) return -1; + + if(0 != fseek(fp, 0, SEEK_END)) + { + LOG_E("file_size_get: seek failed"); + file_close(fp); + return -1; + } + + *p_size = (uint32_t)ftell(fp); + file_close(fp); + + return 0; +} + +/* =========================== 文件操作状态 =========================== */ + +static std::string g_dir_name = ""; +static std::string g_file_name = ""; +static std::string g_zip_name = ""; +static std::vector g_dir_info_vec; +static stru_md5_ctx g_file_md5_ctx; +static int g_md5_started = 0; + +/* =========================== 回调: 内部参数读取出 =========================== */ void ao_pop_out(stru_icp67 *p_icp67, uint16_t addr, uint8_t type, uint8_t len, uint8_t *p_data) { (void)p_icp67; - (void)addr; - (void)type; - (void)len; - (void)p_data; - /* - * AO 参数值返回 → 写入数据中心对应信号。 - * saddr 格式: "self_ptl.ao." - */ { char saddr[64]; - snprintf(saddr, sizeof(saddr), "self_ptl.ao.%d", addr); dc_set_out_signal_val(saddr, p_data, MODULE_SELF_PTL); } @@ -42,239 +165,354 @@ void iec_point_tbl_pop_out(stru_icp67 *p_icp67, uint16_t info_addr, uint16_t num { (void)p_icp67; (void)p_data; - LOG_I("iec_point_tbl_pop_out: info_addr=%d, num=%d", info_addr, num); - /* - * IEC 点表数据返回 — 由应用层解析并写入数据中心。 - * 当前仅记录日志, 具体处理待 PLC/IEC 模块实现。 - */ } -/* ---- 回调: 自检读取出 → 数据中心 self_ptl.st.* 信号 ---- */ +/* ---- 回调: 自检读取出 ---- */ void self_check_pop_out(stru_icp67 *p_icp67, stru_data_info *p_data, uint16_t addr) { (void)p_icp67; + if(NULL == p_data) return; - if(NULL == p_data) - { - return; - } - - /* - * 自检信号映射: addr 对应 self_ptl.st. 信号, - * 值根据 data_type 直接写入数据中心。 - * 例: addr=70 "自检-文件系统挂载异常" → self_ptl.st.70 - */ { char saddr[64]; - snprintf(saddr, sizeof(saddr), "self_ptl.st.%d", addr); dc_set_out_signal_val(saddr, p_data->data, MODULE_SELF_PTL); } } -/* ---- 回调: 目录读取出 ---- */ +/* =========================== 文件操作回调 =========================== */ + +/* ---- 目录读取出 ---- */ void dir_pop_out(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, uint32_t attr, uint32_t size, uint8_t follow) { - (void)p_icp67; - (void)attr; - (void)follow; + stru_dir_info dir_info; - char name_buf[257] = {0}; + if(NULL == p_icp67 || NULL == p_name) return; - if(len < sizeof(name_buf)) + memcpy(dir_info.name, p_name, len); + dir_info.name[len] = '\0'; + dir_info.len = len; + dir_info.attr = attr; + dir_info.size = size; + g_dir_info_vec.push_back(dir_info); + + if(0 == follow) { - memcpy(name_buf, p_name, len); + LOG_I("dir_pop_out: %d files in %s", (int)g_dir_info_vec.size(), g_dir_name.c_str()); + for(uint16_t i = 0; i < g_dir_info_vec.size(); i++) + { + LOG_I(" %s (size=%d)", g_dir_info_vec[i].name, g_dir_info_vec[i].size); + } + g_dir_info_vec.clear(); } - - LOG_I("dir_pop_out: name=%s, size=%d, follow=%d", name_buf, size, follow); } -/* ---- 回调: 读文件激活确认 ---- */ +/* ---- 读文件激活确认 ---- */ void file_read_act_confirm(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, uint32_t id, uint32_t size, uint16_t crc) { - (void)p_icp67; + if(NULL == p_icp67 || NULL == p_name) return; - char name_buf[257] = {0}; + file_paths_init(); + g_file_name = std::string((char *)p_name, len); - if(len < sizeof(name_buf)) + LOG_I("file_read_act_confirm: name=%s, id=%d, size=%d, crc=0x%04X", + g_file_name.c_str(), id, size, crc); + + /* 删除旧文件, 准备接收新数据 */ { - memcpy(name_buf, p_name, len); + std::string fpath = g_file_path + g_dir_name + "/" + g_file_name; + func_make_dirs((g_file_path + g_dir_name).c_str()); + unlink(fpath.c_str()); } - - LOG_I("file_read_act_confirm: name=%s, id=%d, size=%d, crc=%d", - name_buf, id, size, crc); } -/* ---- 回调: 读文件内容 ---- */ +/* ---- 读文件内容 (FTU → RTU 本地写入) ---- */ void file_read(stru_icp67 *p_icp67, uint32_t id, uint32_t offset, uint32_t follow, uint8_t *p_data, uint16_t len) { - (void)p_icp67; - (void)p_data; + if(NULL == p_icp67 || NULL == p_data) return; - LOG_I("file_read: id=%d, offset=%d, follow=%d, len=%d", id, offset, follow, len); + if(0 == offset) + { + LOG_I("file_read: %s start", g_file_name.c_str()); + } + + { + std::string fpath = g_file_path + g_dir_name + "/" + g_file_name; + file_write(fpath.c_str(), offset, p_data, len); + } + + if(0 == follow) + { + LOG_I("file_read: %s complete", g_file_name.c_str()); + } + + /* 确认接收 */ + if(p_icp67->method.file_read_confirm_cb) + { + p_icp67->method.file_read_confirm_cb(p_icp67, 0, id, offset + len); + } } -/* ---- 回调: 写文件激活确认 ---- */ +/* ---- 写文件激活确认 (RTU → FTU 发送文件) ---- */ void file_write_act_confirm(stru_icp67 *p_icp67, uint8_t result, uint8_t *p_name, uint8_t len, uint32_t id, uint32_t size) { - (void)p_icp67; + if(NULL == p_icp67 || NULL == p_name) return; - char name_buf[257] = {0}; - - if(len < sizeof(name_buf)) + if(FILE_WRITE_ACT_0 != result) { - memcpy(name_buf, p_name, len); + LOG_E("file_write_act_confirm: result=%d, abort", result); + return; } - LOG_I("file_write_act_confirm: name=%s, id=%d, size=%d, result=%d", - name_buf, id, size, result); + file_paths_init(); + g_file_name = std::string((char *)p_name, len); + + { + std::string fpath = g_file_path + g_dir_name + "/" + g_file_name; + uint8_t follow = 0; + uint16_t frame_len = 0; + + if(size > FILE_TRANS_FRMAE_LEN) + { + follow = 1; + frame_len = FILE_TRANS_FRMAE_LEN; + } + else + { + frame_len = (uint16_t)size; + } + + uint8_t file_data[FILE_TRANS_FRMAE_LEN] = {0}; + file_read(fpath.c_str(), 0, file_data, frame_len); + + if(p_icp67->method.file_write_cb) + { + p_icp67->method.file_write_cb(p_icp67, id, 0, follow, file_data, frame_len); + } + + md5_start(&g_file_md5_ctx); + md5_update(&g_file_md5_ctx, file_data, frame_len); + g_md5_started = 1; + } } -/* ---- 回调: 写文件确认 ---- */ +/* ---- 写文件确认 (继续发送后续帧) ---- */ void file_write_confirm(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint32_t offset) { - (void)p_icp67; + if(NULL == p_icp67) return; - LOG_I("file_write_confirm: id=%d, offset=%d, result=%d", id, offset, result); + { + std::string fpath = g_file_path + g_dir_name + "/" + g_file_name; + uint32_t size = 0; + uint8_t follow = 0; + uint16_t frame_len; + + file_size_get(fpath.c_str(), &size); + + if((size - offset) > FILE_TRANS_FRMAE_LEN) + { + follow = 1; + frame_len = FILE_TRANS_FRMAE_LEN; + } + else + { + frame_len = (uint16_t)(size - offset); + } + + 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); + } + + if(g_md5_started) + { + md5_update(&g_file_md5_ctx, file_data, frame_len); + } + } + + (void)result; } -/* ---- 回调: 写文件结束 ---- */ +/* ---- 写文件结束 (MD5 校验) ---- */ void file_write_end(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint32_t offset, uint8_t *md5) { - (void)p_icp67; - (void)md5; + uint8_t file_md5[16] = {0}; + uint8_t final_result = result; - LOG_I("file_write_end: id=%d, offset=%d, result=%d", id, offset, result); + if(NULL == p_icp67 || NULL == md5) return; + + if(g_md5_started) + { + md5_final(&g_file_md5_ctx, file_md5); + + if(0 != memcmp(md5, file_md5, 16)) + { + LOG_E("file_write_end: MD5 mismatch"); + final_result = 1; + } + + g_md5_started = 0; + } + + if(0 == final_result) + { + LOG_I("file_write_end: %s success", g_file_name.c_str()); + } + else + { + LOG_E("file_write_end: %s failed", g_file_name.c_str()); + } + + if(p_icp67->method.file_write_end_confirm_cb) + { + p_icp67->method.file_write_end_confirm_cb(p_icp67, final_result, id, file_md5); + } + + (void)offset; } -/* ---- 回调: 压缩目录读取出 ---- */ +/* ---- 压缩目录读取出 ---- */ void zip_dir_pop_out(stru_icp67 *p_icp67, uint8_t zip_type, uint8_t *zip_name, uint8_t len, uint8_t file_num, stru_zip_file_info *p_file_info) { - (void)p_icp67; - (void)p_file_info; + if(NULL == p_icp67 || NULL == zip_name || NULL == p_file_info) return; - char name_buf[257] = {0}; + g_zip_name = std::string((char *)zip_name, len); - if(len < sizeof(name_buf)) + LOG_I("zip_dir_pop_out: type=%d, name=%s, files=%d", zip_type, g_zip_name.c_str(), file_num); + for(uint8_t i = 0; i < file_num; i++) { - memcpy(name_buf, zip_name, len); + LOG_I(" [%d] %s (size=%d)", p_file_info[i].id, p_file_info[i].name, p_file_info[i].size); } - - LOG_I("zip_dir_pop_out: type=%d, name=%s, files=%d", zip_type, name_buf, file_num); } -/* ---- 回调: 压缩文件读取出 ---- */ +/* ---- 压缩文件内容 (FTU → RTU 本地写入 zip/) ---- */ void zip_file_pop_out(stru_icp67 *p_icp67, uint8_t id, uint32_t offset, uint8_t *p_data, uint16_t len) { - (void)p_icp67; - (void)p_data; + if(NULL == p_icp67 || NULL == p_data) return; - LOG_I("zip_file_pop_out: id=%d, offset=%d, len=%d", id, offset, len); + file_paths_init(); + + { + 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()); + } } -/* ---- 回调: MX 遥测传输 → 数据中心 ---- */ +/* =========================== 实时数据 + 事件队列 =========================== */ -void mx_trans(stru_icp67 *p_icp67, uint16_t info_addr, float p_data) -{ - (void)p_icp67; - - char saddr[128]; - - snprintf(saddr, sizeof(saddr), "self_ptl.mx.%d", info_addr); - dc_set_out_signal_val(saddr, &p_data, MODULE_SELF_PTL); -} - -/* ---- 回调: ST 遥信传输 → 数据中心 ---- */ - -void st_trans(stru_icp67 *p_icp67, uint16_t info_addr, uint8_t p_data) -{ - (void)p_icp67; - - char saddr[128]; - - snprintf(saddr, sizeof(saddr), "self_ptl.st.%d", info_addr); - dc_set_out_signal_val(saddr, &p_data, MODULE_SELF_PTL); -} - -/* ---- 回调: DD 电度传输 → 数据中心 ---- */ - -void dd_trans(stru_icp67 *p_icp67, uint16_t info_addr, float p_data) -{ - (void)p_icp67; - - char saddr[128]; - - snprintf(saddr, sizeof(saddr), "self_ptl.dd.%d", info_addr); - dc_set_out_signal_val(saddr, &p_data, MODULE_SELF_PTL); -} - -/* ---- 回调: SOE 事件传输 ---- */ +/* ---- SOE 事件 → dc_soe_event_t → 数据中心事件队列 ---- */ void soe_trans(stru_icp67 *p_icp67, stru_st_info *p_data) { (void)p_icp67; + if(NULL == p_data) return; - if(NULL == p_data) { - return; + dc_soe_event_t *p_ev = new dc_soe_event_t(); + + snprintf(p_ev->saddr, sizeof(p_ev->saddr), "self_ptl.st.%d", p_data->addr); + p_ev->status = p_data->status; + p_ev->attr = p_data->attr; + p_ev->tm_sec = 0; /* TODO: 解析 ICP67 stru_tm_6bit 时间戳 */ + p_ev->tm_ms = 0; + + dc_event_queue_push((void *)p_ev); } LOG_I("soe_trans: addr=%d, status=%d", p_data->addr, p_data->status); - - /* SOE 事件 → 数据中心事件队列 */ - dc_event_queue_push((void *)p_data); } -/* ---- 回调: 故障事件传输 → 数据中心故障队列 ---- */ +/* ---- 故障事件 → dc_fault_event_t → 数据中心故障队列 ---- */ void fault_trans(stru_icp67 *p_icp67, uint16_t num, stru_fault_info *p_data) { - (void)p_icp67; - (void)num; + (void)p_icp67; (void)num; + if(NULL == p_data) return; - if(NULL == p_data) { - return; + dc_fault_event_t *p_ev = new dc_fault_event_t(); + + snprintf(p_ev->saddr, sizeof(p_ev->saddr), "self_ptl.fault.%d", num); + p_ev->fault_id = num; + p_ev->st_count = p_data->st_num; + p_ev->mx_count = p_data->mx_num; + p_ev->tm_sec = 0; + p_ev->tm_ms = 0; + + dc_fault_queue_push((void *)p_ev); } LOG_I("fault_trans: st_count=%d, mx_count=%d", p_data->st_num, p_data->mx_num); - - /* 故障事件 → 数据中心故障队列 */ - dc_fault_queue_push((void *)p_data); } -/* ---- 回调: 遥测扰动传输 → 数据中心扰动队列 ---- */ +/* ---- 遥测扰动 → dc_disturb_event_t → 数据中心扰动队列 ---- */ void mx_change(stru_icp67 *p_icp67, stru_mx_info *p_data) { (void)p_icp67; + if(NULL == p_data) return; - if(NULL == p_data) { - return; + dc_disturb_event_t *p_ev = new dc_disturb_event_t(); + + snprintf(p_ev->saddr, sizeof(p_ev->saddr), "self_ptl.mx.%d", p_data->addr); + p_ev->f_val = (float)p_data->data; + p_ev->tm_sec = 0; + p_ev->tm_ms = 0; + + dc_disturb_dd_queue_push((void *)p_ev); } LOG_I("mx_change: addr=%d, data=%d", p_data->addr, p_data->data); - - /* 遥测扰动 → 数据中心扰动队列 */ - dc_disturb_dd_queue_push((void *)p_data); } + +void mx_trans(stru_icp67 *p_icp67, uint16_t info_addr, float p_data) +{ + (void)p_icp67; + char saddr[128]; + snprintf(saddr, sizeof(saddr), "self_ptl.mx.%d", info_addr); + dc_set_out_signal_val(saddr, &p_data, MODULE_SELF_PTL); +} + +void st_trans(stru_icp67 *p_icp67, uint16_t info_addr, uint8_t p_data) +{ + (void)p_icp67; + char saddr[128]; + snprintf(saddr, sizeof(saddr), "self_ptl.st.%d", info_addr); + dc_set_out_signal_val(saddr, &p_data, MODULE_SELF_PTL); +} + +void dd_trans(stru_icp67 *p_icp67, uint16_t info_addr, float p_data) +{ + (void)p_icp67; + char saddr[128]; + snprintf(saddr, sizeof(saddr), "self_ptl.dd.%d", info_addr); + dc_set_out_signal_val(saddr, &p_data, MODULE_SELF_PTL); +} +