diff --git a/src/system/libiec/src/iec104.cpp b/src/system/libiec/src/iec104.cpp index 12108e6..009da89 100644 --- a/src/system/libiec/src/iec104.cpp +++ b/src/system/libiec/src/iec104.cpp @@ -1,14 +1,11 @@ /** * @file iec104.cpp - * @brief IEC 60870-5-104 核心 — CS10x 初始化 + slot管理 + 协议参数 + 全部回调 + * @brief IEC 60870-5-104 服务端 — CS10x 初始化 + slot 管理 + 全部回调 + 收发桥接 * - * @details 本文件聚合原工程 iec.cpp + iec_yx/yc/dd/soe/fault/yk/param/file/time.cpp - * (共 12 个文件) 为单一文件,简化维护。 - * - * 设计要点: - * - 3 路 slot 复用, 超时 600s 自动回收 - * - CS10x_104Init 绑定向 com_router 发送 (MQ_COM_TO_IEC) - * - 全部 CS10x 回调注册在 set_ptl_itfc() 中 + * @details 聚合原工程 12 个子文件为单文件: + * - slot 管理: 3 路复用, 600s 超时自动回收 + * - CS10x_104Init 绑定向 com_router 发送 + * - 全部 CS10x 回调注册在 protocol_register_callbacks() * - 环形缓冲区: soe(300) / disturb_yc(200) / fault(200) / dd(50) */ @@ -20,613 +17,1228 @@ #include "iec104.h" #include "iec104_cfg.h" -/* 来自 iec104_point.cpp */ -extern int iec104_point_init(void); - #include #include #include +/* 来自 iec104_point.cpp */ +extern int iec104_point_init(void); + /* =========================== 常量 =========================== */ -#define SOE_LEN 300 -#define DISTURB_YC_LEN 200 -#define FAULT_EVENT_LEN 200 -#define FAULT_YC_NUM 8 -#define DD_LEN 50 +#define SOE_LEN 300 /**< SOE 记录缓冲区大小 */ +#define DISTURB_YC_LEN 200 /**< 扰动遥测缓冲区大小 */ +#define FAULT_EVENT_LEN 200 /**< 故障事件缓冲区大小 */ +#define FAULT_YC_NUM 8 /**< 故障遥测最大数量 */ +#define DD_LEN 50 /**< 电度记录缓冲区大小 */ -#define YX_START_PORT 0x0001 /**< 遥信 IOA 起始 */ -#define YC_START_PORT 0x4001 /**< 遥测 IOA 起始 */ -#define DD_START_PORT 0x6401 /**< 电度 IOA 起始 */ +#define YX_START_PORT 0x0001 /**< 遥信 IOA 起始 */ +#define YC_START_PORT 0x4001 /**< 遥测 IOA 起始 */ +#define DD_START_PORT 0x6401 /**< 电度 IOA 起始 */ -#define LINK_OVER_TIME 600000 /**< 链路超时 600s */ +#define LINK_OVER_TIME 600000 /**< 链路超时 600 秒 */ + +/* =========================== 环形缓冲区数据结构 =========================== */ + +/** + * @brief 每通道输出指针 — 关联协议通道与环缓冲读取位置 + */ +typedef struct +{ + uint8_t protocol; /**< 协议类型 */ + uint16_t out; /**< 出指针 */ + uint32_t ch; /**< 通道标识 */ +} st_ring_out_ptr; + +/** + * @brief 扰动遥测环形缓冲区 + */ +typedef struct +{ + bool init; + sem_t sem; + uint16_t in; + std::vector out_ptrs; + struct { uint16_t idx; float val; } yc[DISTURB_YC_LEN]; +} ring_disturb_yc_t; + +/** + * @brief SOE 事件环形缓冲区 + */ +typedef struct +{ + bool init; + sem_t sem; + uint16_t in; + std::vector out_ptrs; + struct { uint8_t st, ty; uint16_t pot, ms; uint32_t sec; } soe[SOE_LEN]; +} ring_soe_t; + +/** + * @brief 扰动电度环形缓冲区 + */ +typedef struct +{ + bool init; + sem_t sem; + uint16_t in; + std::vector out_ptrs; + struct { uint16_t idx; float val; __CP56Time2a tm; uint16_t ms; uint32_t sec; } dd[DD_LEN]; +} ring_dd_t; + +/** + * @brief 故障事件环形缓冲区 + */ +typedef struct +{ + bool init; + sem_t sem; + uint16_t in; + std::vector out_ptrs; + struct + { + iec_soe_info_t soe; + uint8_t yc_n; + iec_yc_info_t yc[FAULT_YC_NUM]; + } fault[FAULT_EVENT_LEN]; +} ring_fault_t; + +/* =========================== 全局变量 =========================== */ + +static stru_iec g_iec[MAX_IEC_NUM]; +static ring_disturb_yc_t g_yc_ring; +static ring_soe_t g_soe_ring; +static ring_dd_t g_dd_ring; +static ring_fault_t g_fault_ring; /* =========================== 前向声明 =========================== */ static int iec104_data_tx(uint8_t *p_tx, uint16_t tx_len, void *arg); -static void set_ptl_104_param(stru_iec *p_iec); -static void set_ptl_itfc(stru_iec *p_iec); +static void protocol_init_104(stru_iec *p_iec); +static void protocol_register_callbacks(stru_iec *p_iec); static void protocol_config(stru_iec *p_iec); -/* =========================== 环形缓冲区数据结构 =========================== */ +/* =========================== 环形缓冲工具 =========================== */ -typedef struct { uint8_t pcol; uint16_t out; uint32_t ch; } st_out_ptr; - -typedef struct { - bool init; sem_t sem; uint16_t in; - std::vector out_ptrs; - struct { uint16_t idx; float val; } yc[DISTURB_YC_LEN]; -} ring_disturb_yc; - -typedef struct { - bool init; sem_t sem; uint16_t in; - std::vector out_ptrs; - struct { uint8_t st, ty; uint16_t pot, ms; uint32_t sec; } soe[SOE_LEN]; -} ring_soe; - -typedef struct { - bool init; sem_t sem; uint16_t in; - std::vector out_ptrs; - struct { uint16_t idx; float val; __CP56Time2a tm; uint16_t ms; uint32_t sec; } dd[DD_LEN]; -} ring_dd; - -typedef struct { - bool init; sem_t sem; uint16_t in; - std::vector out_ptrs; - struct { iec_soe_info_t soe; uint8_t yc_n; iec_yc_info_t yc[FAULT_YC_NUM]; } fault[FAULT_EVENT_LEN]; -} ring_fault; - -/* =========================== 全局变量 =========================== */ - -static stru_iec g_iec[MAX_IEC_NUM]; -static ring_disturb_yc g_yc_ring; -static ring_soe g_soe_ring; -static ring_dd g_dd_ring; -static ring_fault g_fault_ring; - -/* =========================== 工具函数 =========================== */ - -static void ring_sem_init(bool *init, sem_t *sem) +LOCAL void ring_sem_init(bool *p_init, sem_t *p_sem) { - if(!*init) { sem_init(sem, 0, 1); *init = true; } + if (!*p_init) + { + sem_init(p_sem, 0, 1); + *p_init = true; + } } -static int ring_count(uint16_t in, uint16_t out, int size) +LOCAL int ring_count(uint16_t in_ptr, uint16_t out_ptr, int size) { - return (in >= out) ? (in - out) : (size - out + in); + if (in_ptr >= out_ptr) + { + return (int)(in_ptr - out_ptr); + } + + return (int)(size - out_ptr + in_ptr); } -static st_out_ptr *ring_out_get(void *pv, std::vector &vec, - uint8_t pcol) +LOCAL st_ring_out_ptr *ring_out_get(void *pv_param, + std::vector &vec, uint8_t protocol) { - stru_iec *p_iec = iec104_get_by_interface(*(uint32_t*)pv); - uint32_t ch = p_iec ? p_iec->interface : 0; + stru_iec *p_iec = iec104_get_by_interface(*(uint32_t *)pv_param); + uint32_t ch = (NULL != p_iec) ? p_iec->interface : 0; + uint32_t idx; + + for (idx = 0; idx < vec.size(); idx++) + { + if (vec[idx].ch == ch && vec[idx].protocol == protocol) + { + return &vec[idx]; + } + } + + st_ring_out_ptr new_ptr = { protocol, 0, ch }; + vec.push_back(new_ptr); - for(auto &o : vec) if(o.ch == ch && o.pcol == pcol) return &o; - st_out_ptr n = {pcol, 0, ch}; - vec.push_back(n); return &vec.back(); } -static void cp56_from_ts(__CP56Time2a *p, uint32_t sec, uint16_t ms) +LOCAL void cp56_from_ts(__CP56Time2a *p_time, uint32_t sec, uint16_t ms) { - struct tm st; gmtime_r((time_t*)&sec, &st); - uint16_t m = st.tm_sec * 1000 + ms; - p->ucLMs = m & 0xFF; p->ucHMs = (m>>8) & 0xFF; - p->ucMin = st.tm_min; p->ucHour = st.tm_hour; - p->ucWeek = st.tm_mday; p->ucMonth = st.tm_mon+1; p->ucYear = st.tm_year-100; + struct tm st; + uint16_t total_ms; + + gmtime_r((time_t *)&sec, &st); + + total_ms = st.tm_sec * 1000 + ms; + + p_time->ucLMs = total_ms & 0xFF; + p_time->ucHMs = (total_ms >> 8) & 0xFF; + p_time->ucMin = st.tm_min; + p_time->ucHour = st.tm_hour; + p_time->ucWeek = st.tm_mday; + p_time->ucMonth = st.tm_mon + 1; + p_time->ucYear = st.tm_year - 100; } -/* =========================== 时间回调 =========================== */ +/* =========================== 时间 & COI 回调 =========================== */ -static int cb_get_time(__CP56Time2a *p) +LOCAL int cb_get_time(__CP56Time2a *p_time) { - struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); - struct tm st; gmtime_r(&ts.tv_sec, &st); - uint16_t m = st.tm_sec*1000 + ts.tv_nsec/1000000; - p->ucLMs=m&0xFF; p->ucHMs=(m>>8)&0xFF; - p->ucMin=st.tm_min; p->ucHour=st.tm_hour; - p->ucWeek=st.tm_mday; p->ucMonth=st.tm_mon+1; p->ucYear=st.tm_year-100; + struct timespec ts; + struct tm st; + uint16_t total_ms; + + if (NULL == p_time) + { + return 0; + } + + clock_gettime(CLOCK_REALTIME, &ts); + gmtime_r(&ts.tv_sec, &st); + + total_ms = st.tm_sec * 1000 + ts.tv_nsec / 1000000; + + p_time->ucLMs = total_ms & 0xFF; + p_time->ucHMs = (total_ms >> 8) & 0xFF; + p_time->ucMin = st.tm_min; + p_time->ucHour = st.tm_hour; + p_time->ucWeek = st.tm_mday; + p_time->ucMonth = st.tm_mon + 1; + p_time->ucYear = st.tm_year - 100; + return 1; } -static int cb_set_time(__CP56Time2a *p) +LOCAL int cb_set_time(__CP56Time2a *p_time) { - struct tm st={}; - st.tm_year=p->ucYear+100; st.tm_mon=p->ucMonth-1; st.tm_mday=p->ucWeek; - st.tm_hour=p->ucHour&0x7F; st.tm_min=p->ucMin&0x3F; - uint16_t ms=p->ucLMs|((p->ucHMs&0x3F)<<8); - struct timespec ts={timegm(&st), (long)(ms%1000)*1000000L}; - clock_settime(CLOCK_REALTIME, &ts); return 1; + struct tm st; + uint16_t ms; + struct timespec ts; + + if (NULL == p_time) + { + return 0; + } + + memset(&st, 0, sizeof(st)); + st.tm_year = p_time->ucYear + 100; + st.tm_mon = p_time->ucMonth - 1; + st.tm_mday = p_time->ucWeek; + st.tm_hour = p_time->ucHour & 0x7F; + st.tm_min = p_time->ucMin & 0x3F; + + ms = p_time->ucLMs | ((p_time->ucHMs & 0x3F) << 8); + + ts.tv_sec = timegm(&st); + ts.tv_nsec = (long)(ms % 1000) * 1000000L; + clock_settime(CLOCK_REALTIME, &ts); + + return 1; } -/* =========================== COI 回调 =========================== */ +LOCAL uint8_t cb_coi_read(void) +{ + return 0; +} -static uint8_t cb_coi_read(void) { return 0; } -static void cb_coi_write(uint8_t c) { (void)c; } +LOCAL void cb_coi_write(uint8_t coi) +{ + (void)coi; +} /* =========================== YX (遥信) 回调 =========================== */ -static int32_t cb_yx_count(uint16_t g, void *pv, uint32_t *s, uint32_t *e) +LOCAL int32_t cb_yx_count(uint16_t group, void *pv_param, + uint32_t *p_start, uint32_t *p_end) { - (void)g; (void)pv; - auto &v = iec_cfg_ptr_get()->vec_st; - *s = YX_START_PORT; *e = *s + v.size(); return v.size(); + std::vector &vec = iec_cfg_ptr_get()->vec_st; + + (void)group; + (void)pv_param; + + *p_start = YX_START_PORT; + *p_end = *p_start + vec.size(); + + return (int32_t)vec.size(); } -static int32_t cb_yx_val(uint16_t g, uint16_t i, Yx_Info *p, void *pv) +LOCAL int32_t cb_yx_val(uint16_t group, uint16_t idx, + Yx_Info *pst_info, void *pv_param) { - (void)g; auto &v = iec_cfg_ptr_get()->vec_st; - if(i >= v.size()) return 0; - stru_iec *iec = iec104_get_by_interface(*(uint32_t*)pv); - auto *s = &v[i]; - p->ucStatus = s->p_data ? *(uint8_t*)s->p_data : 0; - p->uiInfoAddr = s->inf; p->ucStateType = 0; + std::vector &vec = iec_cfg_ptr_get()->vec_st; + stru_iec_sig *p_sig; + stru_iec *p_iec; - if(iec && iec->cs10x.usYxType) /* 双点 */ + (void)group; + + if (idx >= vec.size()) { - p->ucStateType = 1; - if(s->invert) + return 0; + } + + p_iec = iec104_get_by_interface(*(uint32_t *)pv_param); + p_sig = &vec[idx]; + + pst_info->ucStatus = (NULL != p_sig->p_data) ? *(uint8_t *)p_sig->p_data : 0; + pst_info->uiInfoAddr = p_sig->inf; + pst_info->ucStateType = 0; + + /* 双点遥信 */ + if (NULL != p_iec && p_iec->cs10x.usYxType) + { + pst_info->ucStateType = 1; + + if (p_sig->invert) { - if(p->ucStatus == 2) p->ucStatus = 1; - else if(p->ucStatus == 1) p->ucStatus = 2; + if (pst_info->ucStatus == 2) + { + pst_info->ucStatus = 1; + } + else if (pst_info->ucStatus == 1) + { + pst_info->ucStatus = 2; + } } } - else if(s->invert) + /* 单点遥信 + 取反 */ + else if (p_sig->invert) { - p->ucStatus = p->ucStatus ? 0 : 1; + pst_info->ucStatus = pst_info->ucStatus ? 0 : 1; } + return 1; } /* =========================== YC (遥测) 回调 =========================== */ -static int32_t cb_yc_count(uint16_t g, void *pv, uint32_t *s, uint32_t *e) +LOCAL int32_t cb_yc_count(uint16_t group, void *pv_param, + uint32_t *p_start, uint32_t *p_end) { - (void)g; (void)pv; auto &v = iec_cfg_ptr_get()->vec_mx; - *s = YC_START_PORT; *e = *s + v.size(); return v.size(); + std::vector &vec = iec_cfg_ptr_get()->vec_mx; + + (void)group; + (void)pv_param; + + *p_start = YC_START_PORT; + *p_end = *p_start + vec.size(); + + return (int32_t)vec.size(); } -static int32_t cb_yc_val(uint16_t g, uint16_t i, Yc_Info *p, void *pv) +LOCAL int32_t cb_yc_val(uint16_t group, uint16_t idx, + Yc_Info *pst_info, void *pv_param) { - (void)g; (void)pv; auto &v = iec_cfg_ptr_get()->vec_mx; - if(i >= v.size()) return 0; - auto *s = &v[i]; - float f = s->p_data ? *(float*)s->p_data : 0.0f; - p->fVal = f * s->factor + s->offset; p->uiInfoAddr = s->inf; + std::vector &vec = iec_cfg_ptr_get()->vec_mx; + stru_iec_sig *p_sig; + float raw_val; + + (void)group; + (void)pv_param; + + if (idx >= vec.size()) + { + return 0; + } + + p_sig = &vec[idx]; + raw_val = (NULL != p_sig->p_data) ? *(float *)p_sig->p_data : 0.0f; + + pst_info->fVal = raw_val * p_sig->factor + p_sig->offset; + pst_info->uiInfoAddr = p_sig->inf; + return 1; } +/* ---- 扰动遥测写入 (iec104_point.cpp 调用) ---- */ + int cb_yc_disturb_write(uint16_t idx, float val) { idx += YC_START_PORT; - ring_sem_init(&g_yc_ring.init, &g_yc_ring.sem); sem_wait(&g_yc_ring.sem); + + ring_sem_init(&g_yc_ring.init, &g_yc_ring.sem); + sem_wait(&g_yc_ring.sem); + g_yc_ring.yc[g_yc_ring.in].idx = idx; g_yc_ring.yc[g_yc_ring.in].val = val; g_yc_ring.in = (g_yc_ring.in + 1) % DISTURB_YC_LEN; - sem_post(&g_yc_ring.sem); return 1; -} -static int32_t cb_yc_disturb_get(Yc_Info *p, void *pv, uint32_t pos) -{ - auto *o = ring_out_get(pv, g_yc_ring.out_ptrs, 1); - ring_sem_init(&g_yc_ring.init, &g_yc_ring.sem); sem_wait(&g_yc_ring.sem); - uint16_t i = (pos + o->out) % DISTURB_YC_LEN; - p->uiInfoAddr = g_yc_ring.yc[i].idx; p->fVal = g_yc_ring.yc[i].val; - sem_post(&g_yc_ring.sem); return 1; -} + sem_post(&g_yc_ring.sem); -static int32_t cb_yc_disturb_num(void *pv) -{ - auto *o = ring_out_get(pv, g_yc_ring.out_ptrs, 1); - ring_sem_init(&g_yc_ring.init, &g_yc_ring.sem); sem_wait(&g_yc_ring.sem); - int n = ring_count(g_yc_ring.in, o->out, DISTURB_YC_LEN); - sem_post(&g_yc_ring.sem); return n; -} - -static int32_t cb_yc_disturb_upd(void *pv, uint32_t pos) -{ - if(!pos || !pv) return 0; - auto *o = ring_out_get(pv, g_yc_ring.out_ptrs, 1); - ring_sem_init(&g_yc_ring.init, &g_yc_ring.sem); sem_wait(&g_yc_ring.sem); - o->out = (o->out + pos) % DISTURB_YC_LEN; sem_post(&g_yc_ring.sem); return 1; } -/* =========================== SOE 回调 =========================== */ +/* ---- 扰动遥测读取 (CS10x 回调) ---- */ -int cb_soe_write(uint16_t idx, uint8_t st, uint32_t sec, uint16_t ms) +LOCAL int32_t cb_yc_disturb_get(Yc_Info *pst_info, void *pv_param, uint32_t pos) +{ + st_ring_out_ptr *p_out; + uint16_t read_idx; + + p_out = ring_out_get(pv_param, g_yc_ring.out_ptrs, 1); + + ring_sem_init(&g_yc_ring.init, &g_yc_ring.sem); + sem_wait(&g_yc_ring.sem); + + read_idx = (pos + p_out->out) % DISTURB_YC_LEN; + pst_info->uiInfoAddr = g_yc_ring.yc[read_idx].idx; + pst_info->fVal = g_yc_ring.yc[read_idx].val; + + sem_post(&g_yc_ring.sem); + + return 1; +} + +LOCAL int32_t cb_yc_disturb_num(void *pv_param) +{ + st_ring_out_ptr *p_out; + int num; + + p_out = ring_out_get(pv_param, g_yc_ring.out_ptrs, 1); + + ring_sem_init(&g_yc_ring.init, &g_yc_ring.sem); + sem_wait(&g_yc_ring.sem); + + num = ring_count(g_yc_ring.in, p_out->out, DISTURB_YC_LEN); + + sem_post(&g_yc_ring.sem); + + return num; +} + +LOCAL int32_t cb_yc_disturb_upd(void *pv_param, uint32_t pos) +{ + st_ring_out_ptr *p_out; + + if (0 == pos || NULL == pv_param) + { + return 0; + } + + p_out = ring_out_get(pv_param, g_yc_ring.out_ptrs, 1); + + ring_sem_init(&g_yc_ring.init, &g_yc_ring.sem); + sem_wait(&g_yc_ring.sem); + + p_out->out = (p_out->out + pos) % DISTURB_YC_LEN; + + sem_post(&g_yc_ring.sem); + + return 1; +} + +/* =========================== SOE 事件回调 =========================== */ + +int cb_soe_write(uint16_t idx, uint8_t status, uint32_t sec, uint16_t ms) { idx += YX_START_PORT; - ring_sem_init(&g_soe_ring.init, &g_soe_ring.sem); sem_wait(&g_soe_ring.sem); - g_soe_ring.soe[g_soe_ring.in].st = st; g_soe_ring.soe[g_soe_ring.in].pot = idx; - g_soe_ring.soe[g_soe_ring.in].sec = sec; g_soe_ring.soe[g_soe_ring.in].ms = ms; - g_soe_ring.soe[g_soe_ring.in].ty = 0; - /* 双点 YX: 状态+1, StateType=1 */ - if(iec_cfg_ptr_get()->vec_st.size() > 0) /* use YxType from cs10x later */ - ; + + ring_sem_init(&g_soe_ring.init, &g_soe_ring.sem); + sem_wait(&g_soe_ring.sem); + + g_soe_ring.soe[g_soe_ring.in].st = status; + g_soe_ring.soe[g_soe_ring.in].pot = idx; + g_soe_ring.soe[g_soe_ring.in].sec = sec; + g_soe_ring.soe[g_soe_ring.in].ms = ms; + g_soe_ring.soe[g_soe_ring.in].ty = 0; g_soe_ring.in = (g_soe_ring.in + 1) % SOE_LEN; - sem_post(&g_soe_ring.sem); return 1; + + sem_post(&g_soe_ring.sem); + + return 1; } -static int32_t cb_soe_get(SOE_Info *p, void *pv, uint32_t pos) +LOCAL int32_t cb_soe_get(SOE_Info *pst_info, void *pv_param, uint32_t pos) { - auto *o = ring_out_get(pv, g_soe_ring.out_ptrs, 2); - ring_sem_init(&g_soe_ring.init, &g_soe_ring.sem); sem_wait(&g_soe_ring.sem); - uint16_t i = (pos + o->out) % SOE_LEN; - p->uiInfoAddr = g_soe_ring.soe[i].pot; p->ucStatus = g_soe_ring.soe[i].st; - p->ucStateType = g_soe_ring.soe[i].ty; - cp56_from_ts(&p->stCTime, g_soe_ring.soe[i].sec, g_soe_ring.soe[i].ms); - sem_post(&g_soe_ring.sem); return 1; + st_ring_out_ptr *p_out; + uint16_t read_idx; + + p_out = ring_out_get(pv_param, g_soe_ring.out_ptrs, 2); + + ring_sem_init(&g_soe_ring.init, &g_soe_ring.sem); + sem_wait(&g_soe_ring.sem); + + read_idx = (pos + p_out->out) % SOE_LEN; + + pst_info->uiInfoAddr = g_soe_ring.soe[read_idx].pot; + pst_info->ucStatus = g_soe_ring.soe[read_idx].st; + pst_info->ucStateType = g_soe_ring.soe[read_idx].ty; + + cp56_from_ts(&pst_info->stCTime, g_soe_ring.soe[read_idx].sec, + g_soe_ring.soe[read_idx].ms); + + sem_post(&g_soe_ring.sem); + + return 1; } -static int32_t cb_soe_num(void *pv) +LOCAL int32_t cb_soe_num(void *pv_param) { - auto *o = ring_out_get(pv, g_soe_ring.out_ptrs, 2); - ring_sem_init(&g_soe_ring.init, &g_soe_ring.sem); sem_wait(&g_soe_ring.sem); - int n = ring_count(g_soe_ring.in, o->out, SOE_LEN); sem_post(&g_soe_ring.sem); - return n; + st_ring_out_ptr *p_out; + int num; + + p_out = ring_out_get(pv_param, g_soe_ring.out_ptrs, 2); + + ring_sem_init(&g_soe_ring.init, &g_soe_ring.sem); + sem_wait(&g_soe_ring.sem); + + num = ring_count(g_soe_ring.in, p_out->out, SOE_LEN); + + sem_post(&g_soe_ring.sem); + + return num; } -static int32_t cb_soe_upd(void *pv, uint32_t pos) +LOCAL int32_t cb_soe_upd(void *pv_param, uint32_t pos) { - if(!pos || !pv) return 0; - auto *o = ring_out_get(pv, g_soe_ring.out_ptrs, 2); - ring_sem_init(&g_soe_ring.init, &g_soe_ring.sem); sem_wait(&g_soe_ring.sem); - o->out = (o->out + pos) % SOE_LEN; sem_post(&g_soe_ring.sem); return 1; + st_ring_out_ptr *p_out; + + if (0 == pos || NULL == pv_param) + { + return 0; + } + + p_out = ring_out_get(pv_param, g_soe_ring.out_ptrs, 2); + + ring_sem_init(&g_soe_ring.init, &g_soe_ring.sem); + sem_wait(&g_soe_ring.sem); + + p_out->out = (p_out->out + pos) % SOE_LEN; + + sem_post(&g_soe_ring.sem); + + return 1; } /* =========================== DD (电度) 回调 =========================== */ -static int32_t cb_dd_count(uint16_t g, void *pv, uint32_t *s, uint32_t *e, uint8_t t) +LOCAL int32_t cb_dd_count(uint16_t group, void *pv_param, + uint32_t *p_start, uint32_t *p_end, uint8_t time_en) { - auto &v = iec_cfg_ptr_get()->vec_dd; uint32_t n = v.size(); - if(g == 0) { - if(t) return 0; - *s = DD_START_PORT; *e = *s + n; return n; + std::vector &vec = iec_cfg_ptr_get()->vec_dd; + uint32_t num = (uint32_t)vec.size(); + int split; + + (void)pv_param; + + if (group == 0) + { + if (time_en) + { + return 0; + } + + *p_start = DD_START_PORT; + *p_end = *p_start + num; + + return (int32_t)num; } - int u = 8; /* 前8个无时标 */ - if(t) { *s = DD_START_PORT + u; u = n - u; *e = *s + u; return u > 0 ? u : 0; } - *s = DD_START_PORT; *e = *s + u; return u; - (void)pv; + + /* group 1: 前 8 个不带时标, 其余带时标 */ + split = 8; + if (time_en) + { + *p_start = DD_START_PORT + split; + split = (int)num - split; + *p_end = *p_start + split; + + return (split > 0) ? split : 0; + } + + *p_start = DD_START_PORT; + *p_end = *p_start + split; + + return split; } -static int32_t cb_dd_val(uint16_t g, uint16_t i, TimeDd_Info *p, void *pv, uint8_t t) +LOCAL int32_t cb_dd_val(uint16_t group, uint16_t idx, + TimeDd_Info *pst_info, void *pv_param, uint8_t time_en) { - (void)g; (void)t; (void)pv; auto &v = iec_cfg_ptr_get()->vec_dd; - if(i >= v.size()) return 0; - p->uiInfoAddr = v[i].inf; - p->fVal = v[i].p_data ? *(float*)v[i].p_data : 0.0f; - memset(&p->stCTime, 0, sizeof(p->stCTime)); return 1; + std::vector &vec = iec_cfg_ptr_get()->vec_dd; + stru_iec_sig *p_sig; + + (void)group; + (void)time_en; + (void)pv_param; + + if (idx >= vec.size()) + { + return 0; + } + + p_sig = &vec[idx]; + + pst_info->uiInfoAddr = p_sig->inf; + pst_info->fVal = (NULL != p_sig->p_data) ? *(float *)p_sig->p_data : 0.0f; + + memset(&pst_info->stCTime, 0, sizeof(pst_info->stCTime)); + + return 1; } +/* ---- 扰动电度写入 (iec104_point.cpp 调用) ---- */ + int cb_dd_disturb_write(uint16_t idx, float val, uint32_t sec, uint16_t ms) { idx += DD_START_PORT; - ring_sem_init(&g_dd_ring.init, &g_dd_ring.sem); sem_wait(&g_dd_ring.sem); - g_dd_ring.dd[g_dd_ring.in].idx = idx; g_dd_ring.dd[g_dd_ring.in].val = val; - g_dd_ring.dd[g_dd_ring.in].sec = sec; g_dd_ring.dd[g_dd_ring.in].ms = ms; - g_dd_ring.in = (g_dd_ring.in + 1) % DD_LEN; sem_post(&g_dd_ring.sem); return 1; + + ring_sem_init(&g_dd_ring.init, &g_dd_ring.sem); + sem_wait(&g_dd_ring.sem); + + g_dd_ring.dd[g_dd_ring.in].idx = idx; + g_dd_ring.dd[g_dd_ring.in].val = val; + g_dd_ring.dd[g_dd_ring.in].sec = sec; + g_dd_ring.dd[g_dd_ring.in].ms = ms; + g_dd_ring.in = (g_dd_ring.in + 1) % DD_LEN; + + sem_post(&g_dd_ring.sem); + + return 1; } -static int32_t cb_dd_disturb_get(TimeDd_Info *p, void *pv, uint32_t pos) +/* ---- 扰动电度读取 (CS10x 回调) ---- */ + +LOCAL int32_t cb_dd_disturb_get(TimeDd_Info *pst_info, void *pv_param, uint32_t pos) { - auto *o = ring_out_get(pv, g_dd_ring.out_ptrs, 3); - ring_sem_init(&g_dd_ring.init, &g_dd_ring.sem); sem_wait(&g_dd_ring.sem); - uint16_t i = (pos + o->out) % DD_LEN; - p->uiInfoAddr = g_dd_ring.dd[i].idx; p->fVal = g_dd_ring.dd[i].val; - cp56_from_ts(&p->stCTime, g_dd_ring.dd[i].sec, g_dd_ring.dd[i].ms); - sem_post(&g_dd_ring.sem); return 1; + st_ring_out_ptr *p_out; + uint16_t read_idx; + + p_out = ring_out_get(pv_param, g_dd_ring.out_ptrs, 3); + + ring_sem_init(&g_dd_ring.init, &g_dd_ring.sem); + sem_wait(&g_dd_ring.sem); + + read_idx = (pos + p_out->out) % DD_LEN; + pst_info->uiInfoAddr = g_dd_ring.dd[read_idx].idx; + pst_info->fVal = g_dd_ring.dd[read_idx].val; + + cp56_from_ts(&pst_info->stCTime, g_dd_ring.dd[read_idx].sec, + g_dd_ring.dd[read_idx].ms); + + sem_post(&g_dd_ring.sem); + + return 1; } -static int32_t cb_dd_disturb_num(void *pv) +LOCAL int32_t cb_dd_disturb_num(void *pv_param) { - auto *o = ring_out_get(pv, g_dd_ring.out_ptrs, 3); - ring_sem_init(&g_dd_ring.init, &g_dd_ring.sem); sem_wait(&g_dd_ring.sem); - int n = ring_count(g_dd_ring.in, o->out, DD_LEN); sem_post(&g_dd_ring.sem); - return n; + st_ring_out_ptr *p_out; + int num; + + p_out = ring_out_get(pv_param, g_dd_ring.out_ptrs, 3); + + ring_sem_init(&g_dd_ring.init, &g_dd_ring.sem); + sem_wait(&g_dd_ring.sem); + + num = ring_count(g_dd_ring.in, p_out->out, DD_LEN); + + sem_post(&g_dd_ring.sem); + + return num; } -static int32_t cb_dd_disturb_upd(void *pv, uint32_t pos) +LOCAL int32_t cb_dd_disturb_upd(void *pv_param, uint32_t pos) { - if(!pos || !pv) return 0; - auto *o = ring_out_get(pv, g_dd_ring.out_ptrs, 3); - ring_sem_init(&g_dd_ring.init, &g_dd_ring.sem); sem_wait(&g_dd_ring.sem); - o->out = (o->out + pos) % DD_LEN; sem_post(&g_dd_ring.sem); return 1; + st_ring_out_ptr *p_out; + + if (0 == pos || NULL == pv_param) + { + return 0; + } + + p_out = ring_out_get(pv_param, g_dd_ring.out_ptrs, 3); + + ring_sem_init(&g_dd_ring.init, &g_dd_ring.sem); + sem_wait(&g_dd_ring.sem); + + p_out->out = (p_out->out + pos) % DD_LEN; + + sem_post(&g_dd_ring.sem); + + return 1; } /* =========================== 故障事件回调 =========================== */ -int cb_fault_write(iec_soe_info_t *soe, uint8_t yx_n, iec_yc_info_t *yc, uint8_t yc_n) +int cb_fault_write(iec_soe_info_t *p_soe, uint8_t yx_n, + iec_yc_info_t *p_yc, uint8_t yc_n) { - ring_sem_init(&g_fault_ring.init, &g_fault_ring.sem); sem_wait(&g_fault_ring.sem); - g_fault_ring.fault[g_fault_ring.in].soe = *soe; - g_fault_ring.fault[g_fault_ring.in].yc_n = (yc_n > FAULT_YC_NUM) ? FAULT_YC_NUM : yc_n; - for(int j = 0; j < g_fault_ring.fault[g_fault_ring.in].yc_n; j++) - g_fault_ring.fault[g_fault_ring.in].yc[j] = yc[j]; - g_fault_ring.in = (g_fault_ring.in + 1) % FAULT_EVENT_LEN; - sem_post(&g_fault_ring.sem); - (void)yx_n; return 1; -} + uint8_t j; -static int32_t cb_fault_get(FAULT_EVENT_Info *p, void *pv, uint32_t pos) -{ - auto *o = ring_out_get(pv, g_fault_ring.out_ptrs, 4); - ring_sem_init(&g_fault_ring.init, &g_fault_ring.sem); sem_wait(&g_fault_ring.sem); - uint16_t i = (pos + o->out) % FAULT_EVENT_LEN; - /* 第一个 SOE */ - p->staSoe[0].uiInfoAddr = g_fault_ring.fault[i].soe.info_addr; - p->staSoe[0].ucStatus = g_fault_ring.fault[i].soe.status; - p->staSoe[0].ucStateType = g_fault_ring.fault[i].soe.state_type; - memset(&p->staSoe[0].stCTime, 0, sizeof(p->staSoe[0].stCTime)); - /* YC */ - p->usYcNum = g_fault_ring.fault[i].yc_n; - for(uint8_t j = 0; j < p->usYcNum && j < FAULT_YC_NUM; j++) + if (NULL == p_soe) { - p->staYc[j].uiInfoAddr = g_fault_ring.fault[i].yc[j].info_addr; - p->staYc[j].fVal = g_fault_ring.fault[i].yc[j].val; + return 0; } - sem_post(&g_fault_ring.sem); return 1; + + ring_sem_init(&g_fault_ring.init, &g_fault_ring.sem); + sem_wait(&g_fault_ring.sem); + + g_fault_ring.fault[g_fault_ring.in].soe = *p_soe; + + if (yc_n > FAULT_YC_NUM) + { + yc_n = FAULT_YC_NUM; + } + g_fault_ring.fault[g_fault_ring.in].yc_n = yc_n; + + for (j = 0; NULL != p_yc && j < yc_n; j++) + { + g_fault_ring.fault[g_fault_ring.in].yc[j] = p_yc[j]; + } + + g_fault_ring.in = (g_fault_ring.in + 1) % FAULT_EVENT_LEN; + + sem_post(&g_fault_ring.sem); + + (void)yx_n; + return 1; } -static int32_t cb_fault_num(void *pv) +LOCAL int32_t cb_fault_get(FAULT_EVENT_Info *pst_info, void *pv_param, + uint32_t pos) { - auto *o = ring_out_get(pv, g_fault_ring.out_ptrs, 4); - ring_sem_init(&g_fault_ring.init, &g_fault_ring.sem); sem_wait(&g_fault_ring.sem); - int n = ring_count(g_fault_ring.in, o->out, FAULT_EVENT_LEN); - sem_post(&g_fault_ring.sem); return n; + st_ring_out_ptr *p_out; + uint16_t read_idx; + uint8_t j; + + p_out = ring_out_get(pv_param, g_fault_ring.out_ptrs, 4); + + ring_sem_init(&g_fault_ring.init, &g_fault_ring.sem); + sem_wait(&g_fault_ring.sem); + + read_idx = (pos + p_out->out) % FAULT_EVENT_LEN; + + pst_info->staSoe[0].uiInfoAddr = g_fault_ring.fault[read_idx].soe.info_addr; + pst_info->staSoe[0].ucStatus = g_fault_ring.fault[read_idx].soe.status; + pst_info->staSoe[0].ucStateType = g_fault_ring.fault[read_idx].soe.state_type; + memset(&pst_info->staSoe[0].stCTime, 0, sizeof(pst_info->staSoe[0].stCTime)); + + pst_info->usYcNum = g_fault_ring.fault[read_idx].yc_n; + + for (j = 0; j < pst_info->usYcNum && j < FAULT_YC_NUM; j++) + { + pst_info->staYc[j].uiInfoAddr = g_fault_ring.fault[read_idx].yc[j].info_addr; + pst_info->staYc[j].fVal = g_fault_ring.fault[read_idx].yc[j].val; + } + + sem_post(&g_fault_ring.sem); + + return 1; } -static int32_t cb_fault_upd(void *pv, uint32_t pos) +LOCAL int32_t cb_fault_num(void *pv_param) { - if(!pos || !pv) return 0; - auto *o = ring_out_get(pv, g_fault_ring.out_ptrs, 4); - ring_sem_init(&g_fault_ring.init, &g_fault_ring.sem); sem_wait(&g_fault_ring.sem); - o->out = (o->out + pos) % FAULT_EVENT_LEN; sem_post(&g_fault_ring.sem); + st_ring_out_ptr *p_out; + int num; + + p_out = ring_out_get(pv_param, g_fault_ring.out_ptrs, 4); + + ring_sem_init(&g_fault_ring.init, &g_fault_ring.sem); + sem_wait(&g_fault_ring.sem); + + num = ring_count(g_fault_ring.in, p_out->out, FAULT_EVENT_LEN); + + sem_post(&g_fault_ring.sem); + + return num; +} + +LOCAL int32_t cb_fault_upd(void *pv_param, uint32_t pos) +{ + st_ring_out_ptr *p_out; + + if (0 == pos || NULL == pv_param) + { + return 0; + } + + p_out = ring_out_get(pv_param, g_fault_ring.out_ptrs, 4); + + ring_sem_init(&g_fault_ring.init, &g_fault_ring.sem); + sem_wait(&g_fault_ring.sem); + + p_out->out = (p_out->out + pos) % FAULT_EVENT_LEN; + + sem_post(&g_fault_ring.sem); + return 1; } /* =========================== YK (遥控) 回调 =========================== */ -static uint8_t cb_yk_verify(void *pv) { (void)pv; return 0; } - -static int cb_yk_set(Yk_Info *p, void *pv) +LOCAL uint8_t cb_yk_verify(void *pv_param) { - (void)pv; auto &v = iec_cfg_ptr_get()->vec_co; - for(auto &c : v) + (void)pv_param; + return 0; +} + +LOCAL int cb_yk_set(Yk_Info *pst_info, void *pv_param) +{ + std::vector &vec = iec_cfg_ptr_get()->vec_co; + uint32_t idx; + + (void)pv_param; + + for (idx = 0; idx < vec.size(); idx++) { - if(c.inf == p->uiInfoAddr && c.p_data) + if (vec[idx].inf != pst_info->uiInfoAddr || NULL == vec[idx].p_data) { - if(0 == ((stru_iec*)pv)->cs10x.usYxType) /* 单点 */ - *(uint8_t*)c.p_data = p->ucStatus; - else { /* 双点: 1→0, 2→1 */ - *(uint8_t*)c.p_data = (p->ucStatus == 1) ? 0 : - (p->ucStatus == 2) ? 1 : p->ucStatus; + continue; + } + + /* 单点遥控: 状态值直接写入 */ + if (0 == ((stru_iec *)pv_param)->cs10x.usYxType) + { + *(uint8_t *)vec[idx].p_data = pst_info->ucStatus; + } + /* 双点遥控: 1→0, 2→1 */ + else + { + if (pst_info->ucStatus == 1) + { + *(uint8_t *)vec[idx].p_data = 0; + } + else if (pst_info->ucStatus == 2) + { + *(uint8_t *)vec[idx].p_data = 1; + } + else + { + *(uint8_t *)vec[idx].p_data = pst_info->ucStatus; } } } + return 0; } /* =========================== Param (定值/参数) 回调 =========================== */ -static uint16_t cb_param_area(uint8_t t, void *h) { (void)t; (void)h; return 1; } -static uint16_t cb_param_set_area(uint16_t a, void *h) { (void)h; return a; } - -static uint8_t cb_param_add_iec(uint8_t ucAll, uint8_t ucForce, uint8_t ucType, - IECPARAM_T *p, void *pv) +LOCAL uint16_t cb_param_area(uint8_t type, void *p_handle) { - (void)ucAll; (void)ucForce; (void)ucType; (void)pv; + (void)type; + (void)p_handle; return 1; } -static uint8_t cb_param_rd_run(void *p) { (void)p; return 1; } -static uint8_t cb_param_wt_run(void *p) { (void)p; return 1; } - -static uint16_t cb_param_total(void *p) +LOCAL uint16_t cb_param_set_area(uint16_t area, void *p_handle) { - (void)p; auto &v = iec_cfg_ptr_get()->vec_ao; - return static_cast(v.size()); + (void)p_handle; + return area; } -static uint8_t cb_param_get(uint8_t t, uint16_t i, IECPARAM_T *p, void *pv) +LOCAL uint8_t cb_param_add_iec(uint8_t all, uint8_t force, uint8_t type, + IECPARAM_T *pst_val, void *p_param) { - (void)t; (void)pv; - auto &v = iec_cfg_ptr_get()->vec_ao; - if(i >= v.size()) return 0; - p->uiInfoAddr = v[i].inf; p->ucLen = 1; + (void)all; + (void)force; + (void)type; + (void)pst_val; + (void)p_param; return 1; } -/* =========================== 文件服务回调 =========================== */ - -static bool cb_dir_get(tFILEDIR_RD_SET *s, tDIR_FILE_INFO *f, uint8_t t, uint16_t i, void *info) +LOCAL uint8_t cb_param_rd_run(void *p_param) { - (void)s; (void)t; (void)info; - /* TODO: 实现目录检索, 暂返回空 */ - (void)f; (void)i; return false; + (void)p_param; + return 1; } -static int cb_dir_num(tFILEDIR_RD_SET *s) { (void)s; return 0; } - -static int cb_file_read(uint32_t off, uint8_t *b, uint16_t l, void *pv) +LOCAL uint8_t cb_param_wt_run(void *p_param) { - (void)off; (void)b; (void)l; (void)pv; + (void)p_param; + return 1; +} + +LOCAL uint16_t cb_param_total(void *p_param) +{ + std::vector &vec = iec_cfg_ptr_get()->vec_ao; + + (void)p_param; + + return (uint16_t)vec.size(); +} + +LOCAL uint8_t cb_param_get(uint8_t type, uint16_t idx, + IECPARAM_T *pst_val, void *p_param) +{ + std::vector &vec = iec_cfg_ptr_get()->vec_ao; + + (void)type; + (void)p_param; + + if (idx >= vec.size()) + { + return 0; + } + + pst_val->uiInfoAddr = vec[idx].inf; + pst_val->ucLen = 1; + + return 1; +} + +/* =========================== 文件服务回调 (空桩) =========================== */ + +LOCAL bool cb_dir_get(tFILEDIR_RD_SET *pst_set, tDIR_FILE_INFO *pst_info, + uint8_t type, uint16_t item, void *info) +{ + (void)pst_set; + (void)pst_info; + (void)type; + (void)item; + (void)info; + return false; +} + +LOCAL int cb_dir_num(tFILEDIR_RD_SET *pst_set) +{ + (void)pst_set; return 0; } -static uint8_t cb_file_wr_check(tFILE_WD_SET *s, void *p, void *u) -{ (void)s; (void)p; (void)u; return 0; } +LOCAL int cb_file_read(uint32_t offset, uint8_t *p_buf, uint16_t len, + void *pv_param) +{ + (void)offset; + (void)p_buf; + (void)len; + (void)pv_param; + return 0; +} -static int cb_file_write(uint32_t off, uint8_t *b, uint16_t l, void *f, void *u) -{ (void)off; (void)b; (void)l; (void)f; (void)u; return 0; } +LOCAL uint8_t cb_file_wr_check(tFILE_WD_SET *pst_set, void *p_param, + void *p_user) +{ + (void)pst_set; + (void)p_param; + (void)p_user; + return 0; +} -static int cb_file_wr_finish(uint8_t *md5, void *f, void *u) -{ (void)md5; (void)f; (void)u; return 0; } +LOCAL int cb_file_write(uint32_t offset, uint8_t *p_buf, uint16_t len, + void *p_file, void *p_user) +{ + (void)offset; + (void)p_buf; + (void)len; + (void)p_file; + (void)p_user; + return 0; +} + +LOCAL int cb_file_wr_finish(uint8_t *p_md5, void *p_file, void *p_user) +{ + (void)p_md5; + (void)p_file; + (void)p_user; + return 0; +} /* =========================== 协议栈初始化 =========================== */ -static void set_ptl_104_param(stru_iec *p_iec) +LOCAL void protocol_init_104(stru_iec *p_iec) { - struct CS10x_AppLayerParameters a={}; - a.iSzOfVSQ=1; a.iLinkAddr=1; a.iSzOfCOT=2; a.iSzOfCA=2; - a.iPublicAddr=1; a.iMaxSzOfAsduLen=249; a.iSzOfIOA=3; - CS10x_SetAppParameters(&p_iec->cs10x, &a); + struct CS10x_AppLayerParameters app_param; + struct CS104_APCIParameters apci_param; - struct CS104_APCIParameters api={}; - api.iK=12; api.iW=8; api.iT0=10; api.iT1=12; api.iT2=8; api.iT3=15; - CS10x_SetAPCIParameters(&p_iec->cs10x, &api); + /* 应用层参数 */ + memset(&app_param, 0, sizeof(app_param)); + app_param.iSzOfVSQ = 1; + app_param.iLinkAddr = 1; + app_param.iSzOfCOT = 2; + app_param.iSzOfCA = 2; + app_param.iPublicAddr = 1; + app_param.iMaxSzOfAsduLen = 249; + app_param.iSzOfIOA = 3; + CS10x_SetAppParameters(&p_iec->cs10x, &app_param); - CS10x_SetYcType(&p_iec->cs10x, 2); /* 浮点遥测 */ - CS10x_SetYxType(&p_iec->cs10x, 0); /* 单点遥信 */ + /* APCI 参数 */ + memset(&apci_param, 0, sizeof(apci_param)); + apci_param.iK = 12; + apci_param.iW = 8; + apci_param.iT0 = 10; + apci_param.iT1 = 12; + apci_param.iT2 = 8; + apci_param.iT3 = 15; + CS10x_SetAPCIParameters(&p_iec->cs10x, &apci_param); + + /* 数据类型配置 */ + CS10x_SetYcType(&p_iec->cs10x, 2); /* 浮点遥测 */ + CS10x_SetYxType(&p_iec->cs10x, 0); /* 单点遥信 */ CS10x_SetDdType(&p_iec->cs10x, 1); - CS10x_FrameGap(&p_iec->cs10x, 10); - CS10x_SetMultFrameEn(&p_iec->cs10x, 0); - CS10x_FaultEventEn(&p_iec->cs10x, 0); - CS10x_SetSendSoe(&p_iec->cs10x, 1); - CS10x_SetSendCos(&p_iec->cs10x, 1); - CS10x_SetYKEendFrame(&p_iec->cs10x, 0); - CS10x_SetReadFileVSQ(&p_iec->cs10x, 0); - CS10x_SetPresetContType(&p_iec->cs10x, 0); + CS10x_FrameGap(&p_iec->cs10x, 10); /* 帧间隔 */ + CS10x_SetMultFrameEn(&p_iec->cs10x, 0); /* 多帧不使能 */ + CS10x_FaultEventEn(&p_iec->cs10x, 0); /* 故障事件不使能 */ + CS10x_SetSendSoe(&p_iec->cs10x, 1); /* SOE 发送使能 */ + CS10x_SetSendCos(&p_iec->cs10x, 1); /* COS 发送使能 */ + CS10x_SetYKEendFrame(&p_iec->cs10x, 0); /* YK 结束帧不使能 */ + CS10x_SetReadFileVSQ(&p_iec->cs10x, 0); /* 读文件 VSQ */ + CS10x_SetPresetContType(&p_iec->cs10x, 0); /* 参数预置 */ } -static void set_ptl_itfc(stru_iec *p_iec) +LOCAL void protocol_register_callbacks(stru_iec *p_iec) { - CS10x *cs = &p_iec->cs10x; - CS10x_TimeRWHandler(cs, cb_get_time, cb_set_time); - CS10x_WR_ResetHandler(cs, cb_coi_read, cb_coi_write); - CS10x_S_GetYcByGroupHandler(cs, cb_yc_count, cb_yc_val); - CS10x_S_DiturbYcHandler(cs, cb_yc_disturb_get, cb_yc_disturb_num, cb_yc_disturb_upd); - CS10x_S_GetYxByGroupHandler(cs, cb_yx_count, cb_yx_val); - CS10x_S_SOEHandler(cs, cb_soe_get, cb_soe_num, cb_soe_upd); - CS10x_S_GetDdByGroupHandler(cs, cb_dd_count, cb_dd_val); - CS10x_S_DiturbDduHandler(cs, cb_dd_disturb_get, cb_dd_disturb_num, cb_dd_disturb_upd); - CS10x_S_FaultEventHandler(cs, cb_fault_num, cb_fault_get, cb_fault_upd); - CS10x_S_YkVerifyHandler(cs, cb_yk_verify); - CS10x_S_ParamAreaHandler(cs, cb_param_area, cb_param_set_area); - CS10x_S_IECParamHandler(cs, cb_param_add_iec, cb_param_rd_run, cb_param_wt_run); - CS10x_S_GetParamInfoHandler(cs, cb_param_total, cb_param_get); - CS10x_S_FileReadOprtHandler(cs, cb_dir_get, cb_dir_num, cb_file_read, NULL); - CS10x_S_FileWriteOprtHandler(cs, cb_file_write, cb_file_wr_check, cb_file_wr_finish, NULL); - CS10x_S_UpdateProcHandler(cs, NULL); - CS10x_SetYkInforHandler(cs, cb_yk_set); + CS10x *p_cs = &p_iec->cs10x; + + /* 时间 & 复位 */ + CS10x_TimeRWHandler(p_cs, cb_get_time, cb_set_time); + CS10x_WR_ResetHandler(p_cs, cb_coi_read, cb_coi_write); + + /* 遥测 */ + CS10x_S_GetYcByGroupHandler(p_cs, cb_yc_count, cb_yc_val); + CS10x_S_DiturbYcHandler(p_cs, cb_yc_disturb_get, + cb_yc_disturb_num, cb_yc_disturb_upd); + + /* 遥信 */ + CS10x_S_GetYxByGroupHandler(p_cs, cb_yx_count, cb_yx_val); + + /* SOE */ + CS10x_S_SOEHandler(p_cs, cb_soe_get, cb_soe_num, cb_soe_upd); + + /* 电度 */ + CS10x_S_GetDdByGroupHandler(p_cs, cb_dd_count, cb_dd_val); + CS10x_S_DiturbDduHandler(p_cs, cb_dd_disturb_get, + cb_dd_disturb_num, cb_dd_disturb_upd); + + /* 故障事件 */ + CS10x_S_FaultEventHandler(p_cs, cb_fault_num, cb_fault_get, cb_fault_upd); + + /* 遥控 */ + CS10x_S_YkVerifyHandler(p_cs, cb_yk_verify); + CS10x_SetYkInforHandler(p_cs, cb_yk_set); + + /* 定值/参数 */ + CS10x_S_ParamAreaHandler(p_cs, cb_param_area, cb_param_set_area); + CS10x_S_IECParamHandler(p_cs, cb_param_add_iec, cb_param_rd_run, + cb_param_wt_run); + CS10x_S_GetParamInfoHandler(p_cs, cb_param_total, cb_param_get); + + /* 文件服务 */ + CS10x_S_FileReadOprtHandler(p_cs, cb_dir_get, cb_dir_num, + cb_file_read, NULL); + CS10x_S_FileWriteOprtHandler(p_cs, cb_file_write, cb_file_wr_check, + cb_file_wr_finish, NULL); + CS10x_S_UpdateProcHandler(p_cs, NULL); } -static void protocol_config(stru_iec *p_iec) +LOCAL void protocol_config(stru_iec *p_iec) { - CS10x_104Init(&p_iec->cs10x, iec104_data_tx, (void*)&p_iec->interface, CS104_TYPE_S); - set_ptl_104_param(p_iec); - set_ptl_itfc(p_iec); + CS10x_104Init(&p_iec->cs10x, iec104_data_tx, + (void *)&p_iec->interface, CS104_TYPE_S); + + protocol_init_104(p_iec); + protocol_register_callbacks(p_iec); } /* =========================== Slot 管理 =========================== */ -static stru_iec *iec104_ptr_get(uint32_t interface, CS10x_Type t) +LOCAL stru_iec *iec104_ptr_get(uint32_t interface, CS10x_Type type) { - uint32_t max_tm = 0; uint8_t max_i = 0; uint8_t free_i = MAX_IEC_NUM; + uint32_t max_tm = 0; + uint8_t max_idx = 0; + uint8_t free_idx = MAX_IEC_NUM; + uint8_t i; + uint8_t idx; + stru_iec *p_iec; - for(uint8_t i = 0; i < MAX_IEC_NUM; i++) + for (i = 0; i < MAX_IEC_NUM; i++) { - if(interface == g_iec[i].interface) + if (interface == g_iec[i].interface) { - if(g_iec[i].is_busy) + if (g_iec[i].is_busy) { g_iec[i].tm_out = 0; - if(t == g_iec[i].iec_type) return &g_iec[i]; + + if (type == g_iec[i].iec_type) + { + return &g_iec[i]; + } + g_iec[i].is_busy = 0; } - else free_i = i; + else + { + free_idx = i; + } + } + + if (max_tm < g_iec[i].tm_out) + { + max_tm = g_iec[i].tm_out; + max_idx = i; + } + + if (!g_iec[i].is_busy && free_idx == MAX_IEC_NUM) + { + free_idx = i; } - if(max_tm < g_iec[i].tm_out) { max_tm = g_iec[i].tm_out; max_i = i; } - if(!g_iec[i].is_busy && free_i == MAX_IEC_NUM) free_i = i; } - uint8_t idx = (free_i < MAX_IEC_NUM) ? free_i : max_i; - stru_iec *p = &g_iec[idx]; - memset(p, 0, sizeof(*p)); - p->is_busy = 1; p->interface = interface; p->iec_type = t; - p->cs10x.stRecvBuf.pBuf = p->rx; p->cs10x.stRecvBuf.usBufSize = IEC_BUF_SIZE; - p->cs10x.stSendBuf.pBuf = p->tx; p->cs10x.stSendBuf.usBufSize = IEC_BUF_SIZE; - p->cs10x.stPubBuf.pBuf = p->pub; p->cs10x.stPubBuf.usBufSize = IEC_BUF_SIZE; - p->cs10x.stSendBakBuf.pBuf = p->bak; p->cs10x.stSendBakBuf.usBufSize = IEC_BUF_SIZE; - protocol_config(p); + /* 确定用哪个 slot */ + idx = (free_idx < MAX_IEC_NUM) ? free_idx : max_idx; + p_iec = &g_iec[idx]; + + /* 初始化 slot */ + memset(p_iec, 0, sizeof(stru_iec)); + p_iec->is_busy = 1; + p_iec->interface = interface; + p_iec->iec_type = type; + + /* 绑定缓冲区 */ + p_iec->cs10x.stRecvBuf.pBuf = p_iec->rx; + p_iec->cs10x.stRecvBuf.usBufSize = IEC_BUF_SIZE; + p_iec->cs10x.stSendBuf.pBuf = p_iec->tx; + p_iec->cs10x.stSendBuf.usBufSize = IEC_BUF_SIZE; + p_iec->cs10x.stPubBuf.pBuf = p_iec->pub; + p_iec->cs10x.stPubBuf.usBufSize = IEC_BUF_SIZE; + p_iec->cs10x.stSendBakBuf.pBuf = p_iec->bak; + p_iec->cs10x.stSendBakBuf.usBufSize = IEC_BUF_SIZE; + + protocol_config(p_iec); + LOG_I("iec104: slot[%d] inited, interface=0x%X", idx, interface); - return p; + + return p_iec; } stru_iec *iec104_get_by_interface(uint32_t interface) { - for(uint8_t i = 0; i < MAX_IEC_NUM; i++) - if(interface == g_iec[i].interface && g_iec[i].is_busy) + uint8_t i; + + for (i = 0; i < MAX_IEC_NUM; i++) + { + if (interface == g_iec[i].interface && g_iec[i].is_busy) + { return &g_iec[i]; + } + } + return NULL; } -/* =========================== 收发桥接 =========================== */ +/* =========================== 收发桥接 (MQ 模式) =========================== */ -static int iec104_data_tx(uint8_t *p_tx, uint16_t tx_len, void *arg) +LOCAL int iec104_data_tx(uint8_t *p_tx, uint16_t tx_len, void *arg) { - if(tx_len + sizeof(stru_msg_head) > MSG_SIZE) + stru_app *p_app; + stru_app_msg_queue *p_mq; + stru_msg_head *p_head; + stru_mq_target target; + stru_app *p_target; + uint32_t interface; + + if (tx_len + sizeof(stru_msg_head) > MSG_SIZE) { LOG_E("iec104: tx_len %d > MSG_SIZE", tx_len); return -1; } - uint32_t interface = *(uint32_t*)arg; - stru_app *p_app = app_get_ptr(ENUM_APP_IEC); - stru_app_msg_queue *p_mq; - stru_msg_head *p_head; + interface = *(uint32_t *)arg; - if(NULL == p_app) return -1; - p_head = (stru_msg_head*)p_app->rtx.tx; - p_head->interface = interface; p_head->len = tx_len; + p_app = app_get_ptr(ENUM_APP_IEC); + if (NULL == p_app) + { + LOG_E("iec104: app_get_ptr(ENUM_APP_IEC) failed"); + return -1; + } + + /* 封装消息头 */ + p_head = (stru_msg_head *)p_app->rtx.tx; + p_head->interface = interface; + p_head->len = tx_len; memcpy(p_head->data, p_tx, tx_len); + /* 投递到 MQ_IEC_TO_COM */ p_mq = app_get_msg_queue_ptr(ENUM_MQ_IEC_TO_COM); - if(NULL == p_mq || 0 != task_msg_queue_send(p_mq->p_msg_queue, p_app->rtx.tx, p_mq->msg_size)) + if (NULL == p_mq) + { + LOG_E("iec104: MQ_IEC_TO_COM not found"); return -1; + } + + if (0 != task_msg_queue_send(p_mq->p_msg_queue, p_app->rtx.tx, p_mq->msg_size)) + { + LOG_E("iec104: MQ send failed"); + return -1; + } + + /* 通知 com_router 线程 */ + target = app_get_mq_target(ENUM_MQ_IEC_TO_COM); + p_target = app_get_ptr(target.app_id); + + if (NULL != p_target && NULL != p_target->p_event) + { + task_event_send(p_target->p_event, target.event); + } - stru_mq_target tgt = app_get_mq_target(ENUM_MQ_IEC_TO_COM); - stru_app *p_tgt = app_get_ptr(tgt.app_id); - if(NULL != p_tgt && NULL != p_tgt->p_event) - task_event_send(p_tgt->p_event, tgt.event); return 0; } int iec104_data_rx(uint8_t *msg) { - stru_msg_head *p_head = (stru_msg_head*)msg; - uint32_t interface = p_head->interface; - uint8_t *p_rx = p_head->data; - uint16_t len = p_head->len; + stru_msg_head *p_head; + stru_iec *p_iec; + uint32_t interface; + uint8_t *p_rx; + uint16_t len; - if(NULL == p_rx || len < 2) return -1; + if (NULL == msg) + { + return -1; + } - /* 检测帧类型, 目前仅处理 104 (0x68 开头) */ - if(p_rx[0] != 0x68) return -1; + p_head = (stru_msg_head *)msg; + interface = p_head->interface; + p_rx = p_head->data; + len = p_head->len; - stru_iec *p_iec = iec104_ptr_get(interface, CS104_TYPE_S); - if(NULL == p_iec) { LOG_E("iec104: no free slot"); return -1; } + if (NULL == p_rx || len < 2) + { + return -1; + } + + /* 仅处理 IEC-104 帧 (0x68 开头) */ + if (p_rx[0] != 0x68) + { + return -1; + } + + p_iec = iec104_ptr_get(interface, CS104_TYPE_S); + if (NULL == p_iec) + { + LOG_E("iec104: no free slot for interface 0x%X", interface); + return -1; + } p_iec->tm_out = 0; - CS10x_DoRecv(&p_iec->cs10x, (char*)p_rx, len); + CS10x_DoRecv(&p_iec->cs10x, (char *)p_rx, len); + return 0; } -void iec104_task(uint16_t usGap) +/* =========================== 定时器任务 =========================== */ + +void iec104_task(uint16_t gap) { - for(uint8_t i = 0; i < MAX_IEC_NUM; i++) + uint8_t i; + + for (i = 0; i < MAX_IEC_NUM; i++) { - if(!g_iec[i].is_busy) continue; - g_iec[i].tm_out += usGap; - if(g_iec[i].tm_out >= LINK_OVER_TIME) + if (!g_iec[i].is_busy) { - LOG_I("iec104: slot[%d] timeout, freeing", i); + continue; + } + + g_iec[i].tm_out += gap; + + /* 超时回收 slot */ + if (g_iec[i].tm_out >= LINK_OVER_TIME) + { + LOG_I("iec104: slot[%d] timeout (%u ms), freeing", + i, g_iec[i].tm_out); memset(&g_iec[i], 0, sizeof(stru_iec)); } else { - CS10x_TimerHandle(&g_iec[i].cs10x, usGap); + CS10x_TimerHandle(&g_iec[i].cs10x, gap); } } } @@ -635,34 +1247,53 @@ void iec104_task(uint16_t usGap) LOCAL void cmd_iec(int argc, char *argv[]) { - const char *str = "iec info 查看 IEC 连接状态\n" + const char *help = + "iec info 查看 IEC-104 连接状态\n" "iec reset 清除所有连接\n"; + int i; - if(argc < 2) { printf("%s", str); return; } + if (argc < 2) + { + printf("%s", help); + return; + } - if(0 == strcmp(argv[1], "info")) + if (0 == strcmp(argv[1], "info")) { printf("===== IEC-104 Status =====\n"); - for(int i = 0; i < MAX_IEC_NUM; i++) + + for (i = 0; i < MAX_IEC_NUM; i++) { printf("slot[%d]: busy=%d type=%d if=0x%X tm_out=%u\n", - i, g_iec[i].is_busy, g_iec[i].iec_type, g_iec[i].interface, g_iec[i].tm_out); + i, g_iec[i].is_busy, g_iec[i].iec_type, + g_iec[i].interface, g_iec[i].tm_out); } - printf("SOE: in=%d YC-disturb: in=%d DD-disturb: in=%d Fault: in=%d\n", - g_soe_ring.in, g_yc_ring.in, g_dd_ring.in, g_fault_ring.in); + + printf("SOE: in=%d YC-disturb: in=%d DD-disturb: in=%d" + " Fault: in=%d\n", + g_soe_ring.in, g_yc_ring.in, + g_dd_ring.in, g_fault_ring.in); } - else if(0 == strcmp(argv[1], "reset")) + else if (0 == strcmp(argv[1], "reset")) { - for(int i = 0; i < MAX_IEC_NUM; i++) memset(&g_iec[i], 0, sizeof(stru_iec)); + for (i = 0; i < MAX_IEC_NUM; i++) + { + memset(&g_iec[i], 0, sizeof(stru_iec)); + } + LOG_I("iec: all slots reset"); } - else { printf("unknown: %s\n%s", argv[1], str); } + else + { + printf("unknown: %s\n%s", argv[1], help); + } } -LOCAL void cmd_iec_complete(const char *buf, char ***c, int *n) +LOCAL void cmd_iec_complete(const char *buf, char ***completions, int *ncomp) { - static const char *s[] = {"info", "reset"}; - cmd_sub_complete(buf, c, n, s, 2); + static const char *subs[] = { "info", "reset" }; + + cmd_sub_complete(buf, completions, ncomp, subs, 2); } CMD_REGISTER_C("iec", cmd_iec, "IEC-104 查看/重置", cmd_iec_complete); @@ -671,21 +1302,27 @@ CMD_REGISTER_C("iec", cmd_iec, "IEC-104 查看/重置", cmd_iec_complete); int app_iec_init1(void *arg) { - char dir[512] = {}; - if(0 != func_proc_self_dir(dir, sizeof(dir))) + char dir[512] = { 0 }; + + if (0 != func_proc_self_dir(dir, sizeof(dir))) { LOG_E("app_iec_init1: get_exe_dir failed"); return -1; } + std::string path = std::string(dir) + "config/IEC60870/iec1014.xml"; - if(0 != iec_cfg_parse(path.c_str())) + + if (0 != iec_cfg_parse(path.c_str())) { LOG_E("app_iec_init1: cfg parse failed: %s", path.c_str()); return -1; } - stru_app *p = (stru_app*)arg; - dc_signal_out("iec.run_cnt", "iec.run_cnt", DATA_TYPE_U32, &p->run_cnt, "iec104"); + stru_app *p_app = (stru_app *)arg; + + dc_signal_out("iec.run_cnt", "iec.run_cnt", DATA_TYPE_U32, + &p_app->run_cnt, "iec104"); + LOG_I("app_iec_init1: ok"); return 0; } @@ -693,39 +1330,72 @@ int app_iec_init1(void *arg) int app_iec_init2(void *arg) { (void)arg; - if(0 != iec104_point_init()) + + if (0 != iec104_point_init()) { LOG_E("app_iec_init2: iec104_point_init failed"); return -1; } + LOG_I("app_iec_init2: ok"); return 0; } void *app_iec(void *arg) { - if(NULL == arg) { LOG_E("app_iec: null arg"); return NULL; } - stru_app *p_app = (stru_app*)arg; - uint32_t ev; + stru_app *p_app; + stru_app_msg_queue *p_mq; + uint32_t event; - while(1) + if (NULL == arg) + { + LOG_E("app_iec: NULL arg"); + return NULL; + } + + p_app = (stru_app *)arg; + + while (1) { task_event_recv(p_app->p_event, EV_TIMER1 | EV_TIMER2 | EV_TIMER3 | EV_IEC_RX_COM, TASK_EVENT_FLAG_OR | TASK_EVENT_FLAG_CLEAR, - TASK_EVENT_WAIT_FOREVER, &ev); + TASK_EVENT_WAIT_FOREVER, + &event); - if(ev & EV_IEC_RX_COM) + /* MQ_COM_TO_IEC → decode */ + if (event & EV_IEC_RX_COM) { - stru_app_msg_queue *mq = app_get_msg_queue_ptr(ENUM_MQ_COM_TO_IEC); - if(NULL != mq) - while(0 == task_msg_queue_try_recv(mq->p_msg_queue, p_app->rtx.rx, mq->msg_size)) + p_mq = app_get_msg_queue_ptr(ENUM_MQ_COM_TO_IEC); + + if (NULL != p_mq) + { + while (0 == task_msg_queue_try_recv(p_mq->p_msg_queue, + p_app->rtx.rx, p_mq->msg_size)) + { iec104_data_rx(p_app->rtx.rx); + } + } } - if(ev & EV_TIMER1) iec104_task(10); - if(ev & EV_TIMER3) p_app->run_cnt++; - if(ev & EV_STOP) { LOG_I("app_iec: EV_STOP, exiting"); break; } + /* 10ms 定时器 */ + if (event & EV_TIMER1) + { + iec104_task(10); + } + + /* 1s 计数 */ + if (event & EV_TIMER3) + { + p_app->run_cnt++; + } + + /* 停止信号 */ + if (event & EV_STOP) + { + LOG_I("app_iec: received EV_STOP, exiting"); + break; + } } return NULL;