#pragma once

#include "myBase.h"

#define ICP67_DEV_ADDR 1
#define ICP67_TX_MAX_LEN 2048

struct _icp67;
typedef struct _icp67 stru_icp67;

#define ICP67_RX_FLAG 0x01
#define ICP67_TX_FLAG 0x02
#define ICP67_RESEND_MAX 5


#define DEV_MAINTENANCE_ADDR    0 // 维护软件设备地址
#define DEV_RK3562_ADDR         1 // RK3562设备地址

#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;  // 协议头
    uint16_t len;   // 报文长度
    uint8_t head2;  // 协议头
    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()

// 无数据
#pragma pack(1)
typedef struct
{
    uint16_t data_addr; // 数据地址
    uint8_t data_type;  // 数据类型
    uint8_t data_len;  // 数据长度
}stru_ti_1_2_data;
#pragma pack()


// 有数据
#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()

typedef struct
{
    uint8_t id;
    uint8_t len;
    uint8_t name[256];
    uint32_t size;
}stru_zip_file_info;


#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;

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_param_get_cb)(stru_icp67 *p_icp67, stru_ti_1_2_data *p_data, uint16_t num);
typedef void (*icp67_param_pop_out_cb)(stru_icp67 *p_icp67, uint16_t addr, uint8_t type, uint8_t len, uint8_t *p_data);
typedef void (*icp67_param_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_param_get_cb                  param_get_cb;            // 内部参数读取回调函数
    icp67_param_pop_out_cb              param_pop_out_cb;        // 内部参数读取出回调函数
    icp67_param_set_cb                  param_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;

extern void icp67_set_param_get_cb(icp67_param_get_cb *p_cb);                           // 设置参数获取回调函数
extern void icp67_set_param_pop_out_cb(icp67_param_pop_out_cb cb);                      // 设置参数数据返回回调函数
extern void icp67_set_param_set_cb(icp67_param_set_cb *p_cb);                           // 设置参数设置回调函数
extern void icp67_set_iec_point_tbl_get_cb(icp67_iec_point_tbl_get_cb *p_cb);           // 设置iec点表获取回调函数
extern void icp67_set_iec_point_tbl_pop_out_cb(icp67_iec_point_tbl_pop_out_cb cb);      // 设置iec点表数据返回回调函数
extern void icp67_set_time_set_cb(icp67_time_set_cb *p_cb);                             // 设置时间设置回调函数
extern void icp67_set_self_check_get_cb(icp67_self_check_get_cb *p_cb);                 // 设置自检获取回调函数
extern void icp67_set_self_check_pop_out_cb(icp67_self_check_pop_out_cb cb);            // 设置自检数据返回回调函数
extern void icp67_set_upgrade_start_cb(icp67_upgrade_start_cb *p_cb);                   // 设置升级开始回调函数

extern void icp67_set_dir_read_cb(icp67_dir_read_cb *p_cb);                             // 设置目录读取回调函数
extern void icp67_set_dir_pop_out_cb(icp67_dir_pop_out_cb cb);                          // 设置目录数据返回回调函数
extern void icp67_set_file_read_act_cb(icp67_file_read_act_cb *p_cb);                   // 设置读文件激活回调函数
extern void icp67_set_file_read_act_confirm_cb(icp67_file_read_act_confirm_cb cb);      // 设置读文件激活确认回调函数
extern void icp67_set_file_read_cb(icp67_file_read_cb cb);                              // 设置读文件回调函数
extern void icp67_set_file_read_confirm_cb(icp67_file_read_confirm_cb *p_cb);           // 设置读文件确认回调函数
extern void icp67_set_file_write_act_cb(icp67_file_write_act_cb *p_cb);                 // 设置写文件激活回调函数
extern void icp67_set_file_write_act_confirm_cb(icp67_file_write_act_confirm_cb cb);    // 设置写文件激活确认回调函数
extern void icp67_set_file_write_cb(icp67_file_write_cb *p_cb);                         // 设置写文件回调函数
extern void icp67_set_file_write_confirm_cb(icp67_file_write_confirm_cb cb);            // 设置写文件确认回调函数
extern void icp67_set_file_write_end_cb(icp67_file_write_end_cb cb);                    // 设置写文件结束回调函数
extern void icp67_set_file_write_end_confirm_cb(icp67_file_write_end_confirm_cb *p_cb); // 设置写文件结束确认回调函数

extern void icp67_set_zip_dir_pop_out_cb(icp67_zip_dir_pop_out_cb cb);                  // 设置压缩目录数据返回回调函数
extern void icp67_set_zip_file_pop_out_cb(icp67_zip_file_pop_out_cb cb);                // 设置压缩文件数据返回回调函数

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


typedef struct _icp67
{
    void *arg;
    icp67_send_cb           send_cb;
    icp67_search_frame_cb   search_frame_cb;
    icp67_decode_cb         decode_cb;
    icp67_timer_handler_cb  timer_handler_cb;
    

    uint8_t                 md5[16];
    uint8_t                 tx[ICP67_TX_MAX_LEN];
    uint16_t                tx_len;
    uint8_t                 resend_tx[ICP67_TX_MAX_LEN];
    uint16_t                resend_tx_len;
    uint8_t                 rtx_flag;
    sem_t                   rtx_sem;
    uint8_t                 resend_cnt;
    uint32_t                tm_out;
    uint32_t                tm_cnt;

    bool test;
}icp67;


void icp67_init(stru_icp67 *p_icp67, icp67_send_cb send_cb, void *arg);
int icp67_set_param_cfg_md5(stru_icp67 *p_icp67, uint8_t *p_md5);


