fix(self_ptl): 文件操作回调实现 + 事件队列数据结构修复

- 8个文件操作回调从LOG_I stub改为完整实现
  文件路径: <exe_dir>/file/, <exe_dir>/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*入队后消费者无法识别数据类型的问题
This commit is contained in:
ypc 2026-07-09 18:04:00 +08:00
parent 920524945d
commit ae1329aacc
3 changed files with 429 additions and 131 deletions

View File

@ -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 事件入队 */ /** @brief SOE 事件入队 */
int dc_event_queue_push(void *p_soe); int dc_event_queue_push(void *p_soe);

View File

@ -98,6 +98,15 @@ typedef struct
std::vector<std::string> default_value; std::vector<std::string> default_value;
}stru_self_ptl_cfg_param; }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 typedef struct
{ {
bool init; bool init;

View File

@ -1,34 +1,157 @@
/** /**
* @file self_ptl_cb.cpp * @file self_ptl_cb.cpp
* @brief ICP67 decode * @brief ICP67 decode +
*/ */
#include "myBase.h" #include "myBase.h"
#include "myLog.h" #include "myLog.h"
#include "myFunc.h"
#include "myMd5.h"
#include "myIcp67.h" #include "myIcp67.h"
#include "myDatacenter.h" #include "myDatacenter.h"
#include "self_ptl.h" #include "self_ptl.h"
#include <string> #include <string>
#include <vector>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h>
/* ---- 回调: 内部参数读取出 (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<stru_dir_info> 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 ao_pop_out(stru_icp67 *p_icp67, uint16_t addr, uint8_t type, uint8_t len, uint8_t *p_data)
{ {
(void)p_icp67; (void)p_icp67;
(void)addr;
(void)type;
(void)len;
(void)p_data;
/*
* AO
* saddr : "self_ptl.ao.<addr>"
*/
{ {
char saddr[64]; char saddr[64];
snprintf(saddr, sizeof(saddr), "self_ptl.ao.%d", addr); snprintf(saddr, sizeof(saddr), "self_ptl.ao.%d", addr);
dc_set_out_signal_val(saddr, p_data, MODULE_SELF_PTL); 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_icp67;
(void)p_data; (void)p_data;
LOG_I("iec_point_tbl_pop_out: info_addr=%d, num=%d", info_addr, num); 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 self_check_pop_out(stru_icp67 *p_icp67, stru_data_info *p_data, uint16_t addr)
{ {
(void)p_icp67; (void)p_icp67;
if(NULL == p_data) return;
if(NULL == p_data)
{
return;
}
/*
* : addr self_ptl.st.<addr> ,
* data_type
* : addr=70 "自检-文件系统挂载异常" self_ptl.st.70
*/
{ {
char saddr[64]; char saddr[64];
snprintf(saddr, sizeof(saddr), "self_ptl.st.%d", addr); snprintf(saddr, sizeof(saddr), "self_ptl.st.%d", addr);
dc_set_out_signal_val(saddr, p_data->data, MODULE_SELF_PTL); 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, void dir_pop_out(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len,
uint32_t attr, uint32_t size, uint8_t follow) uint32_t attr, uint32_t size, uint8_t follow)
{ {
(void)p_icp67; stru_dir_info dir_info;
(void)attr;
(void)follow;
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, 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) 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", /* ---- 读文件内容 (FTU → RTU 本地写入) ---- */
name_buf, id, size, crc);
}
/* ---- 回调: 读文件内容 ---- */
void file_read(stru_icp67 *p_icp67, uint32_t id, uint32_t offset, void file_read(stru_icp67 *p_icp67, uint32_t id, uint32_t offset,
uint32_t follow, uint8_t *p_data, uint16_t len) uint32_t follow, uint8_t *p_data, uint16_t len)
{ {
(void)p_icp67; if(NULL == p_icp67 || NULL == p_data) return;
(void)p_data;
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, 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) 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(FILE_WRITE_ACT_0 != result)
if(len < sizeof(name_buf))
{ {
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", file_paths_init();
name_buf, id, size, result); 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, void file_write_confirm(stru_icp67 *p_icp67, uint8_t result,
uint32_t id, uint32_t offset) 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, void file_write_end(stru_icp67 *p_icp67, uint8_t result, uint32_t id,
uint32_t offset, uint8_t *md5) uint32_t offset, uint8_t *md5)
{ {
(void)p_icp67; uint8_t file_md5[16] = {0};
(void)md5; 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, void zip_dir_pop_out(stru_icp67 *p_icp67, uint8_t zip_type,
uint8_t *zip_name, uint8_t len, uint8_t file_num, uint8_t *zip_name, uint8_t len, uint8_t file_num,
stru_zip_file_info *p_file_info) stru_zip_file_info *p_file_info)
{ {
(void)p_icp67; if(NULL == p_icp67 || NULL == zip_name || NULL == p_file_info) return;
(void)p_file_info;
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, void zip_file_pop_out(stru_icp67 *p_icp67, uint8_t id, uint32_t offset,
uint8_t *p_data, uint16_t len) uint8_t *p_data, uint16_t len)
{ {
(void)p_icp67; if(NULL == p_icp67 || NULL == p_data) return;
(void)p_data;
LOG_I("zip_file_pop_out: id=%d, offset=%d, len=%d", id, offset, len); file_paths_init();
}
/* ---- 回调: MX 遥测传输 → 数据中心 ---- */
void mx_trans(stru_icp67 *p_icp67, uint16_t info_addr, float p_data)
{ {
(void)p_icp67; std::string zip_fpath = g_zip_path + g_zip_name;
file_write(zip_fpath.c_str(), offset, p_data, len);
char saddr[128]; if(0 == offset) LOG_I("zip_file_pop_out: %s start", g_zip_name.c_str());
}
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) /* ---- SOE 事件 → dc_soe_event_t → 数据中心事件队列 ---- */
{
(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 事件传输 ---- */
void soe_trans(stru_icp67 *p_icp67, stru_st_info *p_data) void soe_trans(stru_icp67 *p_icp67, stru_st_info *p_data)
{ {
(void)p_icp67; (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); 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 fault_trans(stru_icp67 *p_icp67, uint16_t num, stru_fault_info *p_data)
{ {
(void)p_icp67; (void)p_icp67; (void)num;
(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); 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 mx_change(stru_icp67 *p_icp67, stru_mx_info *p_data)
{ {
(void)p_icp67; (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); 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);
}