/*******************************************************************************
* the includes
******************************************************************************/
#include "Uart2CanDiagApp.h"
#include <string.h>
#include <stdio.h>
#include "CanDrv.h"
/*******************************************************************************
* the defines
******************************************************************************/
#define TX_BUF_SIZE  2050
#define N_Bs 150
#define N_As 70
#define P2_SERVER 50
/*******************************************************************************
* the typedefs
******************************************************************************/
typedef enum
{
    U2CD_TASK_idle=0,
    U2CD_TASK_WaitFC,//流控
    U2CD_TASK_TxCF,
    U2CD_TASK_WaitResp,
    U2CD_TASK_NUM
}U2CD_TASK_STATE;

/*******************************************************************************
* the globals
******************************************************************************/
static uint16_t U2CD_pid;
static uint16_t U2CD_fid;
static uint16_t U2CD_rid;
static uint8_t U2CD_stmin;
static uint8_t U2CD_fill;
static uint8_t U2CD_cfgFlag;
static uint8_t U2CD_TTFlag;
static uint16_t U2CD_TTLen;
static uint8_t U2CD_Txbuf[TX_BUF_SIZE];
static uint16_t U2CD_TxCnt;//发送数据指针
static uint8_t U2CD_TxSN;
static uint8_t U2CD_TxTimeCounter;

static uint8_t U2CD_FCFlag = 0;
static uint8_t U2CD_Framebuf[8];
static U2CD_TASK_STATE task_state;
/*******************************************************************************
* the const
******************************************************************************/



/*******************************************************************************
* the functions
******************************************************************************/
static void U2CD_TxSF(uint16_t id,uint8_t* data,uint16_t len);
static void U2CD_TxFF(uint16_t id,uint8_t* data,uint16_t len);
static void U2CD_TxCF(uint16_t id,uint8_t* data,uint16_t len);

void U2CD_Init(void)
{
    U2CD_cfgFlag = 0;
    U2CD_TTFlag = 0;
    task_state = U2CD_TASK_idle;
}
//pid,fid,rid,stmin,fill
void U2CD_cfg(uint16_t pid,uint16_t fid,uint16_t rid,uint8_t stmin,uint8_t fill)
{
    if (pid<0x7ff&&fid<0x7ff&&rid<0x7ff)
    {
        U2CD_pid = pid;
        U2CD_fid = fid;
        U2CD_rid = rid;
        U2CD_stmin = stmin;
        U2CD_fill = fill;
        U2CD_cfgFlag = 1;
    }
    else
    {
        U2CD_cfgFlag = 0;
        printf("err:配置错误\n");
    }
    
}
void U2CD_TickTask(void)
{
    U2CD_TxTimeCounter++;
}
void U2CD_Task(void)
{
    switch (task_state)
    {
    case U2CD_TASK_idle:
        if (U2CD_TTFlag == 1)
        {
            if (U2CD_TTLen <= 7)
            {
                U2CD_TxSF(U2CD_pid,U2CD_Txbuf,U2CD_TTLen);
                task_state = U2CD_TASK_WaitResp;
                U2CD_TxTimeCounter = 0;
            }
            else
            {
                U2CD_TxFF(U2CD_pid,U2CD_Txbuf,U2CD_TTLen);
                task_state = U2CD_TASK_WaitFC;
                U2CD_TxTimeCounter = 0;
                U2CD_FCFlag = 0;
            }
            
        }
        
        break;
    case U2CD_TASK_WaitFC:
        if (U2CD_TxTimeCounter > N_Bs)
        {
            printf("err:N_Bs timeout\n");
            task_state = U2CD_TASK_idle;
        }
        if (U2CD_FCFlag == 1)
        {
            U2CD_TxTimeCounter = 0;
            task_state = U2CD_TASK_TxCF;
        }
        
        
        break;
    case U2CD_TASK_TxCF:
        
        if (U2CD_TxTimeCounter > U2CD_stmin)
        {
            if (CanDrv_GetCANTxEmpty() == 1)
            {
                U2CD_TxTimeCounter = 0;
                if (U2CD_TxCnt+6 < U2CD_TTLen)
                {
                    U2CD_TxCF(U2CD_pid,&U2CD_Txbuf[U2CD_TxCnt],6);
                    U2CD_TxCnt += 6;
                }
                else
                {
                    //最后一帧
                    U2CD_TxCF(U2CD_pid,&U2CD_Txbuf[U2CD_TxCnt],(U2CD_TTLen-U2CD_TxCnt));
                    task_state = U2CD_TASK_WaitResp;
                }
                
            }
            
        }
        if (U2CD_TxTimeCounter>N_As)
        {
            printf("err:N_As timeout\n");
            task_state = U2CD_TASK_idle;
        }
        break;
    case U2CD_TASK_WaitResp:
        if (U2CD_TxTimeCounter>P2_SERVER)
        {
            printf("err:P2_SERVER timeout\n");
            task_state = U2CD_TASK_idle;
        }
        break;
    default:
        break;
    }
}

void U2CD_TTreq(uint8_t* data,uint16_t len)
{
    if (len > TX_BUF_SIZE)
    {
        printf("err:len too long");
        return;
    }
    if (U2CD_cfgFlag == 0)
    {
        printf("err:no cfg");
        return;
    }
    if (task_state != U2CD_TASK_idle)
    {
        printf("err:busy");
        return;
    }
    
    
    memcpy(U2CD_Txbuf,data,len);
    U2CD_TTLen = len;
    U2CD_TTFlag = 1;
}

static void U2CD_TxSF(uint16_t id,uint8_t* data,uint16_t len)
{
    U2CD_Framebuf[0] = len;
    memcpy(&U2CD_Framebuf[1],data,len);
    if (len < 7)
    {
        for (uint8_t i = (len+1); i < 8; i++)
        {
            U2CD_Framebuf[i] = U2CD_fill;
        }
    }
    CanDrv_Txmsg(id,U2CD_Framebuf);
}

static void U2CD_TxFF(uint16_t id,uint8_t* data,uint16_t len)
{
    U2CD_Framebuf[0] = 0x10 + (len>>8);
    U2CD_Framebuf[1] = len&0xff;
    memcpy(&U2CD_Framebuf[2],data,6);
    CanDrv_Txmsg(id,U2CD_Framebuf);
    U2CD_TxCnt+=6;
    U2CD_TxSN = 1;
}

static void U2CD_TxCF(uint16_t id,uint8_t* data,uint16_t len)
{
    U2CD_Framebuf[0] = 0x20 + (U2CD_TxSN&0x0f);
    memcpy(&U2CD_Framebuf[1],data,len);
    if (len < 7)
    {
        for (uint8_t i = (len+1); i < 8; i++)
        {
            U2CD_Framebuf[i] = U2CD_fill;
        }
    }
    
    CanDrv_Txmsg(id,U2CD_Framebuf);
    U2CD_TxSN++;
}