#include "mySystem.h"
#include "myLog.h"
#include "myCmd.h"
#include "iec.h"
#include "iec_method.h"


stru_iec_60870 g_iec60870[MAX_IEC_NUM];
uint32_t g_uilinkOverTime = 600000;


int iec_data_tx(uint8_t *p_tx, uint16_t tx_len, void *arg);

void set_ptl_104_param(stru_iec_60870 *p_iec)
{
    struct CS10x_AppLayerParameters stAppParam;  /*规约共用参数*/

    /*AppLayerParameters*/
    stAppParam.iSzOfVSQ = 1;  
    stAppParam.iLinkAddr = 1;
    stAppParam.iSzOfCOT = 2; //传输原因字节数
    stAppParam.iSzOfCA = 2; //公共地址字节数
    stAppParam.iPublicAddr = 1; //公共地址
    stAppParam.iMaxSzOfAsduLen = 249;    
    stAppParam.iSzOfIOA = 3; //信息体地址字节数
    CS10x_SetAppParameters(&p_iec->cs10x, &stAppParam);

    /*APCIParameter*/
    struct CS104_APCIParameters stApciParam;
    stApciParam.iK = 12;
    stApciParam.iW = 8;
    stApciParam.iT0 = 10;
    stApciParam.iT1 = 12;
    stApciParam.iT2 = 8;
    stApciParam.iT3 = 15;
    CS10x_SetAPCIParameters(&p_iec->cs10x, &stApciParam);

        /*Yc Yx DD*/
    CS10x_SetYcType(&p_iec->cs10x, 2); /*遥测类型 0整形 2浮点*/
    CS10x_SetYxType(&p_iec->cs10x, 0); /*0单点 1双点*/
    CS10x_SetDdType(&p_iec->cs10x, 1);
    CS10x_FrameGap(&p_iec->cs10x, 10); /*发送帧间隔*/
    CS10x_SetMultFrameEn(&p_iec->cs10x, 0); /* 多帧使能*/
        
    CS10x_FaultEventEn(&p_iec->cs10x, 0);
    CS10x_SetSendSoe(&p_iec->cs10x, 1);  /*发送SOE使能*/
    CS10x_SetSendCos(&p_iec->cs10x, 1);  /*发送COS使能*/
    CS10x_SetYKEendFrame(&p_iec->cs10x, 0); /*遥控结束帧使能*/
    CS10x_SetReadFileVSQ(&p_iec->cs10x, 0); /*读文件数据传输VSQ值*/
    CS10x_SetPresetContType(&p_iec->cs10x, 0);/*参数预置忽略无后续帧*/
}

void set_ptl_101_param(stru_iec_60870 *p_iec)
{
    struct CS10x_AppLayerParameters stAppParam;  /*规约共用参数*/

    stAppParam.iSzOfLinkAddr = 2; //链路地址字节数
    stAppParam.iSzOfVSQ = 1;  
    stAppParam.iSzOfCOT = 2; //传输原因字节数
    stAppParam.iSzOfCA = 2; //公共地址字节数
    stAppParam.iLinkAddr = 1; //链路地址
    stAppParam.iPublicAddr = 1; //公共地址
    stAppParam.iMaxSzOfAsduLen = 245;
    stAppParam.iSzOfIOA = 2; //信息体地址字节数
    CS10x_SetAppParameters(&p_iec->cs10x, &stAppParam);

    CS10x_ResendGap(&p_iec->cs10x, 5 * 1000); 
    CS10x_ResendCnt(&p_iec->cs10x, 5);
    /*Yc Yx DD*/
    CS10x_SetYcType(&p_iec->cs10x, 2); /*0整形 2浮点*/
    CS10x_SetYxType(&p_iec->cs10x, 0); /*0单点 1双点*/
    CS10x_SetDdType(&p_iec->cs10x, 1);
    CS10x_SetHeartTimeGap(&p_iec->cs10x, 10 * 1000); /*心跳间隔*/
    CS10x_FrameGap(&p_iec->cs10x, 10);/*发送帧间隔*/
    CS10x_SetFileAckType(&p_iec->cs10x, 0);/*文件ack应答 只101*/
    CS10x_SetInitType(&p_iec->cs10x, 1);
    
    CS10x_SetSendSoe(&p_iec->cs10x, 1);  /*发送SOE使能*/
    CS10x_SetSendCos(&p_iec->cs10x, 1);  /*发送COS使能*/
    CS10x_SetYKEendFrame(&p_iec->cs10x, 0); /*遥控结束帧使能*/
    CS10x_SetReadFileVSQ(&p_iec->cs10x, 0); /*读文件数据传输VSQ值*/
    CS10x_FaultEventEn(&p_iec->cs10x, 0);
    CS10x_SetPresetContType(&p_iec->cs10x, 0);/*参数预置忽略无后续帧*/

}

void set_ptl_itfc(stru_iec_60870 *p_iec)
{
    CS10x *pstCs10x = &p_iec->cs10x;     
    /*系统时间接口*/
    // CS10x_TimeRWHandler(pstCs10x, GetTimeItfs, SetTimeItfs);
    // CS10x_WR_ResetHandler(pstCs10x, Cs10xReadFileResetCOI, Cs10xWriteFileResetCOI);
    /*子站时，配置获取信息接口*/
    if (CS104_TYPE_S == p_iec->iec_type || CS101_TYPE_S == p_iec->iec_type)
    {
        /*遥测接口*/
        // CS10x_S_GetYcByGroupHandler(pstCs10x, GetYcCountByGroup, GetYcValueByGroup);
        /*扰动遥测接口*/
        // CS10x_S_DiturbYcHandler(pstCs10x, GetDiturbYc, GetDiturbYcSendNum, UpdateDiturbYcPtrOut);
        /*遥信接口*/
        // CS10x_S_GetYxByGroupHandler(pstCs10x, GetYxCountByGroup, GetYxStatusByGroup);
        /*SOE接口*/
        // CS10x_S_SOEHandler(pstCs10x, GetSOE, GetSOESendNum, UpdateSoePtrOut);
        /*电能量接口*/
        // CS10x_S_GetDdByGroupHandler(pstCs10x,GetDdCountByGroup,GetDdValueByGroup);
        /*扰动电度接口*/
        // CS10x_S_DiturbDduHandler(pstCs10x, GetTimeDdu, GetTimeDduSendNum, UpdateTimeDduPtrOut);
        /*故障事件接口*/
        // CS10x_S_FaultEventHandler(pstCs10x, GetEventSendNum, GetFaultEvent, UpdateFaultEventPtrOut);
        /*遥控操作校验*/
        // CS10x_S_YkVerifyHandler(pstCs10x, Cs10xYkVerifyItfs);
        /*定值区号相关接口*/
        // CS10x_S_ParamAreaHandler(pstCs10x, GbParamGetParamArea, GbParamSetParamArea);
        // /*IECP参数相关接口*/
        // CS10x_S_IECParamHandler(pstCs10x, GbParamAddElement, GbParamRunRding, GbParamRunWting);
        // /*获取参数信息相关接口*/    
        // CS10x_S_GetParamInfoHandler(pstCs10x, GbParamGetTotalNum, GbParamGetIecParam);
        // /*文件操作相关函数*/
        // CS10x_S_FileReadOprtHandler(pstCs10x, Fm_GetDirFile, Fm_SearchDirFileNum, Fm_ReadFile, (void *)&pstEntity->stReadParam);
        // CS10x_S_FileWriteOprtHandler(pstCs10x, Cs10xWriteItfs, Cs10xWriteFileCheckItfs, Cs10xWriteFinishItfs, (void *)&pstEntity->stWriteParam);
        // /*升级处理流程*/
        // CS10x_S_UpdateProcHandler(pstCs10x, NULL);
    }
    else /*下行101 计量模块电量表关联*/
    {
      //  CS10x_M_SetDdHandler(pstCs10x, SetMeterYcValue, SetMeterDdValue) ;   	
    }
    /*遥控接口*/
    // CS10x_SetYkInforHandler(pstCs10x, SetYkInfor);
}


void protocol_config(stru_iec_60870 *p_iec)
{
    CS10x_Type iec_type = p_iec->iec_type;

    if(iec_type <= CS104_TYPE_S)
    {
        CS10x *p_cs10x = &p_iec->cs10x;

        if(iec_type == CS104_TYPE_S)
        {
            CS10x_104Init(p_cs10x, iec_data_tx, (void *)&p_iec->interface, iec_type);

            set_ptl_104_param(p_iec);
        }
        else if(iec_type == CS101_TYPE_S /*|| iec_type == CS101_TYPE_M*/ )
        {
            CS10x_101Init(p_cs10x, iec_data_tx, (void *)&p_iec->interface, iec_type);

            set_ptl_101_param(p_iec);
        }
        else
        {
            return;
        }

        set_ptl_itfc(p_iec);
    }
}

stru_iec_60870 *iec60870_ptr_get(uint32_t interface, CS10x_Type iec_type)
{
    uint32_t tm_max = 0;
    char temp_buf[20] = {0};
    uint8_t max_idx = 0;
    uint8_t i = 0;
    stru_iec_60870 *p_iec = NULL;

    for(i = 0; i < MAX_IEC_NUM; i++)
    {
        if(interface == g_iec60870[i].interface)
        {
            if(g_iec60870[i].is_busy)
            {
                g_iec60870[i].tm_out = 0;
                if(iec_type == g_iec60870[i].iec_type)
                {
                    return &g_iec60870[i];
                }
                else
                {
                    g_iec60870[i].is_busy = 0;
                }
            }
        }

        if(tm_max < g_iec60870[i].tm_out)
        {
            tm_max = g_iec60870[i].tm_out;
            max_idx = i;
        }
    }

    for(i = 0; i < MAX_IEC_NUM; i++)
    {
        if(0 == g_iec60870[i].is_busy)
        {
            p_iec = &g_iec60870[i];
            break;
        }
    }

    if(NULL == p_iec)
    {
        i = max_idx;
    }

    p_iec = &g_iec60870[i];
    sprintf(temp_buf, "ch%x Link", interface);

    p_iec->is_busy = 1;
    p_iec->interface = interface;
    p_iec->iec_type = iec_type;
    p_iec->tm_out = 0;

    memset(&p_iec->cs10x, 0, sizeof(CS10x_t));

    p_iec->cs10x.stRecvBuf.pBuf = p_iec->buf.rx;
    p_iec->cs10x.stSendBuf.pBuf = p_iec->buf.tx;
    p_iec->cs10x.stPubBuf.pBuf = p_iec->buf.pub;
    p_iec->cs10x.stSendBakBuf.pBuf = p_iec->buf.bak;

    p_iec->cs10x.stRecvBuf.usBufSize = IEC_BUF_SIZE;
    p_iec->cs10x.stSendBuf.usBufSize = IEC_BUF_SIZE;
    p_iec->cs10x.stPubBuf.usBufSize = IEC_BUF_SIZE;
    p_iec->cs10x.stSendBakBuf.usBufSize = IEC_BUF_SIZE;

    protocol_config(p_iec);

    return p_iec;
}

stru_iec_60870 *iec60870_get_by_interface(uint32_t interface)
{
    for(uint8_t i = 0; i < MAX_IEC_NUM; i++)
    {
        if(interface == g_iec60870[i].interface && 1 == g_iec60870[i].is_busy)
        {
            return &g_iec60870[i];
        }
    }

    return NULL;
}

CS10x *cs10x_get_by_interface(uint32_t interface)
{
    stru_iec_60870 *p_iec = iec60870_get_by_interface(interface);
    if(NULL != p_iec)
    {
        return &p_iec->cs10x;
    }

    return NULL;
}

LOCAL bool iec_check_101_frame(uint8_t *data, uint16_t len)
{
    if(data[0] == 0x10 && data[len - 1] == 0x16)
    {
        return true;
    }

    if(data[0] == 0x68 && data[3] == 0x68 && data[1] == data[2] && data[len - 1] == 0x16)
    {
        return true;
    }

    return false;
}

LOCAL void iec60870_decode(uint8_t *data, uint16_t len, uint32_t interface)
{
    if(NULL == data)
    {
        LOG_E("iec60870_decode data null");
        return;
    }

    CS10x_Type iec_type = CS104_TYPE_S;

    if(iec_check_101_frame(data, len))
    {
        iec_type = CS101_TYPE_S;
    }

    stru_iec_60870 *p_iec = iec60870_ptr_get(interface, iec_type);
    if(NULL == p_iec)
    {
        LOG_E("iec60870_decode iec_60870_get null");
        return;
    }

    p_iec->tm_out = 0;
    CS10x_DoRecv(&p_iec->cs10x, (char *)data, len);
}

int iec_data_tx(uint8_t *p_tx, uint16_t tx_len, void *arg)
{
    if(tx_len + sizeof(stru_msg_head) > MSG_SIZE)
    {
        LOG_E("iec_data_tx tx_len %d > MSG_SIZE", tx_len);
        return -1;
    }
    

    uint32_t interface = *(uint32_t *)arg;

    stru_rtx_data *p_rtx = NULL;
    stru_app *p_app = NULL;
    stru_app_msg_queue *p_mq = NULL;

    if(NULL == (p_app = app_get_ptr(ENUM_APP_IEC)))
    {
        LOG_E("iec_data_tx app_get_ptr failed");
        return -1;
    }

    p_rtx = &p_app->rtx;
    stru_msg_head *p_head = (stru_msg_head *)p_rtx->tx;
    p_head->interface = interface;
    p_head->len = tx_len;
    memcpy(p_head->data, p_tx, tx_len);

    if(NULL == (p_mq = app_get_msg_queue_ptr(ENUM_MQ_IEC_TO_COM)))
    {
        LOG_E("iec_data_tx app_get_msg_queue_ptr failed");
        return -1;
    }
    
    if(0 != task_msg_queue_send(p_mq->p_msg_queue, p_rtx->tx, p_mq->msg_size))
    {
        LOG_E("iec_data_tx task_msg_queue_send failed");
        return -1;
    }

    if(NULL == (p_app = app_get_ptr(ENUM_APP_COM_SCAN)) || 0 != task_event_send(p_app->p_event, EV_COM_RX_IEC))
    {
        LOG_E("iec_data_tx app_get_ptr or task_event_send failed");
        task_msg_queue_try_recv(p_mq->p_msg_queue, p_rtx->rx, p_mq->msg_size);
        return -1;
    }

    return 0;
}

void iec_data_rx(uint8_t *data)
{
    if(NULL == data)
    {
        LOG_E("iec_data_rx data null");
        return;
    }
    
    stru_msg_head *p_head = (stru_msg_head *)data;
    uint32_t interface = p_head->interface;
    uint16_t len = p_head->len;
    uint8_t *p_rx = p_head->data;

    if(p_rx[0] == 0x10 || p_rx[0] == 0x68)
    {
        iec60870_decode(p_rx, len, interface);
    }
}

void iec60870_task(uint16_t usGap)
{
    char temp_buf[20] = {0};

    for(uint8_t i = 0; i < MAX_IEC_NUM; i++)
    {
        if(1 == g_iec60870[i].is_busy)
        {
            g_iec60870[i].tm_out += usGap;
            if(g_iec60870[i].tm_out >= g_uilinkOverTime)
            {
                g_iec60870[i].is_busy = 0;
                g_iec60870[i].tm_out = 0;
                sprintf(temp_buf, "ch%x Link", g_iec60870[i].interface);
                memset(&g_iec60870[i], 0, sizeof(stru_iec_60870));
            }
            else
            {
                CS10x_TimerHandle(&g_iec60870[i].cs10x, usGap);
            }
        }

    }
}

int app_iec_init1(void *arg)
{
    stru_app *p_app = (stru_app *)arg;

    dc_signal_out("iec.run_cnt", "iec.run_cnt", DATA_TYPE_U32, &p_app->run_cnt);
    return 0;
}

int app_iec_init2(void *arg)
{

    return 0;
}

void *app_iec(void *arg)
{
    if(NULL == arg)
    {
        LOG_E("app_iec arg null");
        return NULL;
    }

    stru_app *p_app = (stru_app *)arg;

    uint32_t event;
    stru_app_msg_queue *p_mq = NULL;
    stru_msg_head *p_head = NULL;
    stru_rtx_data *p_rtx = &p_app->rtx;

    while(1)
    {
        task_event_recv(p_app->p_event, 
            EV_TIMER1 | EV_TIMER2 | EV_TIMER3 | EV_IEC_RX_COM, 
            TASK_EVENT_FLAG_OR | TASK_EVENT_FLAG_CLEAR, 
            TASK_EVENT_WAIT_FOREVER, 
            &event);

        if(event & EV_IEC_RX_COM && NULL != (p_mq = app_get_msg_queue_ptr(ENUM_MQ_COM_TO_IEC)))
        {
            while(1)
            {
                if(0 != task_msg_queue_try_recv(p_mq->p_msg_queue, p_rtx->rx, p_mq->msg_size))
                {
                    break;
                }

                iec_data_rx(p_rtx->rx);
            }
        }

        if(event & EV_TIMER1)
        {
            iec60870_task(10);
        }

        if(event & EV_TIMER2)
        {
            ;
        }

        if(event & EV_TIMER3)
        {
            p_app->run_cnt++;
            // LOG_I("iec run cnt %d", p_app->run_cnt);
        }
    }


    return NULL;
}




LOCAL void cmd_iec(int argc, char *argv[])
{
    for(int i = 0; i < argc; i++)
    {
        printf("%s ", argv[i]);
    }

    stru_app *p_app = app_get_ptr(ENUM_APP_IEC);
    if(NULL == p_app)
    {
        LOG_E("app_iec null");
        return;
    }

    if(argc > 2 && 0 == strcmp(argv[1], "run_cnt"))
    {
        if(0 == strcmp(argv[2], "get"))
        {
            printf("%d\n", p_app->run_cnt);
        }
        else if(0 == strcmp(argv[2], "reset"))
        {
            p_app->run_cnt = 0;
            LOG_I("iec run cnt reset, now %d", p_app->run_cnt);
        }
    }
}

CMD_REGISTER("iec", cmd_iec, "iec线程的控制命令");