#include "iec104.h"
#include "iec10x_conf.h"
#include "iec10x_type.h"

/*
 * GLOABLE VARIALBLE
 */

iec_8u Iec104_Sendbuf[IEC104_MAX_BUF_LEN];
/*
 * STATE
 * */
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;
/*
 * receive and send serial number
 * */
iec_32s Iec104_BuildSendSn = 0;
iec_32s Iec104_BuildRecvSn = 0;
iec_32s Iec104_DealSendSn  = -1;
iec_32s Iec104_DealRecvSn  = 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_UploadAddr(void)
{

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

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*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           = Iec10x_Sta_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 = Iec10x_Sta_Addr;
    memcpy(ptr, &Temp32, 2);

    ptr += 2;

    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    IEC10X_Enqueue(Iec104_Sendbuf, len, IEC10X_PRIO_INITLINK, NULL, NULL);

    return RET_SUCESS;
}

iec_8u IEC104_Build_InitFin(void)
{

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

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*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           = Iec10x_Sta_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_Sendbuf;
    Iec104Data->Len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    IEC10X_Enqueue(Iec104_Sendbuf, len, IEC10X_PRIO_INITLINK, NULL, NULL);

    return RET_SUCESS;
}

iec_8u IEC104_BuildCallACK(iec_8u qoi, iec_8u Prio)
{

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

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*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           = Iec10x_Sta_Addr;

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

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

    ptr += 1;
    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;

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

    return RET_SUCESS;
}

iec_8u IEC104_BuildSignal_Spon(iec_8u TimeFlag, iec_8u signalV, iec_16u addrV)
{

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

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

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

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*build ASDU , COT ,Addr*/
    if (TimeFlag == 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           = Iec10x_Sta_Addr;

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

    /*build info value*/
    ptr = info->_element;
    for (i = 0; i < asdu_num; i++)
    {
        *ptr = signalV;
        ptr++;
    }
    if (TimeFlag == 1)
    {
        time = (PCP56Time2a_T)ptr;
        IEC10X->GetTime(time);
        ptr += sizeof(CP56Time2a_T);
    }

    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;

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

    return RET_SUCESS;
}
iec_8u IEC104_BuildDetect_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;

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_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*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*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           = Iec10x_Sta_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;
        IEC10X->GetTime(time);
        ptr += sizeof(CP56Time2a_T);
    }

    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;

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

    return RET_SUCESS;
}

iec_8u IEC104_BuildDetectF_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;

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_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*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*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           = Iec10x_Sta_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;
        IEC10X->GetTime(time);
        ptr += sizeof(CP56Time2a_T);
    }

    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;

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

    return RET_SUCESS;
}
iec_8u IEC104_BuildSignal(iec_8u reason, iec_8u Prio, iec_8u DevType)
{

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

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

    /*get value*/
    IEC10X->GetInfoNum(&asdu_num, DevType);
    LOG("-%s- total info (%d) \n\n", __FUNCTION__, asdu_num);

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*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           = Iec10x_Sta_Addr;

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

    memcpy(ptr, &Temp32, 3);

    /*build info value*/
    ptr = info->_element;
    for (i = 0; i < asdu_num; i++)
    {
        *ptr = IEC10X->GetStationState(i, DevType);
        ptr++;
    }

    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;

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

    return RET_SUCESS;
}

iec_8u IEC104_BuildDetect(iec_8u reason, iec_8u ValueType, iec_8u Prio, iec_8u DevType)
{

    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;

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

    /*get value*/
    IEC10X->GetInfoNum(&asdu_num, DevType);
    LOG("-%s- total info (%d) \n\n", __FUNCTION__, asdu_num);

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

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

    /*build info addr*/
    ptr = info->_addr;
    if (DevType == ENDDEVICE_TYPE_HXTM)
    {
        Temp32 = IEC104_INFOADDR_VALUE_HXTM;
    }
    else if (DevType == ENDDEVICE_TYPE_HXGF)
    {
        Temp32 = IEC104_INFOADDR_VALUE_HXGF;
    }
    else
    {
        LOG("-%s-, error dev type:%d \n", __FUNCTION__, DevType);
        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 = IEC10X->GetStaValue(i, DevType);
            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 = IEC10X->GetStaValue(i, DevType);
            detect_f->_qds    = 0;
            ptr += sizeof(IEC10X_DETECT_F_T);
        }
    }

    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;

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

    return RET_SUCESS;
}

iec_8u IEC104_BuildUpload(iec_8u ValueType, iec_8u Prio, iec_8u DevType)
{

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

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

    /*get value*/
    IEC10X->GetInfoNum(&asdu_num, DevType);
    LOG("-%s- total info (%d) \n\n", __FUNCTION__, asdu_num);

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*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           = Iec10x_Sta_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 = IEC10X->GetStaValue(i, DevType);
        detect->_qds    = 0;
        ptr += sizeof(IEC10X_DETECT_T);
    }
    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;

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

    return RET_SUCESS;
}

iec_8u IEC104_BuildActFinish(iec_8u qoi, iec_8u Prio)
{

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

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*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           = Iec10x_Sta_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_Sendbuf;
    Iec104Data->Len = len - 2;

    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    IEC10X_Enqueue(Iec104_Sendbuf, 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;

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;

    /*build head*/
    Iec104Data->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:
        Iec104Data->Ctrl.Func.Func = Start;
        break;
    case IEC104_U_FUNC_STOPDT:
        Iec104Data->Ctrl.Func.Func = Stop;
        break;
    case IEC104_U_FUNC_TESTER:
        Iec104Data->Ctrl.Func.Func = Tester;
        break;
    default:
        LOG(">%s<, U Type Error(%d) !\n", __FUNCTION__, UType);
        return RET_ERROR;
    }

    /*build ASDU , COT ,Addr*/
    ptr = Iec104Data->Asdu;

    /*build info*/

    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;
    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    IEC10X_Enqueue(Iec104_Sendbuf, len, IEC10X_PRIO_INITLINK, NULL, NULL);

    return RET_SUCESS;
}

iec_8u IEC104_Build_S_Ack(void)
{

    iec_8u  len = 0;
    iec_8u *ptr = NULL;

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.S.Type1 = 1;
    Iec104Data->Ctrl.S.Type2 = 0;

    Iec104Data->Ctrl.S.Reserve = 0;
    Iec104Data->Ctrl.S.RecvSn  = Iec104_BuildRecvSn;

    /*build ASDU , COT ,Addr*/
    ptr = Iec104Data->Asdu;

    /*build info*/

    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;
    // DumpHEX(Iec101_Sendbuf,len);
    /* enqueue to the transmisson queue */
    IEC10X_Enqueue(Iec104_Sendbuf, len, IEC10X_PRIO_INITLINK, NULL, NULL);

    return RET_SUCESS;
}
iec_8u IEC104_ASDU_Call(PIEC10X_ASDU_T Iec10x_Asdu)
{

    PASDU_INFO_T asdu_info = (PASDU_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_BuildCallACK(qoi, Prio);
        /**/
        IEC104_BuildSignal(qoi, Prio, ENDDEVICE_TYPE_HXTM);
        IEC104_BuildDetect(qoi, IEC10X_M_ME_NA_1, Prio, ENDDEVICE_TYPE_HXTM);
        /**/
        IEC104_BuildSignal(qoi, Prio, ENDDEVICE_TYPE_HXGF);
        IEC104_BuildDetect(qoi, IEC10X_M_ME_NA_1, Prio, ENDDEVICE_TYPE_HXGF);
        IEC104_BuildActFinish(qoi, Prio);
        break;

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

    PASDU_INFO_T asdu_info = (PASDU_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*/
        /*...*/
        IEC10X->SetTime(&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_SetAct(PIEC10X_ASDU_T Iec10x_Asdu, iec_8u Type)
{

    PASDU_INFO_T asdu_info = (PASDU_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);
                    IEC10X->SetConfig(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);
                    IEC10X->SetConfig(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);
                    IEC10X->SetConfig(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);
                    IEC10X->SetConfig(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_SetAck(iec_8u Prio, iec_8u Type)
{

    iec_8u  len = 0;
    iec_8u *ptr = NULL;

    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

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

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

    /*len*/
    len             = ptr - Iec104_Sendbuf;
    Iec104Data->Len = len - 2;

    // DumpHEX(Iec104_Sendbuf,len);
    /* enqueue to the transmisson queue */
    IEC10X_Enqueue(Iec104_Sendbuf, 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_BuildSendSn, Iec104_BuildRecvSn);

#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_DealSendSn || RecvSn < Iec104_DealRecvSn)
    {

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

    Iec104_DealSendSn = SendSn;
    Iec104_DealRecvSn = 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_BuildDataAck(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 */
    PIEC104_DATA_T Iec104Data = (PIEC104_DATA_T)Iec104_Sendbuf;
    PIEC10X_ASDU_T asdu       = (PIEC10X_ASDU_T)(Iec104Data->Asdu);
    PASDU_INFO_T   info       = (PASDU_INFO_T)(asdu->_info);

    /*build head*/
    Iec104Data->Head = IEC104_HEAD;

    /*build control code*/
    Iec104Data->Ctrl.I.Type   = 0;
    Iec104Data->Ctrl.I.SendSn = Iec104_BuildSendSn++;
    Iec104Data->Ctrl.I.RecvSn = Iec104_BuildRecvSn;

    /*build ASDU , COT ,Addr*/
    asdu->_type           = TI;
    asdu->_num._sq        = 0;
    asdu->_num._num       = 1;
    asdu->_reason._reason = COT;
    asdu->_addr           = Iec10x_Sta_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_Sendbuf;
    Iec104Data->Len = len - 2;

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

    return RET_SUCESS;
}

iec_8s Iec104_Deal_FirmUpdate(PIEC10X_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*/
    PASDU_INFO_T element = (PASDU_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;

    PASDU_INFO_T info = (PASDU_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 = IEC10X->SaveFirmware(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 = IEC10X->SaveFirmware(DataLen, DataPtr, FirmwareType, Iec10x_Update_SeekAddr);
                    if (ret == RET_SUCESS)
                        break;
                }

                if (ret == RET_ERROR)
                {
                    LOG("save firmware error \n");
                    break;
                }
                Iec104_BuildDataAck(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_BuildDataAck(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 = IEC10X->CheckFirmware(FirmwareType, Iec10x_Update_SeekAddr);
            if (ret == RET_SUCESS)
            {
                Iec104_BuildDataAck(TI, IEC10X_COT_DATA_FIN_ACK, FirmwareType, FlagNum, 1);
                IEC10X->UpdateFirmware(FirmwareType);
            }
            else
            {
                /* check firmware error ,terminal update */
                Iec104_BuildDataAck(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_BuildDataAck(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(PIEC104_DATA_T Iec104Data, iec_16u len)
{

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

    PIEC10X_ASDU_T asdu = (PIEC10X_ASDU_T)(Iec104Data->Asdu);

    SendSn = Iec104Data->Ctrl.I.SendSn;
    RecvSn = Iec104Data->Ctrl.I.RecvSn;

    /* check asdu addrest */
    if (Iec10x_Sta_Addr != asdu->_addr)
    {
        LOG("-%s-, error asdu addr(%x)(%x) \n", __FUNCTION__, Iec10x_Sta_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_Aadu_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_SetAct(asdu, Type);
        IEC104_Build_SetAck(1, Type);
        break;
    case IEC10X_TI_FIRM_UPDATE:
        LOG("++++Asdu Type Firmware Update... \n");
        Iec104_Deal_FirmUpdate(asdu, len);
        break;
    case IEC10X_TI_AP_FIRM_BACKOFF:
        LOG("++++Asdu Type Firmware Backoff... \n");
        memcpy(&FirmwareType, asdu->_info, 3);
        Iec104_BuildDataAck(IEC10X_TI_AP_FIRM_BACKOFF, IEC10X_COT_ACTCON, FirmwareType, 0, 1);
        IEC10X->BackoffFirmware(FirmwareType);
        break;
    default:
        LOG("-%s-, error Type(%d) \n", __FUNCTION__, Type);
        return RET_ERROR;
    }
    return RET_SUCESS;
}

iec_8u Iec104_Deal_S(PIEC104_DATA_T Iec104Data, iec_16u len)
{

    return RET_SUCESS;
}
iec_8u Iec104_Deal_U(PIEC104_DATA_T Iec104Data, iec_16u len)
{

    switch (Iec104Data->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__);
        IEC10X->CloseLink();
        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 Iex104_Receive(iec_8u *buf, iec_16u len)
{

    iec_8u        *BufTemp = NULL;
    iec_16s        LenRemain, LenTmp;
    PIEC104_DATA_T Iec104Data = 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)
    {

        Iec104Data = (PIEC104_DATA_T)BufTemp;
        Iec10x_Lock();
        if (Iec104Data->Head == IEC104_HEAD)
        {

            LenTmp = Iec104Data->Len + 2;
            if (LenRemain < IEC104_HEAD_LEN)
            {
                LOG("_%s_,len error(%d) \n", __FUNCTION__, len);
                Iec10x_UnLock();
                return;
            }
            if (Iec104Data->Ctrl.Type.Type1 == 0)
            {
                LOG("-%s-,Frame Type I \n", __FUNCTION__);
                Iec104_Deal_I(Iec104Data, LenTmp);
            }
            else if (Iec104Data->Ctrl.Type.Type1 == 1 && Iec104Data->Ctrl.Type.Type2 == 0)
            {
                LOG("-%s-,Frame Type S \n", __FUNCTION__);
                Iec104_Deal_S(Iec104Data, LenTmp);
            }
            else if (Iec104Data->Ctrl.Type.Type1 == 1 && Iec104Data->Ctrl.Type.Type2 == 1)
            {
                LOG("-%s-,Frame Type U \n", __FUNCTION__);
                Iec104_Deal_U(Iec104Data, LenTmp);
            }
        }
        else
        {
            LOG("-%s-,head type error(%d) \n", __FUNCTION__, BufTemp[0]);
            Iec10x_UnLock();
            return;
        }
        Iec10x_UnLock();
        BufTemp += LenTmp;
        LenRemain -= LenTmp;
    }
    return;
}

void Iec104_ResetFlag(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_BuildSendSn = 0;
    Iec104_BuildRecvSn = 0;
    Iec104_DealSendSn  = -1;
    Iec104_DealRecvSn  = 0;

    Iec104_TesterCount = 0;
}

iec_32u TestCount_Temp = 0;
iec_8u  Iec104_StateMachine(void)
{

    /*Init link*/
    switch (IEC104_STATE_FLAG_INIT)
    {

    case IEC104_FLAG_CLOSED:
#if defined(IEC104_STM32_FUJIAN_HX)
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_UPLOAD_ADDR;
#else
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_START_LINK;
        IEC10X_ClearQ();
        Iec104_ResetFlag();
#endif /* IEC104_STM32_FUJIAN_HX */
        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;
            IEC10X->CloseLink();
        }
        break;
    case IEC104_FLAG_RECV_CLOSED:
        Iec104_ResetFlag();
        IEC10X_ClearQ();
        IEC104_STATE_FLAG_INIT = IEC104_FLAG_CONNECT_SUCESS;
        break;
    case IEC104_FLAG_LINK_INIT:
        LOG("Iec104 machine state :IEC104_FLAG_LINK_INIT \n");
        Iec104_ResetFlag();
        Iec10x_Sta_Addr = IEC10X->GetLinkAddr();
        IEC104_Build_U(IEC104_U_FUNC_STARTDT, 1);
        IEC104_Build_InitFin();
        IEC104_BuildUpload(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)
        {
            Iec10x_Sta_Addr  = IEC10X->GetLinkAddr();
            Iec104_TimeCycle = 0;
            Iec104_TimeCount++;
            IEC104_UploadAddr();
        }
        if (Iec104_TimeCount >= 3)
        {
            Iec104_TimeCount       = 0;
            IEC104_STATE_FLAG_INIT = IEC104_FLAG_IDLE;
            IEC10X->CloseLink();
        }
        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 0
        if(TestCount_Temp++>(10*60*20)){
            TestCount_Temp = 0;
            IEC104_BuildSignal_Spon(1, 1, IEC104_INFOADDR_STATE_HXGF+2);
            IEC104_BuildDetectF_Spont(1, 60.2, IEC104_INFOADDR_VALUE_HXTM+2);
            IEC104_BuildDetectF_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;
            IEC10X->CloseLink();
        }
        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;
}
