#include "method.h"
#include "myIcp67.h"
#include "myLog.h"

#include "myMd5.h"
#include "myCmd.h"
#include "parse_cfg.h"

#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>

#include <vector>
#include <map>
#include <string>

typedef struct
{
    uint8_t type;  // 数据类型
    uint8_t len;  // 数据长度
    uint8_t val[64];   // 数据
}stru_tlv;

typedef struct
{   
    char name[256];
    uint8_t len;
    uint32_t attr;
    uint32_t size;
}stru_dir_info;

std::vector<stru_dir_info> g_dir_info_vec;

LOCAL std::string g_file_path = "/mnt/RTU/test/file/";
LOCAL std::string g_down_path = "DOWN";

LOCAL std::string g_zip_path = "/mnt/RTU/test/zip/";

LOCAL std::string g_file_name = "";
LOCAL std::string g_zip_name = "";

MD5_CTX file_md5_ctx;

typedef struct
{
    uint16_t rx_cnt;
    uint16_t tx_cnt;
    uint16_t per_cnt;
    uint16_t offset;
}stru_local_param_get;

LOCAL stru_local_param_get g_local_param_get;

typedef struct
{
    uint8_t info_addr;
}stru_local_iec_info_get;

stru_local_iec_info_get g_local_iec_info_get;

typedef struct
{
    uint8_t sub_cmd;
    std::string temp_str;
    std::string dir_name;
    std::string file_name;
}stru_local_file;

LOCAL stru_local_file g_local_file;

LOCAL uint8_t g_flag[256] = {0};

typedef struct
{
    uint8_t zip_type;
    std::string zip_name;
    uint8_t file_num;
    stru_zip_file_info file_info[2];
}stru_local_zip_info;

stru_local_zip_info g_zip_info;

typedef struct
{
    uint32_t offset;
    uint32_t size;
}stru_local_zip_file_info;

stru_local_zip_file_info g_zip_file_info;

typedef void (*iec_point_tbl_decode)(std::vector<stru_tlv> &tlv_vec);

LOCAL void iec_point_tbl_decode_mx(std::vector<stru_tlv> &tlv_vec);
LOCAL void iec_point_tbl_decode_st(std::vector<stru_tlv> &tlv_vec);
LOCAL void iec_point_tbl_decode_co(std::vector<stru_tlv> &tlv_vec);
LOCAL void iec_point_tbl_decode_ao(std::vector<stru_tlv> &tlv_vec);
LOCAL void iec_point_tbl_decode_dd(std::vector<stru_tlv> &tlv_vec);

LOCAL void iec_point_tbl_decode_mx_oper(std::vector<stru_tlv> &tlv_vec);
LOCAL void iec_point_tbl_decode_st_oper(std::vector<stru_tlv> &tlv_vec);

LOCAL FILE *file_open(const char *file_name, const char *mode);
LOCAL int file_close(FILE *fp);
LOCAL int file_write(const char *file_name, uint32_t offset, uint8_t *p_data, uint16_t len);
LOCAL int file_read(const char *file_name, uint32_t offset, uint8_t *p_data, uint16_t len);
LOCAL int file_size_get(const char *file_name, uint32_t *p_size);

LOCAL void test_param_get(stru_icp67 *p_icp67, stru_genneral_method *p_method);
LOCAL void test_iec_point_tbl_get(stru_icp67 *p_icp67, stru_genneral_method *p_method);
LOCAL void test_time_set(stru_icp67 *p_icp67, stru_genneral_method *p_method);
LOCAL void test_self_check_get(stru_icp67 *p_icp67, stru_genneral_method *p_method);
LOCAL void test_upgrade_start(stru_icp67 *p_icp67, stru_genneral_method *p_method);
LOCAL void test_file(stru_icp67 *p_icp67, stru_genneral_method *p_method);



std::map<uint16_t, iec_point_tbl_decode> g_map_iec_point_tbl_decode = 
{
    {MX_INFO_ADDR,      iec_point_tbl_decode_mx},
    {ST_INFO_ADDR,      iec_point_tbl_decode_st},
    {CO_INFO_ADDR,      iec_point_tbl_decode_co},
    {AO_INFO_ADDR,      iec_point_tbl_decode_ao},
    {DD_INFO_ADDR,      iec_point_tbl_decode_dd},

    {MX_OPER_INFO_ADDR, iec_point_tbl_decode_mx_oper},
    {ST_OPER_INFO_ADDR, iec_point_tbl_decode_st_oper}
};

typedef void (* local_test)(stru_icp67 *p_icp67, stru_genneral_method *p_method);
std::map<uint8_t, local_test> g_map_local_test = 
{
    {1, test_param_get},
    {3, test_iec_point_tbl_get},
    {5, test_time_set},
    {6, test_self_check_get},
    {9, test_upgrade_start},
    {11, test_file},
};

LOCAL std::map<uint8_t, uint8_t> g_type_len_map = 
{
    {1,     1},
    {43,    1},
    {32,    1},
    {33,    2},
    {45,    2},
    {2,     4},
    {35,    4},
    {36,    8},
    {37,    8},
    {38,    4},
    {39,    8},
    {100,   16},
    {101,   6},
    {102,   8},
    {103,   32},
    {104,   64},
    {105,   128},
    {106,   1},
};

uint8_t self_ptl_get_type_len(uint8_t type)
{
    if(g_type_len_map.find(type) == g_type_len_map.end())
    {
        LOG_E("self_ptl_get_type_len: invalid type:%d", type);
        return 0;
    }

    return g_type_len_map[type];
}

LOCAL void param_data_show(void *p_data, std::string &dst, uint8_t type)
{
    if(NULL == p_data)
    {
        LOG_E("param_data_show: invalid parameter， p_data:%p", p_data);
        return;
    }

    char temp[64] = {0};
    char *src = NULL;

    switch(type)
    {
        case DATA_TYPE_B:
            dst = *(uint8_t *)p_data ? "true" : "false";
            break;
        case DATA_TYPE_S8:
            dst = std::to_string(*(int8_t *)p_data);
            break;
        case DATA_TYPE_U8:
            dst = std::to_string(*(uint8_t *)p_data);
            break;
        case DATA_TYPE_S16:
            dst = std::to_string(*(int16_t *)p_data);   
            break;
        case DATA_TYPE_U16:
            dst = std::to_string(*(uint16_t *)p_data);
            break;
        case DATA_TYPE_S32:
            dst = std::to_string(*(int32_t *)p_data);
            break;
        case DATA_TYPE_U32:
            dst = std::to_string(*(uint32_t *)p_data);
            break;
        case DATA_TYPE_L64:
            dst = std::to_string(*(int64_t *)p_data);
            break;
        case DATA_TYPE_UL64:
            dst = std::to_string(*(uint64_t *)p_data);
            break;
        case DATA_TYPE_F32:
            dst = std::to_string(*(float *)p_data);
            break;
        case DATA_TYPE_D64:
            dst = std::to_string(*(double *)p_data);
            break;
        case DATA_TYPE_IP:
            src = (char *)p_data;
            sprintf(temp, "%d.%d.%d.%d", (uint8_t)src[0], (uint8_t)src[1], (uint8_t)src[2], (uint8_t)src[3]);
            dst = std::string(temp);
            break;
        case DATA_TYPE_MAC:
            src = (char *)p_data;
            sprintf(temp, "%02x:%02x:%02x:%02x:%02x:%02x", (uint8_t)src[0], (uint8_t)src[1], (uint8_t)src[2], (uint8_t)src[3], (uint8_t)src[4], (uint8_t)src[5]);
            dst = std::string(temp);
            break;
        case DATA_TYPE_C1:
            src = (char *)p_data;
            sprintf(temp, "%c", src[0]);
            dst = std::string(temp);
            break;
        case DATA_TYPE_C8:
        case DATA_TYPE_C32:
        case DATA_TYPE_C64:
        // case DATA_TYPE_C128:
            dst = std::string((char *)p_data);
            break;
        default:
            dst = "unknow type";
            break;
    }
}

LOCAL void param_data_set(stru_param_cfg_data &param_data, uint16_t inf,uint8_t type, uint8_t *data)
{
    if(inf != param_data.inf || type != param_data.type)
    {
        LOG_E("data addr or type not match, data_addr:%x, data_type:%d, param_data.inf:%x, param_data.type:%d");
        return;
    }
    
    char temp[64] = {0};

    switch(param_data.type)
    {
        case DATA_TYPE_B:
            *(uint8_t *)param_data.p_data = data[0] & 0x01;
            break;
        case DATA_TYPE_S8:
            *(int8_t *)param_data.p_data = *(int8_t *)data;
            break;
        case DATA_TYPE_U8:
            *(uint8_t *)param_data.p_data = *(uint8_t *)data;
            break;
        case DATA_TYPE_S16:
            *(int16_t *)param_data.p_data = *(int16_t *)data;
            break;
        case DATA_TYPE_U16:
            *(uint16_t *)param_data.p_data = *(uint16_t *)data;
            break;
        case DATA_TYPE_S32:
            *(int32_t *)param_data.p_data = *(int32_t *)data;
            break;
        case DATA_TYPE_U32:
            *(uint32_t *)param_data.p_data = *(uint32_t *)data;
            break;
        case DATA_TYPE_L64:
            *(int64_t *)param_data.p_data = *(int64_t *)data;
            break;
        case DATA_TYPE_UL64:
            *(uint64_t *)param_data.p_data = *(uint64_t *)data;
            break;
        case DATA_TYPE_F32:
            *(float *)param_data.p_data = *(float *)data;
            break;
        case DATA_TYPE_D64:
            *(double *)param_data.p_data = *(double *)data;
            break;
        case DATA_TYPE_IP:
            // sprintf((char *)param_data.p_data, "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
            strncpy((char *)param_data.p_data, (char *)data, 4);
            break;
        case DATA_TYPE_MAC:
            // sprintf((char *)param_data.p_data, "%02x:%02x:%02x:%02x:%02x:%02x", data[0], data[1], data[2], data[3], data[4], data[5]);
            strncpy((char *)param_data.p_data, (char *)data, 8);
            break;
        case DATA_TYPE_C1:
            *(char *)param_data.p_data = (char)data[0];
            break;
        case DATA_TYPE_C8:
            strncpy((char *)param_data.p_data, (char *)data, 8);
            break;
        case DATA_TYPE_C32:
            strncpy((char *)param_data.p_data, (char *)data, 32);
            break;
        case DATA_TYPE_C64:
            strncpy((char *)param_data.p_data, (char *)data, 64);
            break;
        // case DATA_TYPE_C128:
        //     strncpy((char *)param_data.val.c128, (char *)data, 128);
        //     break;
        default:
            LOG_E("unknow type:%d", param_data.type);
            break;
    }
}

void param_pop_out(stru_icp67 *p_icp67, uint16_t addr, uint8_t type, uint8_t len, uint8_t *p_data)
{
    if(NULL == p_icp67 || NULL == p_data)
    {
        LOG_E("param_pop_out: invalid parameter");
        return;
    }

    stru_app_cfg *p_cfg = get_app_cfg_ptr();

    uint16_t pos = g_local_param_get.offset + g_local_param_get.rx_cnt;
    stru_param_cfg_data *p_param_data = &p_cfg->p_param_cfg->vec_param[pos];

    param_data_set(*p_param_data, addr, type, p_data);


    g_local_param_get.rx_cnt++;
    if(g_local_param_get.rx_cnt == g_local_param_get.tx_cnt)
    {
        g_local_param_get.offset += g_local_param_get.tx_cnt;
        g_flag[1] = 1;
    }   

    // LOG_I("rx_cnt %d, tx_cnt %d, per_cnt %d, offset %d", g_local_param_get.rx_cnt, g_local_param_get.tx_cnt, g_local_param_get.per_cnt, g_local_param_get.offset);
}

void iec_point_tbl_pop_out(stru_icp67 *p_icp67, uint16_t info_addr, uint16_t num, uint8_t *p_data)
{
    if(NULL == p_icp67 || NULL == p_data)
    {
        LOG_E("iec_point_tbl_pop_out: invalid parameter");
        return;
    }

    if(g_map_iec_point_tbl_decode.find(info_addr) == g_map_iec_point_tbl_decode.end())
    {
        LOG_E("iec_point_tbl_pop_out: invalid info_addr %d", info_addr);
        return;
    }
    
    uint16_t pos = 0;
    for(uint16_t i = 0; i < num; i++)
    {
        std::vector<stru_tlv> tlv_vec;

        uint8_t data_num = p_data[pos++];
        for(uint8_t j = 0; j < data_num; j++)
        {
            stru_tlv tlv;
            stru_data_info *p_info = (stru_data_info *)&p_data[pos];

            tlv.type = p_info->data_type;
            tlv.len = p_info->data_len;
            memcpy(tlv.val, p_info->data, tlv.len);

            tlv_vec.push_back(tlv);
            pos += sizeof(stru_data_info) + tlv.len;
        }

        if(tlv_vec.at(0).type != DATA_TYPE_U16)
        {
            LOG_E("iec_point_tbl_pop_out: invalid data_type %d", tlv_vec.at(0).type);
            continue;
        }
        g_map_iec_point_tbl_decode[info_addr](tlv_vec);
    }
}

void self_check_pop_out(stru_icp67 *p_icp67, stru_data_info *p_data, uint16_t addr)
{
    if(NULL == p_icp67 || NULL == p_data)
    {
        LOG_E("self_check_pop_out: invalid parameter");
        return;
    }

    std::string data;
    param_data_show(p_data->data, data, p_data->data_type);

    LOG_I("self_check_pop_out: addr %d, type %d, len %d, data %s", addr, p_data->data_type, p_data->data_len, data.c_str());
}

void dir_pop_out(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, uint32_t attr, uint32_t size, uint8_t follow)
{
    if(NULL == p_icp67 || NULL == p_name)
    {
        LOG_E("dir_pop_out: invalid parameter");
        return;
    }

    stru_dir_info dir_info;
    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)
    {
        LOG_I("dir_pop_out: file num %d", g_dir_info_vec.size());
        for(uint16_t i = 0; i < g_dir_info_vec.size(); i++)
        {
            LOG_I("name %s, len %d, attr %d, size %d", g_dir_info_vec[i].name, g_dir_info_vec[i].len, g_dir_info_vec[i].attr, g_dir_info_vec[i].size);
        }
    }
}

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)
{
    if(NULL == p_icp67 || NULL == p_name)
    {
        LOG_E("file_read_act_confirm: invalid parameter");
        return;
    }

    g_file_name = (char *)p_name;
    LOG_I("file_read_act_confirm: name %s, len %d, id %d, size %d, crc %04x", p_name, len, id, size, crc);

    std::string file_name = g_file_path + g_local_file.dir_name + "/" + g_file_name;
    
    if(0 == unlink(file_name.c_str()))
    {
        LOG_I("file_read_act_confirm: unlink file %s success", file_name.c_str());
    }
}

void file_read(stru_icp67 *p_icp67, uint32_t id, uint32_t offset, uint32_t follow, uint8_t *p_data, uint16_t len)
{
    if(NULL == p_icp67 || NULL == p_data)
    {
        LOG_E("file_read: invalid parameter");
        return;
    }

    if(offset == 0)
    {
        LOG_I("file_read: read file %s start", g_file_name.c_str());
    }

    std::string file_name = g_file_path + g_local_file.dir_name + "/" + g_file_name;
    file_write(file_name.c_str(), offset, p_data, len);

    if(0 == follow)
    {
        LOG_I("file_read: read file %s success", file_name.c_str());
    }

    stru_genneral_method *p_method = self_ptl_method_ptr_get();
    if(p_method && p_method->file_read_cb)
    {
        p_method->file_read_confirm_cb(p_icp67, 0, id, offset+len);
    }
}


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)
{
    if(NULL == p_icp67 || NULL == p_name)
    {
        LOG_E("file_write_act_confirm: invalid parameter");
        return;
    }

    if(result != FILE_WRITE_ACT_0)
    {
        LOG_E("file_write_act_confirm: write file %s failed", p_name);
        return;
    }

    std::string file_name = g_file_path + g_local_file.dir_name + "/" + (char *)p_name;
    g_file_name = (char *)p_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 = size;
    }
    uint8_t file_data[FILE_TRANS_FRMAE_LEN] = {0};
    file_read(file_name.c_str(), 0, file_data, frame_len);

    stru_genneral_method *p_method = self_ptl_method_ptr_get();
    if(p_method && p_method->file_write_cb)
    {
        p_method->file_write_cb(p_icp67, 0, 0, follow, file_data, frame_len);
    }

    StartMD5(&file_md5_ctx);
    EncodeMD5(&file_md5_ctx, file_data, frame_len);
}

void file_write_confirm(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint32_t offset)
{
    if(NULL == p_icp67)
    {
        LOG_E("file_write_confirm: invalid parameter");
        return;
    }

    std::string file_name = g_file_path + g_local_file.dir_name + "/" + g_file_name;
    uint32_t size = 0;
    file_size_get(file_name.c_str(), &size);

    uint8_t follow = 0;
    uint16_t frame_len = 0;

    if((size - offset) > FILE_TRANS_FRMAE_LEN)
    {
        follow = 1;
        frame_len = FILE_TRANS_FRMAE_LEN;
    }
    else
    {
        frame_len = size - offset;
    }
    uint8_t file_data[FILE_TRANS_FRMAE_LEN] = {0};
    file_read(file_name.c_str(), offset, file_data, frame_len);

    // LOG_I("ti 11 9: follow %d, frame_len %d, offset %d, size %d", follow, frame_len, offset, size);
    usleep(5000);
    stru_genneral_method *p_method = self_ptl_method_ptr_get();
    if(p_method && p_method->file_write_cb)
    {
        p_method->file_write_cb(p_icp67, id, offset, follow, file_data, frame_len);
    }

    EncodeMD5(&file_md5_ctx, file_data, frame_len);
}

void file_write_end(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint32_t offset, uint8_t *md5)
{
    if(NULL == p_icp67 || NULL == md5)
    {
        LOG_E("file_write_end: invalid parameter");
        return;
    }

    uint8_t file_md5[16] = {0};
    GetMD5(&file_md5_ctx, file_md5);

    if(0 != memcmp(md5, file_md5, 16))
    {
        LOG_E("file_write_end: md5 check failed");
        result = 1; // 0: success, 1: failed
    }

    if(0 == result)
    {
        LOG_I("file_write_end: write file %s success", g_file_name.c_str());
    }

    stru_genneral_method *p_method = self_ptl_method_ptr_get();
    if(p_method && p_method->file_write_end_confirm_cb)
    {
        p_method->file_write_end_confirm_cb(p_icp67, result, id, file_md5);
    }
}

void zip_dir_pop_out(stru_icp67 *p_icp67, uint8_t zip_type, uint8_t *zip_name, uint8_t len, uint8_t file_num, stru_zip_file_info *p_file_info)
{
    if(NULL == p_icp67 || NULL == zip_name || NULL == p_file_info)
    {
        LOG_E("zip_dir_pop_out: invalid parameter");
        return;
    }

    g_zip_info.zip_type = zip_type;
    g_zip_info.zip_name = (char *)zip_name;
    g_zip_info.file_num = file_num;
    for(uint8_t i = 0; i < file_num; i++)
    {
        memcpy(&g_zip_info.file_info[i], &p_file_info[i], sizeof(stru_zip_file_info));
    }

    LOG_I("zip_dir_pop_out: zip_type %d, zip_name %s, file_num %d", zip_type, zip_name, file_num);
    for(uint8_t i = 0; i < file_num; i++)
    {
        LOG_I("id %d, name %s, size %d", p_file_info[i].id, p_file_info[i].name, p_file_info[i].size);
    }
}

void zip_file_pop_out(stru_icp67 *p_icp67, uint8_t id, uint32_t offset, uint8_t *p_data, uint16_t len)
{
    if(NULL == p_icp67 || NULL == p_data)
    {
        LOG_E("zip_file_pop_out: invalid parameter");
        return;
    }

    if(id >= 2)
    {
        LOG_E("zip_file_pop_out: id error, id %d", id);
        return;
    }
    std::string zip_file_name = g_zip_path + (char *)g_zip_info.file_info[id].name;
    file_write(zip_file_name.c_str(), offset, p_data, len);

    if(offset == 0)
    {
        g_zip_file_info.size = g_zip_info.file_info[id].size;
        g_zip_file_info.offset = 0;

        LOG_I("file %s seg trans start", g_zip_info.file_info[id].name);
    }

    if(g_zip_file_info.offset != offset)
    {
        LOG_E("zip_file_pop_out: offset error, id %d, offset %d,%d len %d", id, g_zip_file_info.offset, offset, len);
    }

    g_zip_file_info.offset += len;

    if(g_zip_file_info.offset == g_zip_file_info.size)
    {
        LOG_I("file %s seg trans end", g_zip_info.file_info[id].name);
        g_zip_file_info.offset = 0;
    }

    if((g_zip_file_info.offset + len) == g_zip_file_info.size)
    {
        LOG_I("file %s trans err, seg offset %d, len %d, file offset %d, size %d", 
            g_zip_info.file_info[id].name, offset, len, g_zip_file_info.offset, g_zip_file_info.size);
    }
}


void mx_trans(stru_icp67 *p_icp67, uint16_t info_addr, float p_data)
{
    if(NULL == p_icp67)
    {
        LOG_E("mx_trans: invalid parameter");
        return;
    }

    stru_app_cfg *p_cfg = get_app_cfg_ptr();

    if(info_addr < p_cfg->mx_info_vec.size())
    {
        p_cfg->mx_info_vec[info_addr].data = p_data;

        if(fabs(p_cfg->mx_info_vec[info_addr].old_data - p_data) > 0.1)
        {
            // UserWriteDisturbYc(info_addr, p_data);
            // LOG_I("mx_trans: addr %d, data %f, old_data %f", info_addr, p_data, p_cfg->mx_info_vec[info_addr].old_data);
        }
        p_cfg->mx_info_vec[info_addr].old_data = p_data;
    }
}

void st_trans(stru_icp67 *p_icp67, uint16_t info_addr, uint8_t p_data)
{
    if(NULL == p_icp67)
    {
        LOG_E("st_trans: invalid parameter");
        return;
    }

    stru_app_cfg *p_cfg = get_app_cfg_ptr();


    if(info_addr < p_cfg->st_info_vec.size())
    {
        // if(p_data == 1 || p_data == 2)
        // {
        //     p_data -= 1; 
        // }
        // else
        // {
        //     p_data = 0;
        // }

        p_cfg->st_info_vec[info_addr].data = p_data;
    }
}


void dd_trans(stru_icp67 *p_icp67, uint16_t info_addr, float p_data)
{
    if(NULL == p_icp67)
    {
        LOG_E("dd_trans: invalid parameter");
        return;
    }

    LOG_I("dd_trans: info_addr %d, p_data %f", info_addr, p_data);
}

void soe_trans(stru_icp67 *p_icp67, stru_st_info *p_data)
{
    if(NULL == p_icp67 || NULL == p_data)
    {
        LOG_E("soe_trans: invalid parameter");
        return;
    }

    LOG_I("soe_trans: addr %d, status %d, attr %d, t1 %d, t2 %d", p_data->addr, p_data->status, p_data->attr, p_data->tm.t1, p_data->tm.t2);

    uint8_t status = 0;
    if(p_data->status == 1 || p_data->status == 2)
    {
        status = p_data->status - 1; 
    }
    else
    {
        status = 0;
    }

    // UserWriteSoeEvent(p_data->addr, status, p_data->tm.t2, p_data->tm.t1);
}

void fault_trans(stru_icp67 *p_icp67, uint16_t num, stru_fault_info *p_data)
{
    if(NULL == p_icp67 || NULL == p_data)
    {
        LOG_E("fault_trans: invalid parameter");
        return;
    }

    LOG_I("fault_trans: num %d", num);
    for(uint16_t i = 0; i < num; i++)
    {
        LOG_I("st num %d", p_data[i].st_num);
        stru_st_info *p_st = p_data[i].p_st_info;
        for(uint16_t j = 0; p_st && j < p_data[i].st_num; j++)
        {
            LOG_I("addr %d:%04x, status %d, attr %d, t1 %d, t2 %d", p_st[j].addr, p_st[j].addr, p_st[j].status, p_st[j].attr, p_st[j].tm.t1, p_st[j].tm.t2);
        }

        LOG_I("mx num %d", p_data[i].mx_num);
        stru_mx_info *p_mx = p_data[i].p_mx_info;
        for(uint16_t j = 0; p_mx && j < p_data[i].mx_num; j++)
        {
            LOG_I("addr %d:%04x, data %f", p_mx[j].addr, p_mx[j].addr, p_mx[j].data);
        }

        // stFAULT_EVENT_MAIN stFaultEvent;
        // stFaultEvent.ucYxNum = 1;
        // stFaultEvent.stSoe.uiInfoAddr = p_st[0].addr;
        // stFaultEvent.stSoe.ucStatus = p_st[0].status;
        // stFaultEvent.stSoe.usMs = p_st[0].tm.t1;
        // stFaultEvent.stSoe.uiSeconds = p_st[0].tm.t2;

        // stFaultEvent.ucYcNum = p_data[i].mx_num;
        // for(uint16_t j = 0; p_mx && j < p_data[i].mx_num; j++)
        // {
        //     stFaultEvent.astYc[j].uiInfoAddr = p_mx[j].addr;
        //     stFaultEvent.astYc[j].fVal = p_mx[j].data;
        // }

        // UserWriteFaultEvent(&stFaultEvent);
    }


}

void mx_change(stru_icp67 *p_icp67, stru_mx_info *p_data)
{
    if(NULL == p_icp67 || NULL == p_data)
    {
        LOG_E("mx_change: invalid parameter");
        return;
    }

    LOG_I("mx_change: addr %d, data %f", p_data->addr, p_data->data);
}




LOCAL void iec_point_tbl_decode_mx(std::vector<stru_tlv> &tlv_vec)
{
    if(tlv_vec.size() < 5)
    {  
        LOG_E("iec_point_tbl_decode_mx: invalid tlv_vec size %d", tlv_vec.size());
        return;
    }
    
    uint16_t inf = *(uint16_t *)tlv_vec[0].val;
    float factor = *(float *)tlv_vec[1].val;
    uint8_t record_flag = *(uint8_t *)tlv_vec[2].val;
    uint16_t dead_zone = *(uint16_t *)tlv_vec[3].val;
    uint16_t max_value = *(uint16_t *)tlv_vec[4].val;

    LOG_I("iec_point_tbl_decode_mx: inf %d, factor %f, record_flag %d, dead_zone %d, max_value %d", inf, factor, record_flag, dead_zone, max_value);

    stru_app_cfg *p_cfg = get_app_cfg_ptr();

    for(uint16_t i = 0; i < p_cfg->mx_info_vec.size(); i++)
    {
        if(inf == p_cfg->mx_info_vec[i].inf)
        {
            p_cfg->mx_info_vec[i].factor = factor;
            p_cfg->mx_info_vec[i].record_flag = record_flag;
            p_cfg->mx_info_vec[i].dead_zone = dead_zone;
            p_cfg->mx_info_vec[i].max_limit = max_value;
        }
    }
}

LOCAL void iec_point_tbl_decode_st(std::vector<stru_tlv> &tlv_vec)
{
    if(tlv_vec.size() < 3)
    {  
        LOG_E("iec_point_tbl_decode_st: invalid tlv_vec size %d", tlv_vec.size());
        return;
    }
    
    uint16_t inf = *(uint16_t *)tlv_vec[0].val;
    uint8_t invert = *(uint8_t *)tlv_vec[1].val;
    uint16_t debounce_time = *(uint16_t *)tlv_vec[2].val;

    LOG_I("iec_point_tbl_decode_st: inf %d, invert %d, debounce_time %d", inf, invert, debounce_time);

    stru_app_cfg *p_cfg = get_app_cfg_ptr();

    for(uint16_t i = 0; i < p_cfg->st_info_vec.size(); i++)
    {
        if(inf == p_cfg->st_info_vec[i].inf)
        {
            p_cfg->st_info_vec[i].invert = invert;
            p_cfg->st_info_vec[i].debounce_time = debounce_time;
        }
    }

}

LOCAL void iec_point_tbl_decode_co(std::vector<stru_tlv> &tlv_vec)
{
    if(tlv_vec.size() < 2)
    {  
        LOG_E("iec_point_tbl_decode_co: invalid tlv_vec size %d", tlv_vec.size());
        return;
    }
    
    uint16_t inf = *(uint16_t *)tlv_vec[0].val;
    uint8_t attr = *(uint8_t *)tlv_vec[1].val;

    LOG_I("iec_point_tbl_decode_co: inf %d, attr %d", inf, attr);

    stru_app_cfg *p_cfg = get_app_cfg_ptr();

    for(uint16_t i = 0; i < p_cfg->co_info_vec.size(); i++)
    {
        if(inf == p_cfg->co_info_vec[i].inf)
        {
            p_cfg->co_info_vec[i].ctrl_attr = attr;
        }
    }
}

LOCAL void iec_point_tbl_decode_ao(std::vector<stru_tlv> &tlv_vec)
{
    if(tlv_vec.size() < 6)
    {
        LOG_E("iec_point_tbl_decode_ao: invalid tlv_vec size %d", tlv_vec.size());
        return;
    }
    
    uint16_t inf = *(uint16_t *)tlv_vec[0].val;
    uint8_t encoding = *(uint8_t *)tlv_vec[1].val;
    uint8_t type = *(uint8_t *)tlv_vec[2].val;
    uint16_t param_addr = *(uint16_t *)tlv_vec[3].val;
    uint8_t up_dtype = *(uint8_t *)tlv_vec[4].val;
    float factor = *(float *)tlv_vec[5].val;

    LOG_I("iec_point_tbl_decode_ao: inf %d, encoding %d, type %d, param_addr %d, up_dtype %d, factor %f", inf, encoding, type, param_addr, up_dtype, factor);

    stru_app_cfg *p_cfg = get_app_cfg_ptr();

    for(uint16_t i = 0; i < p_cfg->param_info_vec.size(); i++)
    {
        if(inf == p_cfg->param_info_vec[i].inf)
        {
            p_cfg->param_info_vec[i].encoding = encoding;
            p_cfg->param_info_vec[i].type = type;
            p_cfg->param_info_vec[i].param_addr = param_addr;
            p_cfg->param_info_vec[i].up_dtype = up_dtype;
            p_cfg->param_info_vec[i].factor = factor;
        }
    }
}

LOCAL void iec_point_tbl_decode_dd(std::vector<stru_tlv> &tlv_vec)
{
    if(tlv_vec.size() < 2)
    {  
        LOG_E("iec_point_tbl_decode_dd: invalid tlv_vec size %d", tlv_vec.size());
        return;
    }
    
    uint16_t inf = *(uint16_t *)tlv_vec[0].val;
    float factor = *(float *)tlv_vec[1].val;

    LOG_I("iec_point_tbl_decode_dd: inf %d, factor %f", inf, factor);

    stru_app_cfg *p_cfg = get_app_cfg_ptr();

    for(uint16_t i = 0; i < p_cfg->dd_info_vec.size(); i++)
    {
        if(inf == p_cfg->dd_info_vec[i].inf)
        {
            p_cfg->dd_info_vec[i].factor = factor;
        }
    }
}

LOCAL void iec_point_tbl_decode_mx_oper(std::vector<stru_tlv> &tlv_vec)
{

}

LOCAL void iec_point_tbl_decode_st_oper(std::vector<stru_tlv> &tlv_vec)
{

}

LOCAL FILE *file_open(const char *file_name, const char *mode)
{
    if(NULL == file_name || NULL == mode)
    {
        return NULL;
    }

    FILE *fp = fopen(file_name, mode);
    if(NULL == fp)
    {
        LOG_E("file_open: open file %s failed", file_name);
        return NULL;
    }

    return fp;
}

LOCAL int file_close(FILE *fp)
{
    if(NULL == fp)
    {
        return -1;
    }

    int ret = fclose(fp);
    if(0 != ret)
    {
        LOG_E("file_close: close file failed");
        return -1;
    }

    return 0;
}

LOCAL int file_write(const char *file_name, uint32_t offset, uint8_t *p_data, uint16_t len)
{
    if(NULL == file_name || NULL == p_data)
    {
        return -1;
    }

    FILE *fp = file_open(file_name, "ab");
    if(NULL == fp)
    {
        return -1;
    }

    if(fseek(fp, offset, SEEK_SET) != 0)
    {
        LOG_E("file_write: seek file failed");
        file_close(fp);
        return -1;
    }

    if(fwrite(p_data, 1, len, fp) != len)
    {
        LOG_E("file_write: write file failed");
        file_close(fp);
        return -1;
    }

    file_close(fp);

    return 0;
}

LOCAL int file_read(const char *file_name, uint32_t offset, uint8_t *p_data, uint16_t len)
{
    if(NULL == file_name || NULL == p_data)
    {
        return -1;
    }

    FILE *fp = file_open(file_name, "rb");
    if(NULL == fp)
    {
        return -1;
    }

    if(fseek(fp, offset, SEEK_SET) != 0)
    {
        LOG_E("file_read: seek file failed");
        file_close(fp);
        return -1;
    }

    if(fread(p_data, 1, len, fp) != len)
    {
        LOG_E("file_read: read file failed");
        file_close(fp);
        return -1;
    }

    file_close(fp);

    return 0;
}

LOCAL int file_size_get(const char *file_name, uint32_t *p_size)
{
    if(NULL == file_name || NULL == p_size)
    {
        return -1;
    }

    FILE *fp = file_open(file_name, "rb");
    if(NULL == fp)
    {
        return -1;
    }

    if(fseek(fp, 0, SEEK_END) != 0)
    {
        LOG_E("file_size_get: seek file failed");
        file_close(fp);
        return -1;
    }

    *p_size = ftell(fp);

    file_close(fp);

    return 0;
}


LOCAL void test_param_get(stru_icp67 *p_icp67, stru_genneral_method *p_method)
{
    stru_app_cfg *p_cfg = get_app_cfg_ptr();
    uint16_t cnt = 0;

    if(g_local_param_get.offset >= p_cfg->p_param_cfg->vec_param.size())
    {
        for(uint16_t i = 0; i < p_cfg->p_param_cfg->vec_param.size(); i++)
        {
            stru_param_cfg_data *p_data = &p_cfg->p_param_cfg->vec_param[i];

            std::string val = "";
            param_data_show(p_data->p_data, val, p_data->type);
            printf("inf %04x, type %04d, len %04d, val %s\n", p_data->inf, p_data->type, g_type_len_map[p_data->type], val.c_str());
        }

        g_flag[1] = 0;
        return;
    }
    uint16_t i = 0;

    if(p_cfg->p_param_cfg->vec_param[g_local_param_get.offset].type == DATA_TYPE_C32)
    {
        g_local_param_get.per_cnt = 10;
    }

    stru_ti_1_2_data data[g_local_param_get.per_cnt] = {0};
    for(i = g_local_param_get.offset; cnt < g_local_param_get.per_cnt && i < p_cfg->p_param_cfg->vec_param.size(); i++,cnt++)
    {

        data[cnt].data_addr = p_cfg->p_param_cfg->vec_param[i].inf;
        data[cnt].data_type = p_cfg->p_param_cfg->vec_param[i].type;
        data[cnt].data_len = g_type_len_map[data[cnt].data_type];
    }

    g_flag[1] = 0;

    g_local_param_get.rx_cnt = 0;
    g_local_param_get.tx_cnt = cnt;

    LOG_I("param_get: i %d, cnt %d, tx_cnt %d, offset %d, size %d", i, cnt, g_local_param_get.tx_cnt, g_local_param_get.offset, p_cfg->p_param_cfg->vec_param.size());
    p_method->param_get_cb(p_icp67, data, cnt);
}

LOCAL void test_iec_point_tbl_get(stru_icp67 *p_icp67, stru_genneral_method *p_method)
{
    if(p_method && p_method->iec_point_tbl_get_cb)
    {
        p_method->iec_point_tbl_get_cb(p_icp67, g_local_iec_info_get.info_addr);
    }

    g_flag[3] = 0;
}

LOCAL void test_time_set(stru_icp67 *p_icp67, stru_genneral_method *p_method)
{
    stru_ti_5 tm = {0};

    struct timeval tt;
    gettimeofday(&tt, NULL);
    struct tm* ptm = localtime(&tt.tv_sec);

    tm.year = ptm->tm_year + 1900 - 2000;
    tm.month = ptm->tm_mon + 1;
    tm.day = ptm->tm_mday;
    tm.hour = ptm->tm_hour;
    tm.min = ptm->tm_min;
    tm.ms = ptm->tm_sec * 1000 + tt.tv_usec / 1000;

    if(p_method && p_method->time_set_cb)
    {
        p_method->time_set_cb(p_icp67, &tm);
    }

    g_flag[5] = 0;
}


LOCAL void test_self_check_get(stru_icp67 *p_icp67, stru_genneral_method *p_method)
{
    if(p_method && p_method->self_check_get_cb)
    {
        p_method->self_check_get_cb(p_icp67);
    }

    g_flag[6] = 0;
}

LOCAL void test_upgrade_start(stru_icp67 *p_icp67, stru_genneral_method *p_method)
{
    if(p_method && p_method->upgrade_start_cb)
    {
        p_method->upgrade_start_cb(p_icp67, 2); // 主板固件升级
    }

    g_flag[9] = 0;
}

LOCAL void test_file(stru_icp67 *p_icp67, stru_genneral_method *p_method)
{
    if(g_local_file.sub_cmd == 1)
    {
        p_method->dir_read_cb(p_icp67, (uint8_t *)g_local_file.temp_str.c_str(), g_local_file.temp_str.size(), NULL, NULL);

        g_local_file.dir_name = g_local_file.temp_str;
    }
    else if(g_local_file.sub_cmd == 3)
    {
        for(uint16_t i = 0; i < g_dir_info_vec.size(); i++)
        {
            if(g_dir_info_vec[i].name == g_local_file.temp_str)
            {
                p_method->file_read_act_cb(p_icp67, (uint8_t *)g_local_file.temp_str.c_str(), g_local_file.temp_str.size());

                g_local_file.file_name = g_local_file.temp_str;
                break;
            }
        }
    }
    else if(g_local_file.sub_cmd == 7)
    {
        g_local_file.dir_name = g_down_path;
        std::string file_name = g_file_path + g_local_file.dir_name + "/" + g_local_file.temp_str;

        uint32_t file_size = 0;
        file_size_get(file_name.c_str(), &file_size);
        p_method->file_write_act_cb(p_icp67, (uint8_t *)g_local_file.temp_str.c_str(), g_local_file.temp_str.size(), 0, file_size, 0);
    }

    g_flag[11] = 0;
}


void self_ptl_method_task()
{
    stru_genneral_method *p_method = self_ptl_method_ptr_get();
    stru_icp67 *p_icp67 = self_ptl_icp67_ptr_get();

    for(auto it = g_map_local_test.begin(); it != g_map_local_test.end(); it++)
    {
        if(!g_flag[it->first])
        {
            continue;
        }

        it->second(p_icp67, p_method);
    }
}


LOCAL void cmd_show_iec_tbl(uint16_t info_addr)
{
    stru_app_cfg *p_cfg = get_app_cfg_ptr();
    if(info_addr == MX_INFO_ADDR)
    {
        for(uint16_t i = 0; i < p_cfg->mx_info_vec.size(); i++)
        {
            stru_iec_mx_info *p = &p_cfg->mx_info_vec[i];

            printf("no %04d, inf %04x, factor %f, record_flag %d, dead_zone %d, max_value %f, data %f, desc %s\n ", 
                i, p->inf, p->factor, p->record_flag, p->dead_zone, p->max_limit, p->data, p->desc.c_str());
        }
    }
    else if(info_addr == ST_INFO_ADDR)
    {
        for(uint16_t i = 0; i < p_cfg->st_info_vec.size(); i++)
        {
            stru_iec_st_info *p = &p_cfg->st_info_vec[i];

            printf("no %04d, inf %04x, invert %d, debounce_time %d, data %d, desc %s\n ", 
                i, p->inf, p->invert, p->debounce_time, p->data, p->desc.c_str());  
        }
    }
    else if(info_addr == CO_INFO_ADDR)
    {
        for(uint16_t i = 0; i < p_cfg->co_info_vec.size(); i++)
        {
            stru_iec_co_info *p = &p_cfg->co_info_vec[i];

            printf("no %04d, inf %04x, ctrl_attr %d, data %d, desc %s\n ", i, p->inf, p->ctrl_attr, p->data, p->desc.c_str());  
        }
    }
    else if(info_addr == AO_INFO_ADDR)
    {
        for(uint16_t i = 0; i < p_cfg->param_info_vec.size(); i++)
        {
            stru_iec_param_info *p = &p_cfg->param_info_vec[i];

            char val[256] = {0};
            // param_data_show(p->p_val->buf, val, p->type);
            printf("no %04d, inf %04x, encoding %d, type %d, param_addr %d, up_dtype %d, factor %f, data %s, desc %s\n ", 
                i, p->inf, p->encoding, p->type, p->param_addr, p->up_dtype, p->factor, val, p->desc.c_str());  
        }
    }
    else if(info_addr == DD_INFO_ADDR)
    {
        for(uint16_t i = 0; i < p_cfg->dd_info_vec.size(); i++)
        {
            stru_iec_dd_info *p = &p_cfg->dd_info_vec[i];

            printf("no %04d, inf %04x, factor %f, data %f, desc %s\n ", i, p->inf, p->factor, p->data, p->desc.c_str());  
        }
    }
}

LOCAL void cmd_self_ptl(int argc, char *argv[])
{
    printf("self_ptl 1 -----param_get\n");
    printf("self_ptl 3 100 -----iec_point_tbl_get\n");
    printf("self_ptl 5 -----time_set\n");
    printf("self_ptl 6 -----self_check_get\n");
    printf("self_ptl 9 -----upgrade_start\n");
    printf("self_ptl 11 1 -----file\n");

    if(argc >= 2)
    {
        if(strcmp(argv[1], "1") == 0)
        {
            if(argc == 2)
            {
                g_flag[1] = 1;
                stru_icp67 *p_icp67 = self_ptl_icp67_ptr_get();

                g_local_param_get.offset = 0;
                g_local_param_get.per_cnt = 40;
            }
            else if(argc == 3)
            {
                stru_app_cfg *p_cfg = get_app_cfg_ptr();
                for(uint16_t i = 0; i < p_cfg->p_param_cfg->vec_param.size(); i++)
                {
                    stru_param_cfg_data *p_data = &p_cfg->p_param_cfg->vec_param[i];

                    std::string val = "";
                    param_data_show(p_data->p_data, val, p_data->type);
                    printf("no %06d, inf %04x, type %04d, len %04d, val %s\n", i, p_data->inf, p_data->type, g_type_len_map[p_data->type], val.c_str());
                }
            }
        }
        else if(strcmp(argv[1], "3") == 0 && argc >= 3)
        {
            uint16_t info_addr = atoi(argv[2]);

            if(argc == 3 && (info_addr == MX_INFO_ADDR || info_addr == ST_INFO_ADDR || info_addr == CO_INFO_ADDR || info_addr == AO_INFO_ADDR || info_addr == DD_INFO_ADDR))
            {
                g_flag[3] = 1;
                g_local_iec_info_get.info_addr = info_addr;
            }

            if(argc == 4 && strcmp(argv[3], "show") == 0)
            {
                cmd_show_iec_tbl(info_addr);
            }
        }
        else if(strcmp(argv[1], "5") == 0)
        {
            g_flag[5] = 1;
        }
        else if(strcmp(argv[1], "6") == 0)
        {
            g_flag[6] = 1;
        }
        else if(strcmp(argv[1], "9") == 0)
        {
            g_flag[9] = 1;
        }
        else if(strcmp(argv[1], "11") == 0 && argc >= 3)
        {
            g_local_file.sub_cmd = atoi(argv[2]);
            if(argc == 4)
            {
                g_local_file.temp_str = argv[3];
            }

            g_flag[11] = 1;
        }
    }

}


CMD_REGISTER("self_ptl", cmd_self_ptl, "私有规约的控制命令");



