#include "iec104.h"

iec_8u iec104_send_buf[IEC104_MAX_BUF_LEN];

iec_8u IEC104_STATE_FLAG_INIT    = IEC104_FLAG_CLOSED;
iec_8u IEC104_STATE_FLAG_CALLALL = IEC104_FLAG_CLOSED;
iec_8u IEC104_STATE_FLAG_GROUP   = IEC104_FLAG_CLOSED;
iec_8u IEC104_STATE_FLAG_CLOCK   = IEC104_FLAG_CLOSED;
iec_8u IEC104_STATE_FLAG_TESTER  = IEC104_FLAG_IDLE;
iec_8u IEC104_STATE_FLAG_S_ACK   = IEC104_FLAG_CLOSED;

iec_32s iec104_build_send_sn = 0;
iec_32s iec104_build_recv_sn = 0;
iec_32s iec104_deal_send_sn  = -1;
iec_32s iec104_deal_recv_sn  = 0;

iec_8u IEC104_Call_AllQoi   = 0;
iec_8u IEC104_Call_GroupQoi = 0;

#define IEC104_CYCLE_TIME_MS       100             /*100ms*/
#define IEC104_RESEND_TIME_MS      (30 * 1000)     /*30s*/
#define IEC104_S_ACK_TIMEOUT       (5 * 1000)      /*5s*/
#define IEC104_TESTER_IDLE_TIMEOUT (1 * 30 * 1000) /*2min*/
iec_32u Iec104_TimeCount            = 0;
iec_32u Iec104_TimeCycle            = IEC104_RESEND_TIME_MS;
iec_32u Iec104_TimeCycle_S          = 0;
iec_32u Iec104_TimeCycle_TesterIdle = 0;
iec_8u  Iec104_TesterCount          = 0;

iec_32u Iec10x_Update_SeekAddr = 0;
iec_16u FirmFlagCount          = 0;

iec_8u iec104_upload_addr(void)
{

    iec_8u  len    = 0;
    iec_8u *ptr    = NULL;
    iec_32u temp32 = 0;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = IEC104_ASDU_TYPE_M_DTU_INF_1;
    asdu->_num._sq        = 0;
    asdu->_num._num       = 1;
    asdu->_reason._reason = IEC10X_ASDU_COT_UNKNOW;
    asdu->_addr           = iec104_state_addr;

    /*build info*/
    ptr    = info->_addr;
    temp32 = 0;
    memcpy(ptr, &temp32, 3);

    ptr    = info->_element;
    temp32 = IEC104_INFO_SIGNATURE;
    memcpy(ptr, &temp32, 4);

    ptr += 4;
    temp32 = iec104_state_addr;
    memcpy(ptr, &temp32, 2);

    ptr += 2;

    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    dump_hex(Iec104_Sendbuf, len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, IEC10X_PRIO_INITLINK, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_build_init_fin(void)
{

    iec_8u  len    = 0;
    iec_8u *ptr    = NULL;
    iec_32u temp32 = 0;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = Iec10x_M_EI_NA_1;
    asdu->_num._sq        = 0;
    asdu->_num._num       = 1;
    asdu->_reason._reason = IEC10X_ASDU_REASON_INIT;
    asdu->_addr           = iec104_state_addr;

    /*build info*/
    ptr    = info->_addr;
    temp32 = 0;
    memcpy(ptr, &temp32, 3);

    ptr = info->_element;
    // temp32 = 0;
    // memcpy(ptr, &temp32, 4);
    info->_element[0] = 0;

    ptr++;

    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    dump_hex(Iec104_Sendbuf, len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, IEC10X_PRIO_INITLINK, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_build_call_ack(iec_8u qoi, iec_8u Prio)
{

    iec_8u  len    = 0;
    iec_8u *ptr    = NULL;
    iec_32u temp32 = 0;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = IEC10X_C_IC_NA_1;
    asdu->_num._sq        = 0;
    asdu->_num._num       = 1;
    asdu->_reason._reason = IEC10X_ASDU_REASON_ACTCON;
    asdu->_addr           = iec104_state_addr;

    /*build info*/
    ptr    = info->_addr;
    temp32 = 0;
    memcpy(ptr, &temp32, 3);

    ptr    = info->_element;
    ptr[0] = qoi;

    ptr += 1;
    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    dump_hex(Iec104_Sendbuf, len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, Prio, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_build_signal_spon(iec_8u time_flag, iec_8u v_signal, iec_16u v_addr)
{

    iec_8u        len = 0, asdu_num = 0, i;
    iec_8u       *ptr    = NULL;
    iec_32u       temp32 = 0;
    PCP56Time2a_T time   = NULL;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /* check Time flag */
    if (time_flag != 1 && time_flag != 0)
    {
        LOG("-%s-, error time flag(%d) \n", __FUNCTION__, time_flag);
        return RET_ERROR;
    }
    LOG("-%s-, time flag(%d) signalV(%d) \n", __FUNCTION__, time_flag, v_signal);
    /*get value*/
    asdu_num = 1;

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    if (time_flag == 0)
        asdu->_type = IEC10X_M_SP_NA_1;
    else
        asdu->_type = IEC10X_M_SP_TB_1;
    asdu->_num._sq        = 1;
    asdu->_num._num       = asdu_num;
    asdu->_reason._reason = IEC10X_COT_SPONT;
    asdu->_addr           = iec104_state_addr;

    /*build info addr*/
    ptr    = info->_addr;
    temp32 = v_addr;
    memcpy(ptr, &temp32, 3);

    /*build info value*/
    ptr = info->_element;
    for (i = 0; i < asdu_num; i++)
    {
        *ptr = v_signal;
        ptr++;
    }
    if (time_flag == 1)
    {
        time = (PCP56Time2a_T)ptr;
        iec104->get_time(time);
        ptr += sizeof(CP56Time2a_T);
    }

    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, IEC10X_PRIO_SPON, NULL, NULL);

    return RET_SUCESS;
}
iec_8u iec104_build_detect_spont(iec_8u TimeFlag, PIEC10X_DETECT_T detectV, iec_16u addrV)
{

    iec_8u           len = 0, asdu_num = 0;
    iec_8u          *ptr    = NULL;
    iec_32u          temp32 = 0;
    PIEC10X_DETECT_T detect = NULL;
    PCP56Time2a_T    time   = NULL;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /* check Time flag */
    if (TimeFlag != 1 && TimeFlag != 0)
    {
        LOG("-%s-, error time flag(%d) \n", __FUNCTION__, TimeFlag);
        return RET_ERROR;
    }
    /*get value*/
    asdu_num = 1;

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    if (TimeFlag == 0)
        asdu->_type = IEC10X_M_ME_NA_1;
    else
        asdu->_type = IEC10X_M_ME_TD_1;
    asdu->_num._sq        = 1;
    asdu->_num._num       = asdu_num;
    asdu->_reason._reason = IEC10X_COT_SPONT;
    asdu->_addr           = iec104_state_addr;

    /*build info addr*/
    ptr    = info->_addr;
    temp32 = addrV;
    memcpy(ptr, &temp32, 3);

    /*build info value*/
    ptr             = info->_element;
    detect          = (PIEC10X_DETECT_T)ptr;
    detect->_detect = detectV->_detect;
    detect->_qds    = detectV->_qds;
    ptr += sizeof(IEC10X_DETECT_T);
    if (TimeFlag == 1)
    {
        time = (PCP56Time2a_T)ptr;
        iec104->get_time(time);
        ptr += sizeof(CP56Time2a_T);
    }

    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, IEC10X_PRIO_SPON, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_build_detect_f_spont(iec_8u TimeFlag, float detectV, iec_16u addrV)
{

    iec_8u             len = 0, asdu_num = 0;
    iec_8u            *ptr    = NULL;
    iec_32u            temp32 = 0;
    PIEC10X_DETECT_F_T detect = NULL;
    PCP56Time2a_T      time   = NULL;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /* check Time flag */
    if (TimeFlag != 1 && TimeFlag != 0)
    {
        LOG("-%s-, error time flag(%d) \n", __FUNCTION__, TimeFlag);
        return RET_ERROR;
    }
    /*get value*/
    asdu_num = 1;

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    if (TimeFlag == 0)
        asdu->_type = IEC10X_M_ME_NC_1;
    else
        asdu->_type = IEC10X_M_ME_TF_1;
    asdu->_num._sq        = 1;
    asdu->_num._num       = asdu_num;
    asdu->_reason._reason = IEC10X_COT_SPONT;
    asdu->_addr           = iec104_state_addr;

    /*build info addr*/
    ptr    = info->_addr;
    temp32 = addrV;
    memcpy(ptr, &temp32, 3);

    /*build info value*/
    ptr             = info->_element;
    detect          = (PIEC10X_DETECT_F_T)ptr;
    detect->_detect = detectV;
    detect->_qds    = 0;
    ptr += sizeof(IEC10X_DETECT_F_T);
    if (TimeFlag == 1)
    {
        time = (PCP56Time2a_T)ptr;
        iec104->get_time(time);
        ptr += sizeof(CP56Time2a_T);
    }

    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, IEC10X_PRIO_SPON, NULL, NULL);

    return RET_SUCESS;
}
iec_8u iec104_build_signal(iec_8u reason, iec_8u Prio, iec_8u dev_type)
{

    iec_8u  len = 0, asdu_num = 0;
    iec_16u i      = 0;
    iec_8u *ptr    = NULL;
    iec_32u temp32 = 0;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /*get value*/
    iec104->get_info_num(&asdu_num, dev_type);
    LOG("-%s- total info (%d) \n\n", __FUNCTION__, asdu_num);

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = IEC10X_M_SP_NA_1;
    asdu->_num._sq        = 1;
    asdu->_num._num       = asdu_num;
    asdu->_reason._reason = reason;
    asdu->_addr           = iec104_state_addr;

    /*build info addr*/
    ptr = info->_addr;
    if (dev_type == ENDDEVICE_TYPE_HXTM)
    {
        temp32 = IEC104_INFOADDR_STATE_HXTM;
    }
    else if (dev_type == ENDDEVICE_TYPE_HXGF)
    {
        temp32 = IEC104_INFOADDR_STATE_HXGF;
    }
    else
    {
        LOG("-%s-, error dev type:%d \n", __FUNCTION__, dev_type);
        return RET_ERROR;
    }

    memcpy(ptr, &temp32, 3);

    /*build info value*/
    ptr = info->_element;
    for (i = 0; i < asdu_num; i++)
    {
        *ptr = iec104->get_station_state(i, dev_type);
        ptr++;
    }

    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, Prio, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_build_detect(iec_8u reason, iec_8u ValueType, iec_8u Prio, iec_8u dev_type)
{

    iec_8u             len = 0, asdu_num = 0, i;
    iec_8u            *ptr      = NULL;
    iec_32u            temp32   = 0;
    PIEC10X_DETECT_T   detect   = NULL;
    PIEC10X_DETECT_F_T detect_f = NULL;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /*get value*/
    iec104->get_info_num(&asdu_num, dev_type);
    LOG("-%s- total info (%d) \n\n", __FUNCTION__, asdu_num);

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = ValueType;
    asdu->_num._sq        = 1;
    asdu->_num._num       = asdu_num;
    asdu->_reason._reason = reason;
    asdu->_addr           = iec104_state_addr;

    /*build info addr*/
    ptr = info->_addr;
    if (dev_type == ENDDEVICE_TYPE_HXTM)
    {
        temp32 = IEC104_INFOADDR_VALUE_HXTM;
    }
    else if (dev_type == ENDDEVICE_TYPE_HXGF)
    {
        temp32 = IEC104_INFOADDR_VALUE_HXGF;
    }
    else
    {
        LOG("-%s-, error dev type:%d \n", __FUNCTION__, dev_type);
        return RET_ERROR;
    }
    memcpy(ptr, &temp32, 3);

    /*Build Detect value*/
    ptr = info->_element;
    for (i = 0; i < asdu_num; i++)
    {
        /*short int*/
        if (ValueType == IEC10X_M_ME_NA_1)
        {
            detect          = (PIEC10X_DETECT_T)ptr;
            detect->_detect = iec104->get_sta_value(i, dev_type);
            detect->_qds    = 0;
            ptr += sizeof(IEC10X_DETECT_T);
        }
        /*float*/
        else if (ValueType == IEC10X_M_ME_NC_1)
        {
            detect_f          = (PIEC10X_DETECT_F_T)ptr;
            detect_f->_detect = iec104->get_sta_value(i, dev_type);
            detect_f->_qds    = 0;
            ptr += sizeof(IEC10X_DETECT_F_T);
        }
    }

    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, Prio, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_build_upload(iec_8u ValueType, iec_8u Prio, iec_8u dev_type)
{

    iec_8u           len = 0, asdu_num = 0, i;
    iec_8u          *ptr    = NULL;
    iec_32u          temp32 = 0;
    PIEC10X_DETECT_T detect = NULL;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /*get value*/
    iec104->get_info_num(&asdu_num, dev_type);
    LOG("-%s- total info (%d) \n\n", __FUNCTION__, asdu_num);

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = ValueType;
    asdu->_num._sq        = 1;
    asdu->_num._num       = asdu_num;
    asdu->_reason._reason = AP_COT_BASE_INFO;
    asdu->_addr           = iec104_state_addr;

    /*build info addr*/
    ptr = info->_addr;

    temp32 = IEC104_INFOADDR_BASE_DEVINFO;
    memcpy(ptr, &temp32, 3);
    ptr += 3;
    /*Build Detect value*/
    ptr = info->_element;
    for (i = 0; i < asdu_num; i++)
    {

        detect          = (PIEC10X_DETECT_T)ptr;
        detect->_detect = iec104->get_sta_value(i, dev_type);
        detect->_qds    = 0;
        ptr += sizeof(IEC10X_DETECT_T);
    }
    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, Prio, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_build_act_finish(iec_8u qoi, iec_8u Prio)
{

    iec_8u  len = 0, asdu_num = 0;
    iec_8u *ptr    = NULL;
    iec_32u temp32 = 0;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(Iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.i.type    = 0;
    Iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    Iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = IEC10X_C_IC_NA_1;
    asdu->_num._sq        = 1;
    asdu->_num._num       = asdu_num;
    asdu->_reason._reason = IEC10X_ASDU_REASON_ACTTERM;
    asdu->_addr           = iec104_state_addr;

    /*build info addr*/
    ptr    = info->_addr;
    temp32 = IEC10X_INFO_ADDR_SIG_BASE + IEC10X_INFO_ADDR_SIG_TEMP_HX_OFF;
    memcpy(ptr, &temp32, 3);

    /*Build Detect value*/
    ptr    = info->_element;
    ptr[0] = qoi;

    ptr += 1;
    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, Prio, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_build_u(iec_8u UType, iec_8u Ack)
{

    iec_8u  len = 0, Tester, Start, Stop;
    iec_8u *ptr = NULL;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    if (Ack)
    {
        Tester = IEC104_U_FUNC_TESTER_ACK;
        Start  = IEC104_U_FUNC_STARTDT_ACK;
        Stop   = IEC104_U_FUNC_STOPDT_ACK;
    }
    else
    {
        Tester = IEC104_U_FUNC_TESTER;
        Start  = IEC104_U_FUNC_STARTDT;
        Stop   = IEC104_U_FUNC_STOPDT;
    }

    switch (UType)
    {

    case IEC104_U_FUNC_STARTDT:
        Iec104_data->ctrl.func.func = Start;
        break;
    case IEC104_U_FUNC_STOPDT:
        Iec104_data->ctrl.func.func = Stop;
        break;
    case IEC104_U_FUNC_TESTER:
        Iec104_data->ctrl.func.func = Tester;
        break;
    default:
        LOG(">%s<, U Type Error(%d) !\n", __FUNCTION__, UType);
        return RET_ERROR;
    }

    /*build ASDU , COT ,Addr*/
    ptr = Iec104_data->asdu;

    /*build info*/

    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;
    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, IEC10X_PRIO_INITLINK, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_build_s_ack(void)
{

    iec_8u  len = 0;
    iec_8u *ptr = NULL;

    p_iec104_data_t Iec104_data = (p_iec104_data_t)iec104_send_buf;

    /*build head*/
    Iec104_data->head = IEC104_HEAD;

    /*build control code*/
    Iec104_data->ctrl.s.type_1 = 1;
    Iec104_data->ctrl.s.type_2 = 0;

    Iec104_data->ctrl.s.reserve = 0;
    Iec104_data->ctrl.s.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    ptr = Iec104_data->asdu;

    /*build info*/

    /*len*/
    len              = ptr - iec104_send_buf;
    Iec104_data->len = len - 2;
    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, IEC10X_PRIO_INITLINK, NULL, NULL);

    return RET_SUCESS;
}
iec_8u iec104_asdu_call(p_iec10x_asdu_t Iec10x_Asdu)
{

    p_asdu_info_t asdu_info = (p_asdu_info_t)(Iec10x_Asdu->_info);
    iec_8u        qoi       = asdu_info->_element[0];
    iec_8u        Prio      = 0;

    iec_32u InfoAddr = 0;

    /* check info addrest */
    memcpy(&InfoAddr, asdu_info->_addr, 3);
    if (InfoAddr != 0)
    {
        LOG("-%s- call cmd active error addr(%x) \n", __FUNCTION__, InfoAddr);
        return RET_ERROR;
    }

    switch (Iec10x_Asdu->_reason._reason)
    {

    case IEC10X_ASDU_REASON_ACT:
        switch (qoi)
        {
        case IEC10X_CALL_QOI_TOTAL:
            Prio                      = IEC10X_PRIO_CALLALL;
            IEC104_STATE_FLAG_CALLALL = IEC104_FLAG_CALL_ALLDATA;
            IEC104_Call_AllQoi        = qoi;
            break;
        case IEC10X_CALL_QOI_GROUP1:
        case IEC10X_CALL_QOI_GROUP2:
        case IEC10X_CALL_QOI_GROUP9:
        case IEC10X_CALL_QOI_GROUP10:
            Prio                    = IEC10X_PRIO_CALLGROUP;
            IEC104_STATE_FLAG_GROUP = IEC101_FLAG_CALL_GROURPDATA;
            IEC104_Call_GroupQoi    = qoi;
            break;
        default:
            LOG("-%s- call cmd error qoi(%d) \n", __FUNCTION__, qoi);
            return RET_ERROR;
        }
        iec104_build_call_ack(qoi, Prio);
        /**/
        iec104_build_signal(qoi, Prio, ENDDEVICE_TYPE_HXTM);
        iec104_build_detect(qoi, IEC10X_M_ME_NA_1, Prio, ENDDEVICE_TYPE_HXTM);
        /**/
        iec104_build_signal(qoi, Prio, ENDDEVICE_TYPE_HXGF);
        iec104_build_detect(qoi, IEC10X_M_ME_NA_1, Prio, ENDDEVICE_TYPE_HXGF);
        iec104_build_act_finish(qoi, Prio);
        break;

    default:
        LOG("-%s- call cmd error reason(%d) \n", __FUNCTION__, Iec10x_Asdu->_reason._reason);
        break;
    }
    return RET_SUCESS;
}
iec_8u iec104_asdu_clock(p_iec10x_asdu_t Iec10x_Asdu)
{

    p_asdu_info_t asdu_info = (p_asdu_info_t)(Iec10x_Asdu->_info);

    memcpy(&IEC10X_Cp56time2a, asdu_info->_element, sizeof(CP56Time2a_T));

    if (asdu_info->_addr[0] != 0 || asdu_info->_addr[1] != 0 || asdu_info->_addr[2] != 0)
    {
        LOG("-%s- Clock cmd error addr(0x%02x:%02x:%02x) \n", __FUNCTION__, asdu_info->_addr[0], asdu_info->_addr[2], asdu_info->_addr[2]);
        return RET_ERROR;
    }

    switch (Iec10x_Asdu->_reason._reason)
    {

    case IEC10X_COT_ACT:
        LOG("-%s- Clock cmd (20%d-%d-%d %d %d:%d:%d) \n", __FUNCTION__, IEC10X_Cp56time2a._year._year, IEC10X_Cp56time2a._month._month, IEC10X_Cp56time2a._day._dayofmonth,
            IEC10X_Cp56time2a._day._dayofweek, IEC10X_Cp56time2a._hour._hours, IEC10X_Cp56time2a._min._minutes, IEC10X_Cp56time2a._milliseconds);
        /*get time*/
        /*...*/
        iec104->set_time(&IEC10X_Cp56time2a);
        // IEC104_Build_S_Ack();

        break;
    case IEC10X_COT_SPONT:
        LOG("-%s- Clock cmd spont \n", __FUNCTION__);
        break;
    default:
        LOG("-%s- Clock cmd error reason(%d) \n", __FUNCTION__, Iec10x_Asdu->_reason._reason);
        break;
    }
    return RET_SUCESS;
}

iec_8u iec104_asdu_set_act(p_iec10x_asdu_t Iec10x_Asdu, iec_8u Type)
{

    p_asdu_info_t asdu_info = (p_asdu_info_t)(Iec10x_Asdu->_info);
    iec_8u       *ptr       = NULL;
    iec_8u        n = Iec10x_Asdu->_num._num, Sq = Iec10x_Asdu->_num._sq, i;
    float         Value    = 0.0;
    iec_32u       InfoAddr = 0;

    /* if sq == 1 */
    PIEC10X_DETECT_T   detect   = NULL;
    PIEC10X_DETECT_F_T detect_f = NULL;

    /* if sq == 0 */
    PIEC10X_DETECT_SQ0_T   detect_Sq0   = NULL;
    PIEC10X_DETECT_SQ0_F_T detect_Sq0_f = NULL;

    /* check info addrest */
    memcpy(&InfoAddr, asdu_info->_addr, 3);

    switch (Iec10x_Asdu->_reason._reason)
    {

    case IEC10X_COT_ACT:

        switch (Type)
        {
        case IEC10X_C_SE_NA_1:

            if (Sq == 1)
            {
                ptr = asdu_info->_element;
                for (i = 0; i < n; i++)
                {

                    detect = (PIEC10X_DETECT_T)ptr;
                    Value  = (float)(detect->_detect);
                    ptr += sizeof(IEC10X_DETECT_T);
                    iec104->set_config(Value, InfoAddr + i);
                }
            }
            else if (Sq == 0)
            {
                ptr = Iec10x_Asdu->_info;
                for (i = 0; i < n; i++)
                {

                    detect_Sq0 = (PIEC10X_DETECT_SQ0_T)ptr;
                    Value      = (float)(detect_Sq0->_detect);
                    InfoAddr   = 0;
                    memcpy(&InfoAddr, detect_Sq0->_addr, 3);
                    iec104->set_config(Value, InfoAddr);
                    ptr += sizeof(IEC10X_DETECT_SQ0_T);
                }
            }
            break;
        case IEC10X_C_SE_NC_1:
            if (Sq == 1)
            {
                ptr = asdu_info->_element;
                for (i = 0; i < n; i++)
                {

                    detect_f = (PIEC10X_DETECT_F_T)ptr;
                    Value    = detect_f->_detect;
                    ptr += sizeof(IEC10X_DETECT_F_T);
                    iec104->set_config(Value, InfoAddr + i);
                }
            }
            else if (Sq == 0)
            {
                ptr = Iec10x_Asdu->_info;
                for (i = 0; i < n; i++)
                {
                    detect_Sq0_f = (PIEC10X_DETECT_SQ0_F_T)ptr;
                    Value        = (float)(detect_Sq0_f->_detect);
                    memcpy(&InfoAddr, detect_Sq0_f->_addr, 3);
                    iec104->set_config(Value, InfoAddr);
                    ptr += sizeof(IEC10X_DETECT_SQ0_F_T);
                }
            }
            break;
        default:
            LOG("-%s-, Type error !", __FUNCTION__);
            return RET_ERROR;
        }
        break;

    default:
        LOG("-%s- , error reason(%d) \n", __FUNCTION__, Iec10x_Asdu->_reason._reason);
        return RET_ERROR;
    }
    return RET_SUCESS;
}

iec_8u iec104_build_set_ack(iec_8u Prio, iec_8u Type)
{

    iec_8u  len = 0;
    iec_8u *ptr = NULL;

    p_iec104_data_t iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /*build head*/
    iec104_data->head = IEC104_HEAD;

    /*build control code*/
    iec104_data->ctrl.i.type    = 0;
    iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = Type;
    asdu->_num._sq        = 0;
    asdu->_num._num       = 0;
    asdu->_reason._reason = IEC10X_ASDU_REASON_ACTFIN;
    asdu->_addr           = iec104_state_addr;

    /*build info*/
    ptr = info->_addr;

    /*len*/
    len              = ptr - iec104_send_buf;
    iec104_data->len = len - 2;

    // DumpHEX(Iec104_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, Prio, NULL, NULL);

    return RET_SUCESS;
}

iec_8u iec104_deal_sn(iec_16u SendSn, iec_16u RecvSn)
{

    LOG("Receive Pakage I(%d,%d), Send(%d,%d)\n", SendSn, RecvSn, iec104_build_send_sn, iec104_build_recv_sn);

#if 0
    if(SendSn > Iec104_DealSendSn+1){
        LOG("-%s-, error,send last(%d),now(%d) \n",__FUNCTION__,Iec104_DealSendSn,SendSn);
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_SEND_CLOSED;
        return RET_ERROR;
    }else if(SendSn < Iec104_DealSendSn+1){
        LOG("-%s-, Retransmit,send last(%d),now(%d) \n",__FUNCTION__,Iec104_DealSendSn,SendSn);
        return RET_ERROR;
    }
    if(RecvSn != Iec104_BuildSendSn){
        LOG("-%s-, error,receive last(%d),now(%d) \n",__FUNCTION__,Iec104_BuildSendSn,RecvSn);
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_SEND_CLOSED;
        return RET_ERROR;
    }
    if(RecvSn < Iec104_DealRecvSn){
        LOG("-%s-, error,receive2 last(%d),now(%d) \n",__FUNCTION__,Iec104_DealRecvSn,RecvSn);
        return RET_ERROR;
    }
#endif

    if (SendSn < iec104_deal_send_sn || RecvSn < iec104_deal_recv_sn)
    {

        LOG("-%s-, error,send last(%d),now(%d). recv last(%d),now(%d) \n", __FUNCTION__,
            iec104_deal_send_sn, SendSn, iec104_deal_recv_sn, RecvSn);
        return RET_ERROR;
    }
    iec104_build_recv_sn = SendSn + 1;

    iec104_deal_send_sn = SendSn;
    iec104_deal_recv_sn = RecvSn;

    // Iec104_BuildRecvSn++;

    /* return S ACK */
    IEC104_STATE_FLAG_S_ACK = IEC104_FLAG_S_ACK;
    Iec104_TimeCycle_S      = 0;

    return RET_SUCESS;
}
iec_8s iec104_build_data_ack(iec_8u TI, iec_16u COT, iec_32u InfoAddr, iec_16u Info, iec_8u Prio)
{

    iec_8u  len    = 0;
    iec_8u *ptr    = NULL;
    iec_32u temp32 = 0;

    /* build head */
    p_iec104_data_t iec104_data = (p_iec104_data_t)iec104_send_buf;
    p_iec10x_asdu_t asdu        = (p_iec10x_asdu_t)(iec104_data->asdu);
    p_asdu_info_t   info        = (p_asdu_info_t)(asdu->_info);

    /*build head*/
    iec104_data->head = IEC104_HEAD;

    /*build control code*/
    iec104_data->ctrl.i.type    = 0;
    iec104_data->ctrl.i.send_sn = iec104_build_send_sn++;
    iec104_data->ctrl.i.recv_sn = iec104_build_recv_sn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = TI;
    asdu->_num._sq        = 0;
    asdu->_num._num       = 1;
    asdu->_reason._reason = COT;
    asdu->_addr           = iec104_state_addr;

    /*build info*/
    ptr    = info->_addr;
    temp32 = InfoAddr;
    memcpy(ptr, &temp32, 3);

    ptr = info->_element;
    if (COT == IEC10X_COT_ACT_TERMINAL || COT == IEC10X_COT_ACTCON || COT == IEC10X_COT_ACT_TERMINAL_ACK || COT == IEC10X_TI_AP_FIRM_BACKOFF)
    {
        ptr[0] = 0;
        ptr[1] = 0;
        ptr += 2;
    }
    else if (COT == IEC10X_COT_DATA_ACK || COT == IEC10X_COT_DATA_FIN_ACK)
    {
        memcpy(ptr, &Info, 2);
        ptr += 2;
    }

    /*len*/
    len              = ptr - iec104_send_buf;
    iec104_data->len = len - 2;

    // DumpHEX(Iec104_Sendbuf,len);
    /* enqueue to the transmisson queue */
    iec104_enqueue(iec104_send_buf, len, Prio, NULL, NULL);

    return RET_SUCESS;
}

iec_8s iec104_deal_firmware_update(p_iec10x_asdu_t asdu, iec_8u Len)
{

    iec_16u       cot     = asdu->_reason._reason;
    iec_16u       FlagNum = 0, i;
    iec_8u        DataLen = Len - IEC104_DATA_LEN - 3; /* flag num 2, check sum 1 byte*/
    p_asdu_info_t element = (p_asdu_info_t)(asdu->_info);
    iec_8u       *DataPtr = (iec_8u *)(element->_element) + 3;
    iec_8u        TI = asdu->_type, csum = 0, CsumTemp = 0;
    iec_32u       FirmwareType = 0;
    iec_8s        ret          = 0;

    p_asdu_info_t info = (p_asdu_info_t)(asdu->_info);

    FlagNum = *(iec_16u *)(info->_element);
    memcpy(&FirmwareType, asdu->_info, 3);

    if (Len == 0)
    {
        LOG("-%s-,data:%d,Len:%d error!\n", __FUNCTION__, FlagNum, DataLen);
        return RET_ERROR;
    }

    /* reset the flag counter */
    if (FlagNum == 1)
    {
        FirmFlagCount          = 0;
        Iec10x_Update_SeekAddr = 0;
    }

    switch (cot)
    {

    case IEC10X_COT_DATA:

        if (FlagNum == FirmFlagCount + 1)
        {

            /* check sum */
            csum = info->_element[2];

            for (i = 0; i < DataLen; i++)
            {
                CsumTemp += DataPtr[i];
            }
            if (CsumTemp == csum)
            {
                LOG("-%s-,data:%d,Len:%d,seek:%d \n", __FUNCTION__, FlagNum, DataLen, Iec10x_Update_SeekAddr);
                for (i = 0; i < 3; i++)
                {
                    ret = iec104->save_firmware(DataLen, DataPtr, FirmwareType, Iec10x_Update_SeekAddr);
                    if (ret == RET_SUCESS)
                        break;
                }
                if (ret == RET_ERROR)
                {
                    LOG("save firmware error \n");
                    break;
                }

                FirmFlagCount = FlagNum;
                Iec10x_Update_SeekAddr += DataLen;
            }
            else
            {
                LOG("%s, check sum error:%d,need:%d,num:%d\n", __FUNCTION__, CsumTemp, csum, FlagNum);
            }
        }
        else if (FlagNum < FirmFlagCount + 1)
        {
            LOG("update flag resend,need:%d,flag:%d\n", FirmFlagCount + 1, FlagNum);
        }
        else
        {
            LOG("update flag error! need:%d,flag:%d\n", FirmFlagCount + 1, FlagNum);
            // Iec104_BuildDataAck(TI, IEC10X_COT_ACT_TERMINAL, FirmwareType, FlagNum,1);
        }
        break;

    case IEC10X_COT_DATA_NEEDACK:
        if (FlagNum == FirmFlagCount + 1)
        {

            /* check sum */
            csum = info->_element[2];
            for (i = 0; i < DataLen; i++)
            {
                CsumTemp += DataPtr[i];
            }
            if (CsumTemp == csum)
            {
                LOG("-%s-,data need ack:%d,Len:%d,seek:%d \n", __FUNCTION__, FlagNum, DataLen, Iec10x_Update_SeekAddr);

                for (i = 0; i < 3; i++)
                {
                    ret = iec104->save_firmware(DataLen, DataPtr, FirmwareType, Iec10x_Update_SeekAddr);
                    if (ret == RET_SUCESS)
                        break;
                }

                if (ret == RET_ERROR)
                {
                    LOG("save firmware error \n");
                    break;
                }
                iec104_build_data_ack(TI, IEC10X_COT_DATA_ACK, FirmwareType, FlagNum, 1);

                FirmFlagCount = FlagNum;
                Iec10x_Update_SeekAddr += DataLen;
            }
            else
            {
                LOG("%s,need ack check sum error:%d,need:%d,num...:%d\n", __FUNCTION__, CsumTemp, csum, FlagNum);
                // Iec104_BuildDataAck(TI, IEC10X_COT_ACT_TERMINAL, FirmwareType, FlagNum,1);
            }
        }
        else if (FlagNum < FirmFlagCount + 1)
        {
            LOG("update flag resend,need:%d,flag:%d\n", FirmFlagCount + 1, FlagNum);
            iec104_build_data_ack(TI, IEC10X_COT_DATA_ACK, FirmwareType, FlagNum, 1);
        }
        else
        {
            LOG("update flag error! need:%d,flag:%d\n", FirmFlagCount + 1, FlagNum);
            // Iec104_BuildDataAck(TI, IEC10X_COT_ACT_TERMINAL, FirmwareType, FlagNum,1);
        }
        break;

    case IEC10X_COT_DATA_FIN:
        if (FirmFlagCount == FlagNum)
        {
            LOG("-%s-,data finish:%d,Len:%d,Total Len:%d \n", __FUNCTION__, FlagNum, DataLen, Iec10x_Update_SeekAddr);
            ret = iec104->check_firmware(FirmwareType, Iec10x_Update_SeekAddr);
            if (ret == RET_SUCESS)
            {
                iec104_build_data_ack(TI, IEC10X_COT_DATA_FIN_ACK, FirmwareType, FlagNum, 1);
                iec104->update_firmware(FirmwareType);
            }
            else
            {
                /* check firmware error ,terminal update */
                iec104_build_data_ack(TI, IEC10X_COT_ACT_TERMINAL, FirmwareType, 0, 1);
            }
        }
        else
        {
            LOG("-%s-,data finish error:%d,Len:%d,Total Len:%d,FirmFlagCount:%d,FlagNum:%d, \n", __FUNCTION__, FlagNum, DataLen, Iec10x_Update_SeekAddr, FirmFlagCount, FlagNum);
            return RET_ERROR;
        }
        break;

    case IEC10X_COT_ACT_TERMINAL:
        LOG("-%s-, Terminal:%d,Len:%d \n", __FUNCTION__, FlagNum, DataLen);
        iec104_build_data_ack(TI, IEC10X_COT_ACT_TERMINAL_ACK, FirmwareType, 0, 1);
        break;
    case IEC10X_COT_ACT_TERMINAL_ACK:
        LOG("-%s-, Terminal Ack \n", __FUNCTION__);
        break;
    default:
        LOG("-%s-,data:%d,Len:%d error cot: \n", __FUNCTION__, FlagNum, Len);
        return RET_ERROR;
    }
    return RET_SUCESS;
}

void iec104_tester_timer(void)
{

    IEC104_STATE_FLAG_TESTER    = IEC104_FLAG_IDLE;
    Iec104_TimeCycle_TesterIdle = 0;
}

iec_8u iec104_deal_i(p_iec104_data_t Iec104_data, iec_16u len)
{

    iec_8u  Type;
    iec_16u RecvSn, SendSn;
    iec_32u FirmwareType = 0;

    p_iec10x_asdu_t asdu = (p_iec10x_asdu_t)(Iec104_data->asdu);

    SendSn = Iec104_data->ctrl.i.send_sn;
    RecvSn = Iec104_data->ctrl.i.recv_sn;

    /* check asdu addrest */
    if (iec104_state_addr != asdu->_addr)
    {
        LOG("-%s-, error asdu addr(%x)(%x) \n", __FUNCTION__, iec10x_state_addr, asdu->_addr);
        return RET_ERROR;
    }

    /* deal the receive and send serial number */
    if (iec104_deal_sn(SendSn, RecvSn) == RET_ERROR)
    {
        return RET_ERROR;
    }
    /* Start tester timer */
    iec104_tester_timer();

    Type = asdu->_type;
    switch (Type)
    {

    case IEC10X_C_IC_NA_1:
        LOG("++++Asdu Type Call cmd... \n");
        iec104_asdu_call(asdu);
        IEC104_STATE_FLAG_S_ACK = IEC104_FLAG_IDLE;
        break;
    case IEC10X_C_CS_NA_1:
        LOG("++++Asdu Type Clock syc cmd... \n");
        iec104_asdu_clock(asdu);
        break;

    case IEC10X_C_SE_NA_1:
    case IEC10X_C_SE_NC_1:
        LOG("++++Asdu Type Set type(%d)... \n", Type);
        iec104_asdu_set_act(asdu, Type);
        iec104_build_set_ack(1, Type);
        break;
    case IEC10X_TI_FIRM_UPDATE:
        LOG("++++Asdu Type Firmware Update... \n");
        iec104_deal_firmware_update(asdu, len);
        break;
    case IEC10X_TI_AP_FIRM_BACKOFF:
        LOG("++++Asdu Type Firmware Backoff... \n");
        memcpy(&FirmwareType, asdu->_info, 3);
        iec104_build_data_ack(IEC10X_TI_AP_FIRM_BACKOFF, IEC10X_COT_ACTCON, FirmwareType, 0, 1);
        iec104->backoff_firmware(FirmwareType);
        break;
    default:
        LOG("-%s-, error Type(%d) \n", __FUNCTION__, Type);
        return RET_ERROR;
    }
    return RET_SUCESS;
}

iec_8u iec104_deal_s(p_iec104_data_t Iec104_data, iec_16u len)
{

    return RET_SUCESS;
}
iec_8u iec104_deal_u(p_iec104_data_t iec104_data, iec_16u len)
{

    switch (iec104_data->ctrl.func.func)
    {

    case IEC104_U_FUNC_STARTDT:
        LOG(">%s<, function STARTDT \n", __FUNCTION__);
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_LINK_INIT;
        Iec104_TimeCycle       = 0;
        Iec104_TimeCount       = 0;
        // IEC104_Build_U(IEC104_U_FUNC_STARTDT,1);
        // IEC104_Build_InitFin();
        break;
    case IEC104_U_FUNC_STOPDT:
        LOG(">%s<, function STOPDT \n", __FUNCTION__);
        iec104->close_link();
        iec104_build_u(IEC104_U_FUNC_STOPDT, 1);
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_RECV_CLOSED;
        break;
    case IEC104_U_FUNC_TESTER:
        LOG(">%s<, function TESTER \n", __FUNCTION__);
        iec104_build_u(IEC104_U_FUNC_TESTER, 1);
        break;

    /* U ACK */
    case IEC104_U_FUNC_STARTDT_ACK:
        LOG(">%s<, function STARTDT ACK\n", __FUNCTION__);
        break;
    case IEC104_U_FUNC_STOPDT_ACK:
        LOG(">%s<, function STOPDT ACK\n", __FUNCTION__);
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_RECV_CLOSED;
        break;
    case IEC104_U_FUNC_TESTER_ACK:
        LOG(">%s<, function TESTER ACK\n", __FUNCTION__);
        Iec104_TesterCount = 0;
        break;
    default:
        LOG(">%s<, function ERROR \n", __FUNCTION__);
        break;
    }
    return RET_SUCESS;
}

void iec104_receive(iec_8u *buf, iec_16u len)
{

    iec_8u         *BufTemp = NULL;
    iec_16s         LenRemain, LenTmp;
    p_iec104_data_t Iec104_data = NULL;

    if (buf == NULL)
    {
        LOG("-%s-,buffer (null)", __FUNCTION__);
        return;
    }
#if 0
    if(len <= 0 || len>IEC104_MAX_BUF_LEN || len<BufTemp[0]+2){
        LOG("-%s-,buffer len error(%d) \n",__FUNCTION__,len);
        return;
    }
#endif

    BufTemp   = buf;
    LenRemain = len;

    while (BufTemp < buf + len)
    {

        Iec104_data = (p_iec104_data_t)BufTemp;
        iec104_lock();
        if (Iec104_data->head == IEC104_HEAD)
        {

            LenTmp = Iec104_data->len + 2;
            if (LenRemain < IEC104_HEAD_LEN)
            {
                LOG("_%s_,len error(%d) \n", __FUNCTION__, len);
                iec104_unlock();
                return;
            }
            if (Iec104_data->ctrl.type.type_1 == 0)
            {
                LOG("-%s-,frame type i \n", __FUNCTION__);
                iec104_deal_i(Iec104_data, LenTmp);
            }
            else if (Iec104_data->ctrl.type.type_1 == 1 && Iec104_data->ctrl.type.type_2 == 0)
            {
                LOG("-%s-,frame type s \n", __FUNCTION__);
                iec104_deal_s(Iec104_data, LenTmp);
            }
            else if (Iec104_data->ctrl.type.type_1 == 1 && Iec104_data->ctrl.type.type_2 == 1)
            {
                LOG("-%s-,frame type u \n", __FUNCTION__);
                iec104_deal_u(Iec104_data, LenTmp);
            }
        }
        else
        {
            LOG("-%s-,head type error(%d) \n", __FUNCTION__, BufTemp[0]);
            iec104_unlock();
            return;
        }
        iec104_unlock();
        BufTemp += LenTmp;
        LenRemain -= LenTmp;
    }
    return;
}

void iec104_reset_flag(void)
{

    IEC104_STATE_FLAG_CALLALL = IEC104_FLAG_IDLE;
    IEC104_STATE_FLAG_GROUP   = IEC104_FLAG_IDLE;
    IEC104_STATE_FLAG_CLOCK   = IEC104_FLAG_IDLE;
    IEC104_STATE_FLAG_TESTER  = IEC104_FLAG_IDLE;

    iec104_build_send_sn = 0;
    iec104_build_recv_sn = 0;
    iec104_deal_send_sn  = -1;
    iec104_deal_recv_sn  = 0;

    Iec104_TesterCount = 0;
}

iec_32u TestCount_Temp = 0;
iec_8u  iec104_state_machine(void)
{

    /*Init link*/
    switch (IEC104_STATE_FLAG_INIT)
    {
    case IEC104_FLAG_CLOSED:
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_START_LINK;
        iec104_queue_clear();
        iec104_reset_flag();
        break;
    case IEC104_FLAG_SEND_CLOSED:
        Iec104_TimeCycle += IEC104_CYCLE_TIME_MS;
        if (Iec104_TimeCycle > IEC104_RESEND_TIME_MS)
        {
            Iec104_TimeCycle = 0;
            Iec104_TimeCount++;
            iec104_build_u(IEC104_U_FUNC_STOPDT, 0);
        }
        if (Iec104_TimeCount >= 3)
        {
            Iec104_TimeCount       = 0;
            IEC104_STATE_FLAG_INIT = IEC104_FLAG_IDLE;
            iec104->close_link();
        }
        break;
    case IEC104_FLAG_RECV_CLOSED:
        iec104_reset_flag();
        iec104_queue_clear();
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_CONNECT_SUCESS;
        break;
    case IEC104_FLAG_LINK_INIT:
        LOG("Iec104 machine state :IEC104_FLAG_LINK_INIT \n");
        iec104_reset_flag();
        iec104_state_addr = iec104->get_link_addr();
        iec104_build_u(IEC104_U_FUNC_STARTDT, 1);
        iec104_build_init_fin();
        iec104_build_upload(IEC10X_TI_AP_BASE_INFO, IEC10X_PRIO_INITLINK, AP_TYPE_BASE_INFO);
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_CONNECT_SUCESS;
        break;
    case IEC104_FLAG_UPLOAD_ADDR:
        Iec104_TimeCycle += IEC104_CYCLE_TIME_MS;
        if (Iec104_TimeCycle > IEC104_RESEND_TIME_MS)
        {
            iec104_state_addr = iec104->get_link_addr();
            Iec104_TimeCycle  = 0;
            Iec104_TimeCount++;
            iec104_upload_addr();
        }
        if (Iec104_TimeCount >= 3)
        {
            Iec104_TimeCount       = 0;
            IEC104_STATE_FLAG_INIT = IEC104_FLAG_IDLE;
            iec104->close_link();
        }
        break;

    case IEC104_FLAG_CONNECT_SUCESS:
    case IEC104_FLAG_IDLE:
    default:
        break;
    }
    if (IEC104_STATE_FLAG_INIT == IEC104_FLAG_CONNECT_SUCESS)
    {

        /* Return s ack */
        switch (IEC104_STATE_FLAG_S_ACK)
        {

        case IEC104_FLAG_S_ACK:
            Iec104_TimeCycle_S += IEC104_CYCLE_TIME_MS;
            if (Iec104_TimeCycle_S > IEC104_S_ACK_TIMEOUT)
            {
                Iec104_TimeCycle_S = 0;
                iec104_build_s_ack();
                IEC104_STATE_FLAG_S_ACK = IEC104_FLAG_IDLE;
            }
            break;
        case IEC104_FLAG_IDLE:
            break;
        default:
            break;
        }
        /* test spon */
#if 1
        if (TestCount_Temp++ > (10 * 60 * 20))
        {
            TestCount_Temp = 0;
            iec104_build_signal_spon(1, 1, IEC104_INFOADDR_STATE_HXGF + 2);
            iec104_build_detect_f_spont(1, 60.2, IEC104_INFOADDR_VALUE_HXTM + 2);
            iec104_build_detect_f_spont(1, 61.1, IEC104_INFOADDR_VALUE_HXGF + 2);
        }
#endif
    }
    /* Tester */
    switch (IEC104_STATE_FLAG_TESTER)
    {
    case IEC104_FLAG_TESTER:
        iec104_build_u(IEC104_U_FUNC_TESTER, 0);
        IEC104_STATE_FLAG_TESTER = IEC104_FLAG_IDLE;
        Iec104_TesterCount++;
        LOG("Tester Count(%d)... \n", Iec104_TesterCount);
        if (Iec104_TesterCount > 3)
        {
            Iec104_TesterCount = 0;
            LOG("Tester error(%d)... \n", Iec104_TesterCount);
            IEC104_STATE_FLAG_INIT = IEC104_FLAG_CLOSED;
            iec104->close_link();
        }
        break;
    case IEC104_FLAG_TESTER_STOP:
        break;
    case IEC104_FLAG_IDLE:
        Iec104_TimeCycle_TesterIdle += IEC104_CYCLE_TIME_MS;
        if (Iec104_TimeCycle_TesterIdle > IEC104_TESTER_IDLE_TIMEOUT)
        {
            Iec104_TimeCycle_TesterIdle = 0;
            IEC104_STATE_FLAG_TESTER    = IEC104_FLAG_TESTER;
        }
        break;
    default:
        break;
    }
    return RET_SUCESS;
}
