#include "icp67.h"
#include "myLog.h"
#include "general_method.h"

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

LOCAL uint8_t crc_check_sum(uint8_t *p_data, uint16_t len);

LOCAL int icp67_decode_ti_1(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_2(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_3(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_4(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_5(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_6(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_9(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_11(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_30(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_200(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_201(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_202(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_203(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_204(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_205(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_207(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);

LOCAL int icp67_decode_ti_11_2(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_11_4(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_11_5(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_11_8(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_11_10(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);

LOCAL int icp67_decode_ti_30_1(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);
LOCAL int icp67_decode_ti_30_3(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len);



LOCAL std::map<uint8_t, icp67_decode_cb> g_map_ti_decode = 
{
    {TI_1,      icp67_decode_ti_1},
    {TI_2,      icp67_decode_ti_2},
    {TI_3,      icp67_decode_ti_3},
    {TI_4,      icp67_decode_ti_4},
    {TI_5,      icp67_decode_ti_5},
    {TI_6,      icp67_decode_ti_6},
    {TI_9,      icp67_decode_ti_9},
    {TI_11,     icp67_decode_ti_11},
    {TI_30,     icp67_decode_ti_30},
    {TI_200,    icp67_decode_ti_200},
    {TI_201,    icp67_decode_ti_201},
    {TI_202,    icp67_decode_ti_202},
    {TI_203,    icp67_decode_ti_203},
    {TI_204,    icp67_decode_ti_204},
    {TI_205,    icp67_decode_ti_205},
    {TI_207,    icp67_decode_ti_207},
}; 

LOCAL std::map<uint8_t, icp67_decode_cb> g_map_file_decode = 
{
    {FILE_CMD_2,    icp67_decode_ti_11_2},
    {FILE_CMD_4,    icp67_decode_ti_11_4},
    {FILE_CMD_5,    icp67_decode_ti_11_5},
    {FILE_CMD_8,    icp67_decode_ti_11_8},
    {FILE_CMD_10,   icp67_decode_ti_11_10},
};

LOCAL std::map<uint8_t, icp67_decode_cb> g_map_zip_decode =
{
    {TI_30_CMD_1,   icp67_decode_ti_30_1},
    {TI_30_CMD_3,   icp67_decode_ti_30_3}
}; 

LOCAL int icp67_decode_ti_1(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_1 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;
    stru_ti_1_2 *p_asdu = (stru_ti_1_2 *)p_head->data;

    if(COT_7 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_1 COT_7 != p_head->cot, COT_7=%d, p_head->cot=%d", COT_7, p_head->cot);
        return -1;
    }

    if(0 != memcmp(p_icp67->md5, p_asdu->md5, 16))
    {
        LOG_E("icp67_decode_ti_1 md5 error, md5=%s, p_asdu->md5=%s", p_icp67->md5, p_asdu->md5);
        return -1;
    }

    uint16_t pos = 0;
    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();
    for(uint8_t i = 0; p_genneral_method && p_genneral_method->param_pop_out_cb && i < p_asdu->num; i++)
    {
        stru_ti_1_2_data_info *p_info = (stru_ti_1_2_data_info *)&p_asdu->data[pos];
        pos += sizeof(stru_ti_1_2_data_info) + p_info->data_len;

        p_genneral_method->param_pop_out_cb(p_icp67, p_info->data_addr, p_info->data_type, p_info->data_len, p_info->data);
    }

    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_2(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_2 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;
    stru_ti_1_2 *p_asdu = (stru_ti_1_2 *)p_head->data;

    if(COT_7 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_2 COT_7 != p_head->cot, COT_7=%d, p_head->cot=%d", COT_7, p_head->cot);
        return -1;
    }

    if(0 != memcmp(p_icp67->md5, p_asdu->md5, 16))
    {
        LOG_E("icp67_decode_ti_2 md5 error, md5=%s, p_asdu->md5=%s", p_icp67->md5, p_asdu->md5);
        return -1;
    }

    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_3(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_3 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    if(COT_7 != p_head->cot)
    {   
        LOG_E("icp67_decode_ti_3 COT_7 != p_head->cot, COT_7=%d, p_head->cot=%d", COT_7, p_head->cot);
        return -1;
    }

    stru_ti_3_follow *p_asdu = (stru_ti_3_follow *)p_head->data;

    LOG_I("ti 3 decode, total %d, frame no %d, follow %d, num %d", p_asdu->total, p_asdu->frame_no, p_asdu->follow, p_asdu->num);

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();
    if(p_genneral_method && p_genneral_method->iec_point_tbl_pop_out_cb)
    {
        p_genneral_method->iec_point_tbl_pop_out_cb(p_icp67, p_head->info_addr, p_asdu->num, p_asdu->data);
    }

    if(p_asdu->follow)
    {
        uint16_t offset = p_asdu->frame_no + p_asdu->num;

        uint8_t *p_tx = p_icp67->tx;
        uint16_t tx_len = 0;

        icp67_make_head(ENUM_DEV_TYPE_SYS, p_head->ti, COT_7, p_head->info_addr, p_tx, tx_len);

        stru_ti_3_follow *p_tx_asdu = (stru_ti_3_follow *)&p_tx[tx_len];
        p_tx_asdu->total = p_asdu->total;
        p_tx_asdu->frame_no = offset;
        p_tx_asdu->follow = p_asdu->follow;
        p_tx_asdu->num = p_asdu->num;
        tx_len += sizeof(stru_ti_3_follow);

        icp67_make_tail(p_tx, tx_len);
        
        p_icp67->tx_len = tx_len;
        p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

        icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
    }
    else
    {
        icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);
    }
    return 0;
}

LOCAL int icp67_decode_ti_4(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    return 0;
}

LOCAL int icp67_decode_ti_5(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_5 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    if(COT_7 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_5 COT_7 != p_head->cot, COT_7=%d, p_head->cot=%d", COT_7, p_head->cot);
        return -1;
    }

    stru_ti_5 *p_asdu = (stru_ti_5 *)p_head->data;

    LOG_I("tm set success: %04d-%02d-%02d %02d:%02d:%02d.%03d", 
        p_asdu->year+2000, p_asdu->month, p_asdu->day, p_asdu->hour, p_asdu->min, p_asdu->ms / 1000, p_asdu->ms % 1000);

    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_6(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_6 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    if(COT_7 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_6 COT_7 != p_head->cot, COT_7=%d, p_head->cot=%d", COT_7, p_head->cot);
        return -1;
    }

    stru_ti_6 *p_asdu = (stru_ti_6 *)p_head->data;

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    uint16_t pos = 0;
    for(uint16_t i = 0; p_genneral_method && p_genneral_method->self_check_pop_out_cb && i < p_asdu->st_num; i++)
    {
        stru_data_info *p = (stru_data_info *)&p_asdu->st_data[pos];
        pos += sizeof(stru_data_info) + p->data_len;

        p_genneral_method->self_check_pop_out_cb(p_icp67, p, i);
    }

    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_9(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_9 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    if(COT_7 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_9 COT_7 != p_head->cot, COT_7=%d, p_head->cot=%d", COT_7, p_head->cot);
        return -1;
    }

    uint8_t result = p_head->data[0];

    if(UP_RESULT_1 != result)
    {
        LOG_E("icp67_decode_ti_9 UP_RESULT_1 != result, UP_RESULT_1=%d, result=%d", UP_RESULT_1, result);
        return -1;
    }

    LOG_I("up success");
    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_11(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_11 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    if(COT_7 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_11 COT_7 != p_head->cot, COT_7=%d, p_head->cot=%d", COT_7, p_head->cot);
        return -1;
    }

    uint8_t cmd = p_head->data[0];

    if(p_head->len > 11 && g_map_file_decode.find(cmd) != g_map_file_decode.end())
    {
        g_map_file_decode[cmd](p_icp67, p_rx, rx_len);
    }

    // if(p_head->len == 11)
    // {
    //     icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);
    // }

    return 0;
}

LOCAL int icp67_decode_ti_30(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_30 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }
    stru_head *p_head = (stru_head *)p_rx;
    if(COT_5 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_30 COT_5 != p_head->cot, COT_5=%d, p_head->cot=%d", COT_5, p_head->cot);
        return -1;
    }
    
    uint8_t cmd = p_head->data[0];

    if(g_map_zip_decode.find(cmd) != g_map_zip_decode.end())
    {
        g_map_zip_decode[cmd](p_icp67, p_rx, rx_len);
    }

    return 0;
}

LOCAL int icp67_decode_ti_200(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_200 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    // if(COT_6 != p_head->cot)
    // {
    //     LOG_E("icp67_decode_ti_200 COT_6 != p_head->cot, COT_6=%d, p_head->cot=%d", COT_6, p_head->cot);
    //     return -1;
    // }

    stru_ti_200_201_202 *p_asdu = (stru_ti_200_201_202 *)p_head->data;

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    uint16_t pos = 0;
    for(uint16_t i = 0; p_genneral_method && p_genneral_method->mx_trans_cb && i < p_asdu->num; i++)
    {
        p_genneral_method->mx_trans_cb(p_icp67, p_asdu->addr+i, *(float *)&p_asdu->data[pos]);
        pos += 4;
    }

    return 0;
}
LOCAL int icp67_decode_ti_201(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_201 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }
    
    stru_head *p_head = (stru_head *)p_rx;

    // if(COT_6 != p_head->cot)
    // {
    //     LOG_E("icp67_decode_ti_201 COT_6 != p_head->cot, COT_6=%d, p_head->cot=%d", COT_6, p_head->cot);
    //     return -1;
    // }
    
    stru_ti_200_201_202 *p_asdu = (stru_ti_200_201_202 *)p_head->data;

    stru_genneral_method *p = icp67_get_genneral_method();

    uint16_t pos = 0;
    for(uint16_t i = 0; p && p->st_trans_cb && i < p_asdu->num; i++)
    {
        p->st_trans_cb(p_icp67, p_asdu->addr+i, p_asdu->data[pos++]);
    }
    
    return 0;
}

LOCAL int icp67_decode_ti_202(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_202 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    // if(COT_6 != p_head->cot)
    // {
    //     LOG_E("icp67_decode_ti_202 COT_6 != p_head->cot, COT_6=%d, p_head->cot=%d", COT_6, p_head->cot);
    //     return -1;
    // }

    stru_ti_200_201_202 *p_asdu = (stru_ti_200_201_202 *)p_head->data;

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    uint16_t pos = 0;
    for(uint16_t i = 0; p_genneral_method && p_genneral_method->dd_trans_cb && i < p_asdu->num; i++)
    {
        p_genneral_method->dd_trans_cb(p_icp67, p_asdu->addr+i, *(float *)&p_asdu->data[pos]);
        pos += 4;
    }

    return 0;
}

LOCAL int icp67_decode_ti_203(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    return 0;
}

LOCAL int icp67_decode_ti_204(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_204 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }
    
    stru_head *p_head = (stru_head *)p_rx;

    if(COT_3 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_204 COT_6 != p_head->cot, COT_3=%d, p_head->cot=%d", COT_3, p_head->cot);
        return -1;
    }

    stru_ti_204_205_207 *p_asdu = (stru_ti_204_205_207 *)p_head->data;
    uint16_t pos = 0;

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    for(uint16_t i = 0; p_genneral_method && p_genneral_method->soe_trans_cb && i < p_asdu->num; i++)
    {
        stru_st_info *p_st_info = (stru_st_info *)&p_asdu->data[pos];
        pos += sizeof(stru_st_info);

        p_genneral_method->soe_trans_cb(p_icp67, p_st_info);
    }

    return 0;
}

LOCAL int icp67_decode_ti_205(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_205 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    if(COT_3 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_205 COT_3 != p_head->cot, COT_3=%d, p_head->cot=%d", COT_3, p_head->cot);
        return -1;
    }

    stru_ti_204_205_207 *p_asdu = (stru_ti_204_205_207 *)p_head->data;
    uint16_t pos = 0;

    
    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    std::vector<stru_st_info> st_info_vec;
    std::vector<stru_mx_info> mx_info_vec;

    for(uint16_t i = 0; i < p_asdu->num; i++)
    {
        uint8_t st_num = p_asdu->data[pos++];
        for(uint8_t i = 0; i < st_num; i++)
        {
            stru_st_info *p_st_info = (stru_st_info *)&p_asdu->data[pos];
            pos += sizeof(stru_st_info);

            st_info_vec.push_back(*p_st_info);
        }
        
        uint8_t mx_num = p_asdu->data[pos++];
        for(uint8_t i = 0; i < mx_num; i++)
        {
            stru_mx_info *p_mx_info = (stru_mx_info *)&p_asdu->data[pos];
            pos += sizeof(stru_mx_info);

            mx_info_vec.push_back(*p_mx_info);
        }
    }

    stru_fault_info fault_info;
    fault_info.st_num = st_info_vec.size();
    fault_info.p_st_info = st_info_vec.data();
    fault_info.mx_num = mx_info_vec.size();
    fault_info.p_mx_info = mx_info_vec.data();

    if(p_genneral_method && p_genneral_method->fault_trans_cb)
    {
        p_genneral_method->fault_trans_cb(p_icp67, p_asdu->num, &fault_info);
    }

    return 0;
}

LOCAL int icp67_decode_ti_206(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    return 0;
}

LOCAL int icp67_decode_ti_207(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_207 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }
    stru_head *p_head = (stru_head *)p_rx;

    if(COT_3 != p_head->cot)
    {
        LOG_E("icp67_decode_ti_207 COT_3 != p_head->cot, COT_3=%d, p_head->cot=%d", COT_3, p_head->cot);
        return -1;
    }

    stru_ti_204_205_207 *p_asdu = (stru_ti_204_205_207 *)p_head->data;
    uint16_t pos = 0;

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    for(uint16_t i = 0; p_genneral_method && p_genneral_method->mx_change_cb && i < p_asdu->num; i++)
    {
        stru_mx_info *p_mx_info = (stru_mx_info *)&p_asdu->data[pos];
        pos += sizeof(stru_mx_info);

        p_genneral_method->mx_change_cb(p_icp67, p_mx_info);
    }

    return 0;
}


LOCAL int icp67_decode_ti_11_2(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_11_2 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }
    
    stru_head *p_head = (stru_head *)p_rx;

    stru_ti_11_2 *p_asdu = (stru_ti_11_2 *)p_head->data;

    uint16_t pos = 0;
    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    uint8_t len = 0;
    uint8_t name[256] = {0};
    uint32_t attr = 0;
    uint32_t size = 0;
    uint8_t follow = 1;

    for(uint16_t i = 0; p_genneral_method && p_genneral_method->dir_pop_out_cb && i < p_asdu->num; i++)
    {
        len = p_asdu->data[pos++];
        memcpy(name, p_asdu->data + pos, len);
        name[len] = '\0';
        pos += len;
        attr = *(uint32_t *)&p_asdu->data[pos];
        pos += 4;
        size = *(uint32_t *)&p_asdu->data[pos];
        pos += 4;

        if(p_asdu->follow == 0 && i == (p_asdu->num - 1))
        {
            follow = 0;
        }
        p_genneral_method->dir_pop_out_cb(p_icp67, name, len, attr, size, follow);
    }

    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_11_4(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_11_4 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }
    
    stru_head *p_head = (stru_head *)p_rx;

    stru_ti_11_4 *p_asdu = (stru_ti_11_4 *)p_head->data;

    uint16_t pos = 0;
    uint8_t name[256] = {0};
    uint32_t id = 0;
    uint32_t size = 0;
    uint16_t crc = 0;

    memcpy(name, p_asdu->data, p_asdu->len);
    name[p_asdu->len] = '\0';
    pos += p_asdu->len;
    id = *(uint32_t *)&p_asdu->data[pos];
    pos += 4;
    size = *(uint32_t *)&p_asdu->data[pos];
    pos += 4;
    crc = *(uint16_t *)&p_asdu->data[pos];
    pos += 2;

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    if(p_genneral_method && p_genneral_method->file_read_act_confirm_cb)
    {
        p_genneral_method->file_read_act_confirm_cb(p_icp67, name, p_asdu->len, id, size, crc);
    }

    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_11_5(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_11_5 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    stru_ti_11_5 *p_asdu = (stru_ti_11_5 *)p_head->data;

    if(p_asdu->data[p_asdu->len] != crc_check_sum(p_asdu->data, p_asdu->len))
    {
        LOG_E("icp67_decode_ti_11_5 crc error crc %02X, crc_check_sum %02X", p_asdu->data[p_asdu->len], crc_check_sum(p_asdu->data, p_asdu->len));
        return -1;
    }

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    if(p_genneral_method && p_genneral_method->file_read_cb)
    {
        p_genneral_method->file_read_cb(p_icp67, p_asdu->id, p_asdu->offset, p_asdu->follow, p_asdu->data, p_asdu->len);
    }

    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_11_8(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_11_8 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    stru_ti_11_8 *p_asdu = (stru_ti_11_8 *)p_head->data;

    if(FILE_WRITE_ACT_0 != p_asdu->result)
    {
        LOG_E("icp67_decode_ti_11_8 FILE_WRITE_ACT_0 != p_asdu->result, FILE_WRITE_ACT_0=%d, p_asdu->result=%d", FILE_WRITE_ACT_0, p_asdu->result);
        return -1;
    }
    
    uint16_t pos = 0;
    uint8_t name[256] = {0};
    uint32_t id = 0;
    uint32_t size = 0;
    
    memcpy(name, p_asdu->data, p_asdu->len);
    name[p_asdu->len] = '\0';
    pos += p_asdu->len;
    id = *(uint32_t *)&p_asdu->data[pos];
    pos += 4;
    size = *(uint32_t *)&p_asdu->data[pos];
    pos += 4;

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    if(p_genneral_method && p_genneral_method->file_write_act_confirm_cb)
    {
        p_genneral_method->file_write_act_confirm_cb(p_icp67, p_asdu->result, name, p_asdu->len, id, size);
    }

    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_11_10(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_11_10 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }
    stru_head *p_head = (stru_head *)p_rx;
    stru_ti_11_10 *p_asdu = (stru_ti_11_10 *)p_head->data;

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    if(FILE_WRITE_CONT_0 == p_asdu->result)
    {
        // LOG_I("ti 11 10: end, result %d, id %d, offset %d", p_asdu->result, p_asdu->id, p_asdu->offset);
        if(p_genneral_method && p_genneral_method->file_write_end_cb)
        {
            p_genneral_method->file_write_end_cb(p_icp67, p_asdu->result, p_asdu->id, p_asdu->offset, p_asdu->md5);
        }
    }
    else if(FILE_WRITE_CONT_1 == p_asdu->result)
    {
        // LOG_I("ti 11 10: offset %d", p_asdu->offset);
        if(p_genneral_method && p_genneral_method->file_write_confirm_cb)
        {
            p_genneral_method->file_write_confirm_cb(p_icp67, p_asdu->result, p_asdu->id, p_asdu->offset);
        }
    }
    else
    {
        LOG_E("icp67_decode_ti_11_10 result error, result=%d", p_asdu->result);
        return -1;
    }

    icp67_rtx_flag_set(p_icp67, ICP67_RX_FLAG, 0, 0);

    return 0;
}

LOCAL int icp67_decode_ti_30_1(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_30_1 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    stru_ti_30_1 *p_asdu = (stru_ti_30_1 *)p_head->data;
    uint8_t zip_name[256] = {0};
    uint16_t pos = 0;

    memcpy(zip_name, p_asdu->data, p_asdu->len);
    zip_name[p_asdu->len] = '\0';
    pos += p_asdu->len;

    uint8_t file_num = p_asdu->data[pos++];

    std::vector<stru_zip_file_info> zip_file_vec;

    for(uint8_t i = 0; i < file_num; i++)
    {
        stru_zip_file_info file_info;

        file_info.id = i;
        file_info.len = p_asdu->data[pos++];
        memcpy(file_info.name, p_asdu->data + pos, file_info.len);
        file_info.name[file_info.len] = '\0';
        pos += file_info.len;
        file_info.size = *(uint32_t *)&p_asdu->data[pos];
        pos += 4;

        zip_file_vec.push_back(file_info);
    }

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();
    if(p_genneral_method && p_genneral_method->zip_dir_pop_out_cb)
    {
        p_genneral_method->zip_dir_pop_out_cb(p_icp67, p_asdu->zip_type, zip_name, p_asdu->len, file_num, zip_file_vec.data());
    }

    return 0;
}

LOCAL int icp67_decode_ti_30_3(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        LOG_E("icp67_decode_ti_30_3 param error, p_icp67=%p, p_rx=%p, rx_len=%d", p_icp67, p_rx, rx_len);
        return -1;
    }
    
    stru_head *p_head = (stru_head *)p_rx;

    stru_ti_30_3 *p_asdu = (stru_ti_30_3 *)p_head->data;

    stru_genneral_method *p_genneral_method = icp67_get_genneral_method();

    if(p_genneral_method && p_genneral_method->zip_file_pop_out_cb)
    {
        p_genneral_method->zip_file_pop_out_cb(p_icp67, p_asdu->file_no, p_asdu->offset, p_asdu->data, p_asdu->len);
    }

    return 0;
}




LOCAL uint8_t crc_check_sum(uint8_t *p_data, uint16_t len)
{
    uint8_t crc = 0;
    uint16_t i;
    for(i = 0; i < len; i++)
    {
        crc += p_data[i];
    }
    return crc;
}

void icp67_make_head(uint8_t dst, uint8_t ti, uint8_t cot, uint16_t inf, uint8_t *p_tx, uint16_t &tx_len)
{
    stru_head *p_head = (stru_head *)p_tx;

    p_head->head1       = ICP67_HEAD;
    p_head->head2       = ICP67_HEAD;
    p_head->src         = ENUM_DEV_TYPE_MAINTENANCE;
    p_head->dst         = dst;
    p_head->dir         = ENUM_DIR_MASTER;
    p_head->ti          = ti;
    p_head->cot         = cot;
    p_head->info_addr   = inf;
    p_head->dev_addr    = DEV_RK3562_ADDR;  // 0:维护软件 ，1:rk3562
    tx_len = sizeof(stru_head);
}

void icp67_make_tail(uint8_t *p_tx, uint16_t &tx_len)
{
    stru_head *p_head = (stru_head *)p_tx;
    p_head->len = tx_len - 4; // head1, len, head2,
    p_tx[tx_len ++] = crc_check_sum(p_tx + 4, p_head->len);
    p_tx[tx_len ++] = ICP67_TAIL;
}

LOCAL int icp67_search_frame(uint8_t *p_data, uint16_t len, uint16_t *p_pos, uint16_t *p_valid_len)
{
    if(NULL == p_data || NULL == p_pos || NULL == p_valid_len || 0 == len)
    {
        return -1;
    }
    
    for(uint16_t i = 0; i < len; i++)
    {
        stru_head *p_head = (stru_head *)(p_data + i);

        if(i +2 + sizeof(stru_head) > len)
        {
            break;
        }

        if(ICP67_HEAD != p_head->head1 || ICP67_HEAD != p_head->head2)
        {
            continue;
        }

        if((p_head->len + 6) > (len - i))
        {
            break;
        }

        if(p_data[i + p_head->len + 4] != crc_check_sum(p_data + i + 4, p_head->len))
        {
            continue;
        }

        if(p_data[i + p_head->len + 5] != ICP67_TAIL)
        {
            continue;
        }

        (*p_pos) = i;
        (*p_valid_len) = p_head->len + 6;

        return 0;
    }

    return -1;
}

LOCAL void icp67_show_frame(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data || 0 == len)
    {
        return;
    }

    stru_head *p_head = (stru_head *)p_data;

    const char *str[5] = {"维护软件", "主板", "采样板", "LCD", "XTU"};

    printf("%s -> %s, len = %d, dev_addr %d\n", str[p_head->src-1], str[p_head->dst-1], len, p_head->dev_addr);
    for(uint16_t i = 0; i < len; i++)
    {
        printf("%02X ", p_data[i]);
    }
    printf("\n");
}


LOCAL int icp67_decode(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_len)
{
    if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
    {
        return -1;
    }

    stru_head *p_head = (stru_head *)p_rx;

    // if(p_head->ti != TI_200 && p_head->ti != TI_201)
    // {
    //     icp67_show_frame(p_rx, rx_len);
    // }

    if(g_map_ti_decode.find(p_head->ti) == g_map_ti_decode.end())
    {
        LOG_E("not support ti %d\n", p_head->ti);
        return -1;
    }

    g_map_ti_decode[p_head->ti](p_icp67, p_rx, rx_len);

    return 0;
} 

LOCAL void icp67_timer_handler(stru_icp67 *p_icp67)
{
    if(NULL == p_icp67)
    {
        return;
    }

    uint8_t rtx_flag = 0;
    uint8_t resend_cnt = 0;
    uint32_t tm_cnt = 0;
    icp67_rtx_flag_get(p_icp67, rtx_flag, resend_cnt, tm_cnt);

    if(rtx_flag == ICP67_TX_FLAG && resend_cnt < ICP67_RESEND_MAX && tm_cnt >= p_icp67->tm_out)
    {
        p_icp67->send_cb(p_icp67->resend_tx, p_icp67->resend_tx_len, p_icp67->arg);
        p_icp67->resend_cnt ++;
        p_icp67->tm_cnt = 0;

        LOG_I("resend cnt %d", p_icp67->resend_cnt);
        icp67_show_frame(p_icp67->resend_tx, p_icp67->resend_tx_len);
    }

    p_icp67->tm_cnt++;
}

void icp67_init(stru_icp67 *p_icp67, icp67_send_cb send_cb, void *arg)
{
    p_icp67->arg                    = arg;
    p_icp67->send_cb                = send_cb;

    p_icp67->search_frame_cb        = icp67_search_frame;
    p_icp67->decode_cb              = icp67_decode;
    p_icp67->timer_handler_cb       = icp67_timer_handler;

    p_icp67->rtx_flag = 0;
    sem_init(&p_icp67->rtx_sem, 0, 1);

    p_icp67->resend_cnt = 0;
    p_icp67->tm_out = 1000 / 10; // 1000ms
    p_icp67->tm_cnt = 0;
}

int icp67_set_param_cfg_md5(stru_icp67 *p_icp67, uint8_t *p_md5)
{
    if(NULL == p_icp67 || NULL == p_md5)
    {
        return -1;
    }

    memcpy(p_icp67->md5, p_md5, 16);

    return 0;
}

void icp67_rtx_flag_get(stru_icp67 *p_icp67, uint8_t &flag, uint8_t &resend_cnt, uint32_t &tm_cnt)
{
    sem_wait(&p_icp67->rtx_sem);

    flag = p_icp67->rtx_flag;
    resend_cnt = p_icp67->resend_cnt;
    tm_cnt = p_icp67->tm_cnt;
    sem_post(&p_icp67->rtx_sem);
}

void icp67_rtx_flag_set(stru_icp67 *p_icp67, uint8_t flag, uint8_t resend_cnt, uint32_t tm_cnt)
{
    sem_wait(&p_icp67->rtx_sem);
    p_icp67->rtx_flag = flag;
    p_icp67->resend_cnt = resend_cnt;
    p_icp67->tm_cnt = tm_cnt;

    if(flag == ICP67_TX_FLAG)
    {
        memcpy(p_icp67->resend_tx, p_icp67->tx, p_icp67->tx_len);
        p_icp67->resend_tx_len = p_icp67->tx_len;
    }
    sem_post(&p_icp67->rtx_sem);
}

void icp67_reset_resend_cnt(stru_icp67 *p_icp67)
{
    p_icp67->resend_cnt = 0;
}

void icp67_reset_tm_cnt(stru_icp67 *p_icp67)
{
    p_icp67->tm_cnt = 0;
}