/**
 * @file    myIcp67.h
 * @brief   ICP67 自定义协议公共头文件 — 帧结构、回调类型、协议实例、常量宏
 * @details 本文件为 libicp67 协议库与 libself_ptl 应用层的共享契约。
 *          所有对外接口使用 extern "C" 包裹，兼容 C/C++ 调用者。
 */

#ifndef _MY_ICP67_H_
#define _MY_ICP67_H_

#include "myBase.h"

#ifdef __cplusplus
extern "C" {
#endif

/* =========================== 常量宏 =========================== */

#define ICP67_TX_BUF_SIZE    2048   /**< tx/resend_tx 缓冲区大小 */
#define ICP67_RESEND_MAX_DEF 5      /**< 重发最大次数 (默认值) */
#define ICP67_TM_TICK_MS     10     /**< 定时器 tick 周期 (ms) */
#define ICP67_TM_OUT_DEF_MS  1000   /**< 重传超时 ms (默认值) */
#define ICP67_MD5_LEN        16     /**< MD5 长度 */

#define ICP67_RX_FLAG        0x01   /**< 接收标志 */
#define ICP67_TX_FLAG        0x02   /**< 发送标志 */

/* =========================== 设备地址 =========================== */

#define DEV_MAINTENANCE_ADDR 0      /**< 维护软件设备地址 */
#define DEV_RK3562_ADDR      1      /**< RK3562 设备地址 */
#define DEV_SAMPL_ADDR       3      /**< 采样板设备地址 */

/* =========================== 信息体地址 =========================== */

#define MX_INFO_ADDR         100    /**< 遥测组合编码 信息体地址 */
#define ST_INFO_ADDR         101    /**< 遥信组合编码 信息体地址 */
#define CO_INFO_ADDR         102    /**< 遥控组合编码 信息体地址 */
#define AO_INFO_ADDR         103    /**< 定值参数组合编码 信息体地址 */
#define DD_INFO_ADDR         104    /**< 电能量组合编码 信息体地址 */

#define MX_OPER_INFO_ADDR    200    /**< 遥测一体化运维 信息体地址 */
#define ST_OPER_INFO_ADDR    201    /**< 遥信一体化运维 信息体地址 */

/* =========================== 升级相关 =========================== */

#define UP_CMD               1      /**< 执行升级命令 */
#define UP_RESULT_1          1      /**< 升级成功 */
#define UP_RESULT_2          2      /**< 无升级文件 */
#define UP_RESULT_3          3      /**< MD5 不匹配 */
#define UP_RESULT_4          4      /**< 固件信息不对 */

#define FILE_TRANS_FRMAE_LEN 800    /**< 文件传输帧长度 */

/* =========================== 文件操作 =========================== */

#define FILE_WRITE_ACT_0     0      /**< 写文件激活 成功 */
#define FILE_WRITE_ACT_1     1      /**< 写文件激活 未知错误 */
#define FILE_WRITE_ACT_2     2      /**< 写文件激活 文件名不支持 */
#define FILE_WRITE_ACT_3     3      /**< 写文件激活 长度超范围 */

#define FILE_WRITE_CONT_0    0      /**< 写文件内容 文件成功(最后一帧) */
#define FILE_WRITE_CONT_1    1      /**< 写文件内容 段成功(中间帧) */
#define FILE_WRITE_CONT_2    2      /**< 写文件内容 未知错误 */
#define FILE_WRITE_CONT_3    3      /**< 写文件内容 校验和不匹配 */
#define FILE_WRITE_CONT_4    4      /**< 写文件内容 文件长度不对应 */
#define FILE_WRITE_CONT_5    5      /**< 写文件内容 文件ID不对应 */

/* =========================== 帧结构定义 =========================== */

#pragma pack(1)
typedef struct
{
	uint8_t  head1;      /**< 协议头 0x67 */
	uint16_t len;        /**< 报文长度 (info_addr + dev_addr + data) */
	uint8_t  head2;      /**< 协议头 0x67 */
	uint8_t  src;        /**< 源设备 */
	uint8_t  dst;        /**< 目标设备 */
	uint8_t  dir;        /**< 方向 */
	uint8_t  ti;         /**< 类型标识 */
	uint8_t  cot;        /**< 传输原因 */
	uint16_t info_addr;  /**< 信息地址 */
	uint32_t dev_addr;   /**< 终端地址 */
	uint8_t  data[0];    /**< 数据区 (柔性数组) */
}stru_head;
#pragma pack()

/* 无数据 — TI_1/TI_2 参数条目描述 */
#pragma pack(1)
typedef struct
{
	uint16_t data_addr;  /**< 数据地址 */
	uint8_t  data_type;  /**< 数据类型 */
	uint8_t  data_len;   /**< 数据长度 */
}stru_ti_1_2_data;
#pragma pack()

/* 有数据 — TI_1/TI_2 参数条目 + 值 */
#pragma pack(1)
typedef struct
{
	uint16_t data_addr;  /**< 数据地址 */
	uint8_t  data_type;  /**< 数据类型 */
	uint8_t  data_len;   /**< 数据长度 */
	uint8_t  data[0];    /**< 数据 (柔性数组) */
}stru_ti_1_2_data_info;
#pragma pack()

/* 终端时间 */
#pragma pack(1)
typedef struct
{
	uint16_t ms;         /**< 毫秒 */
	uint8_t  min;        /**< 分钟 */
	uint8_t  hour;       /**< 小时 */
	uint8_t  day;        /**< 日期 */
	uint8_t  month;      /**< 月份 */
	uint8_t  year;       /**< 年份 */
}stru_ti_5;
#pragma pack()

/* 通用数据段 */
#pragma pack(1)
typedef struct
{
	uint8_t data_type;   /**< 数据类型 */
	uint8_t data_len;    /**< 数据长度 */
	uint8_t data[0];     /**< 数据 (柔性数组) */
}stru_data_info;
#pragma pack()

/* ZIP 文件信息 */
typedef struct
{
	uint8_t  id;
	uint8_t  len;
	uint8_t  name[256];
	uint32_t size;
}stru_zip_file_info;

/* 6字节时间 */
#pragma pack(1)
typedef struct
{
	uint16_t t1;
	uint32_t t2;
}stru_tm_6bit;
#pragma pack()

/* 单个遥信数据 */
#pragma pack(1)
typedef struct
{
	uint16_t     addr;    /**< SOE 地址 */
	uint8_t      status;  /**< SOE 状态 */
	uint8_t      attr;    /**< SOE 属性 */
	stru_tm_6bit tm;      /**< SOE 时间 */
}stru_st_info;
#pragma pack()

/* 单个遥测数据 */
#pragma pack(1)
typedef struct
{
	uint16_t addr;        /**< 遥测地址 */
	int      data;        /**< 遥测数据 float→int */
}stru_mx_info;
#pragma pack()

/* 故障信息 */
typedef struct
{
	uint8_t       st_num;
	stru_st_info *p_st_info;
	uint8_t       mx_num;
	stru_mx_info *p_mx_info;
}stru_fault_info;

/* =========================== 回调函数类型定义 =========================== */

struct _icp67;
typedef struct _icp67 stru_icp67;

typedef void (*icp67_send_cb)(uint8_t *p_tx, uint16_t tx_len, void *arg);
typedef int  (*icp67_search_frame_cb)(uint8_t *p_data, uint16_t len, uint16_t *p_pos, uint16_t *p_valid_len);
typedef int  (*icp67_decode_cb)(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
typedef void (*icp67_timer_handler_cb)(stru_icp67 *p_icp67);

typedef void (*icp67_ao_get_cb)(stru_icp67 *p_icp67, stru_ti_1_2_data *p_data, uint16_t num);
typedef void (*icp67_ao_pop_out_cb)(stru_icp67 *p_icp67, uint16_t addr, uint8_t type, uint8_t len, uint8_t *p_data);
typedef void (*icp67_ao_set_cb)(stru_icp67 *p_icp67, uint8_t *p_data, uint16_t num);
typedef void (*icp67_iec_point_tbl_get_cb)(stru_icp67 *p_icp67, uint16_t info_addr);
typedef void (*icp67_iec_point_tbl_pop_out_cb)(stru_icp67 *p_icp67, uint16_t info_addr, uint16_t num, uint8_t *p_data);
typedef void (*icp67_time_set_cb)(stru_icp67 *p_icp67, stru_ti_5 *p_time);
typedef void (*icp67_self_check_get_cb)(stru_icp67 *p_icp67);
typedef void (*icp67_self_check_pop_out_cb)(stru_icp67 *p_icp67, stru_data_info *p_data, uint16_t addr);
typedef void (*icp67_upgrade_start_cb)(stru_icp67 *p_icp67, uint8_t dst);

typedef void (*icp67_dir_read_cb)(stru_icp67 *p_icp67, uint8_t *p_dir, uint8_t len, uint8_t *tm_start, uint8_t *tm_end);
typedef void (*icp67_dir_pop_out_cb)(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, uint32_t attr, uint32_t size, uint8_t follow);
typedef void (*icp67_file_read_act_cb)(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len);
typedef void (*icp67_file_read_act_confirm_cb)(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, uint32_t id, uint32_t size, uint16_t crc);
typedef void (*icp67_file_read_cb)(stru_icp67 *p_icp67, uint32_t id, uint32_t offset, uint32_t follow, uint8_t *p_data, uint16_t len);
typedef void (*icp67_file_read_confirm_cb)(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint32_t offset);
typedef void (*icp67_file_write_act_cb)(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, uint32_t id, uint32_t size, uint16_t crc);
typedef void (*icp67_file_write_act_confirm_cb)(stru_icp67 *p_icp67, uint8_t result, uint8_t *p_name, uint8_t len, uint32_t id, uint32_t size);
typedef void (*icp67_file_write_cb)(stru_icp67 *p_icp67, uint32_t id, uint32_t offset, uint8_t follow, uint8_t *p_data, uint16_t len);
typedef void (*icp67_file_write_confirm_cb)(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint32_t offset);
typedef void (*icp67_file_write_end_cb)(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint32_t offset, uint8_t *md5);
typedef void (*icp67_file_write_end_confirm_cb)(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint8_t *md5);

typedef void (*icp67_zip_dir_pop_out_cb)(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);
typedef void (*icp67_zip_file_pop_out_cb)(stru_icp67 *p_icp67, uint8_t id, uint32_t offset, uint8_t *p_data, uint16_t len);

typedef void (*icp67_mx_trans_cb)(stru_icp67 *p_icp67, uint16_t info_addr, float p_data);
typedef void (*icp67_st_trans_cb)(stru_icp67 *p_icp67, uint16_t info_addr, uint8_t p_data);
typedef void (*icp67_dd_trans_cb)(stru_icp67 *p_icp67, uint16_t info_addr, float p_data);
typedef void (*icp67_soe_trans_cb)(stru_icp67 *p_icp67, stru_st_info *p_data);
typedef void (*icp67_fault_trans_cb)(stru_icp67 *p_icp67, uint16_t num, stru_fault_info *p_data);
typedef void (*icp67_mx_change_cb)(stru_icp67 *p_icp67, stru_mx_info *p_data);

/* =========================== 回调表结构体 =========================== */

typedef struct
{
	icp67_ao_get_cb                 ao_get_cb;                   /**< 内部参数读取回调 */
	icp67_ao_pop_out_cb             ao_pop_out_cb;               /**< 内部参数读取出回调 */
	icp67_ao_set_cb                 ao_set_cb;                   /**< 外部修改参数设置回调 */
	icp67_iec_point_tbl_get_cb      iec_point_tbl_get_cb;        /**< 内部 IEC 表读取回调 */
	icp67_iec_point_tbl_pop_out_cb  iec_point_tbl_pop_out_cb;    /**< 内部 IEC 表读取出回调 */
	icp67_time_set_cb               time_set_cb;                 /**< 时间设置回调 */
	icp67_self_check_get_cb         self_check_get_cb;           /**< 自检读取回调 */
	icp67_self_check_pop_out_cb     self_check_pop_out_cb;       /**< 自检读取出回调 */
	icp67_upgrade_start_cb          upgrade_start_cb;            /**< 升级开始回调 */

	icp67_dir_read_cb               dir_read_cb;                 /**< 目录读取回调 */
	icp67_dir_pop_out_cb            dir_pop_out_cb;              /**< 目录读取出回调 */
	icp67_file_read_act_cb          file_read_act_cb;            /**< 文件读取回调 */
	icp67_file_read_act_confirm_cb  file_read_act_confirm_cb;    /**< 文件读取确认回调 */
	icp67_file_read_cb              file_read_cb;                /**< 文件读取回调 */
	icp67_file_read_confirm_cb      file_read_confirm_cb;        /**< 文件读取确认回调 */
	icp67_file_write_act_cb         file_write_act_cb;           /**< 文件写入回调 */
	icp67_file_write_act_confirm_cb file_write_act_confirm_cb;   /**< 文件写入确认回调 */
	icp67_file_write_cb             file_write_cb;               /**< 文件写入回调 */
	icp67_file_write_confirm_cb     file_write_confirm_cb;       /**< 文件写入确认回调 */
	icp67_file_write_end_cb         file_write_end_cb;           /**< 文件写入结束回调 */
	icp67_file_write_end_confirm_cb file_write_end_confirm_cb;   /**< 文件写入结束确认回调 */

	icp67_zip_dir_pop_out_cb        zip_dir_pop_out_cb;          /**< 压缩目录读取出回调 */
	icp67_zip_file_pop_out_cb       zip_file_pop_out_cb;         /**< 压缩文件读取出回调 */

	icp67_mx_trans_cb               mx_trans_cb;                 /**< MX 通讯回调 */
	icp67_st_trans_cb               st_trans_cb;                 /**< ST 通讯回调 */
	icp67_dd_trans_cb               dd_trans_cb;                 /**< DD 通讯回调 */
	icp67_soe_trans_cb              soe_trans_cb;                /**< SOE 通讯回调 */
	icp67_fault_trans_cb            fault_trans_cb;              /**< 故障通讯回调 */
	icp67_mx_change_cb              mx_change_cb;                /**< MX 变更回调 */
}stru_genneral_method;

/* =========================== 协议实例结构体 =========================== */

typedef struct _icp67
{
	void                    *arg;              /**< 用户数据 (interface ID) */
	icp67_send_cb            send_cb;          /**< 发送回调 (→ libself_ptl) */
	icp67_search_frame_cb    search_frame_cb;  /**< 帧搜索回调 (内部) */
	icp67_decode_cb          decode_cb;        /**< 解码回调 (内部) */
	icp67_timer_handler_cb   timer_handler_cb; /**< 定时器回调 (内部) */

	stru_genneral_method     method;           /**< 回调表 (实例化，替代全局变量) */

	uint8_t                  md5[ICP67_MD5_LEN];        /**< AO 参数 MD5 */
	uint8_t                  tx[ICP67_TX_BUF_SIZE];      /**< 发送缓冲区 */
	uint16_t                 tx_len;                     /**< 发送数据长度 */
	uint8_t                  resend_tx[ICP67_TX_BUF_SIZE]; /**< 重发备份缓冲区 */
	uint16_t                 resend_tx_len;              /**< 重发数据长度 */
	uint8_t                  rtx_flag;                   /**< 重传标志 */
	sem_t                    rtx_sem;                    /**< 重传信号量 */
	uint8_t                  resend_max;                 /**< 重发最大次数 (可配置) */
	uint8_t                  resend_cnt;                 /**< 重发计数 */
	uint32_t                 tm_out_ms;                  /**< 超时 ms (可配置) */
	uint32_t                 tm_out;                     /**< 超时阈值 (tick数, =tm_out_ms/TM_TICK_MS) */
	uint32_t                 tm_cnt;                     /**< 当前 tick 计数 */

	uint8_t                  test;                       /**< 测试标志 */
}icp67;

/* =========================== 对外 API =========================== */

/**
 * @brief 初始化 ICP67 协议实例
 * @param p_icp67  协议实例指针
 * @param send_cb  发送回调 (→物理层)
 * @param arg      用户参数 (interface ID)
 */
void icp67_init(stru_icp67 *p_icp67, icp67_send_cb send_cb, void *arg,
		uint32_t tm_out_ms, uint8_t resend_max);

/**
 * @brief 设置 AO 参数配置的 MD5 校验值
 * @param p_icp67  协议实例指针
 * @param p_md5    16 字节 MD5 值
 * @return 0 成功, -1 失败
 */
int icp67_set_ao_cfg_md5(stru_icp67 *p_icp67, uint8_t *p_md5);

/**
 * @brief 环形缓冲区帧搜索 (零拷贝)
 * @param buf    环形缓冲区基址
 * @param size   缓冲区总大小
 * @param rptr   读指针
 * @param cnt    有效数据长度
 * @param p_pos  输出: 帧偏移
 * @param p_valid_len 输出: 帧长度
 * @return 0 找到, -1 未找到
 */
extern int icp67_search_frame_in_ring(const uint8_t *buf, uint16_t size,
	uint16_t rptr, uint16_t cnt,
	uint16_t *p_pos, uint16_t *p_valid_len);

/* =========================== 回调注册 setter (17个) =========================== */

extern void icp67_set_ao_pop_out_cb(stru_icp67 *p_icp67, icp67_ao_pop_out_cb cb);
extern void icp67_set_iec_point_tbl_pop_out_cb(stru_icp67 *p_icp67, icp67_iec_point_tbl_pop_out_cb cb);
extern void icp67_set_self_check_pop_out_cb(stru_icp67 *p_icp67, icp67_self_check_pop_out_cb cb);

extern void icp67_set_dir_pop_out_cb(stru_icp67 *p_icp67, icp67_dir_pop_out_cb cb);
extern void icp67_set_file_read_act_confirm_cb(stru_icp67 *p_icp67, icp67_file_read_act_confirm_cb cb);
extern void icp67_set_file_read_cb(stru_icp67 *p_icp67, icp67_file_read_cb cb);
extern void icp67_set_file_write_act_confirm_cb(stru_icp67 *p_icp67, icp67_file_write_act_confirm_cb cb);
extern void icp67_set_file_write_confirm_cb(stru_icp67 *p_icp67, icp67_file_write_confirm_cb cb);
extern void icp67_set_file_write_end_cb(stru_icp67 *p_icp67, icp67_file_write_end_cb cb);

extern void icp67_set_zip_dir_pop_out_cb(stru_icp67 *p_icp67, icp67_zip_dir_pop_out_cb cb);
extern void icp67_set_zip_file_pop_out_cb(stru_icp67 *p_icp67, icp67_zip_file_pop_out_cb cb);

extern void icp67_set_mx_trans_cb(stru_icp67 *p_icp67, icp67_mx_trans_cb cb);
extern void icp67_set_st_trans_cb(stru_icp67 *p_icp67, icp67_st_trans_cb cb);
extern void icp67_set_dd_trans_cb(stru_icp67 *p_icp67, icp67_dd_trans_cb cb);
extern void icp67_set_soe_trans_cb(stru_icp67 *p_icp67, icp67_soe_trans_cb cb);
extern void icp67_set_fault_trans_cb(stru_icp67 *p_icp67, icp67_fault_trans_cb cb);
extern void icp67_set_mx_change_cb(stru_icp67 *p_icp67, icp67_mx_change_cb cb);

#ifdef __cplusplus
}
#endif

#endif /* _MY_ICP67_H_ */
