#include "stdint.h"
#include "stddef.h"
#include "dbug.h"
#include "djyos.h"
#include <math.h>
#include "Iboot_info.h"
#include <uartctrl.h>
#include "string.h"
static int serial = -1; //串口句柄
bool_t RxEnabled = false;
char Buffer[600]={0};
char *RWstate = NULL;

bool_t COMWrite(char BMSBuffer[], int Lenght) //往串口输出数据
{
    if (BMSBuffer[0]!='~'||BMSBuffer[Lenght-1]!='\r'||BMSBuffer[0]==NULL)
    {
        return false;
    }

    int res;
    int left = (int)Lenght;
    int done = 0;
    u32 timeout = 3;

    while ((left > 0) && (timeout > 0))
    {
        if ((res = write(serial, BMSBuffer + done, left)) == -1)
        {
            timeout--;
            continue;
        }
        done += res;
        left -= res;
    }
    return left == 0 ? TRUE : FALSE;


}

bool_t COMRead(void) //通过串口读取数据
{
    bool_t bResult = FALSE;
    char BMSBuffer[600]={0};
    memset(BMSBuffer, 0, sizeof(BMSBuffer));
    int Read = 0, num = 0,con=0, res = 0,startaddressA=0,startaddressB=1,timeout=5,endaddres=0;
    char testBUFF[300]={0};
    char hex[20]={0};
    while (timeout)
    {
        startaddressA=0;
        if (Read>=600)
        {
            break;
        }
        res = read(serial, BMSBuffer + Read, sizeof(BMSBuffer)-Read);
        if (res == -1)
        {
            timeout--;
            bResult = FALSE; //数据接收出现故障
        }
        else if (res == 0)
        {
            timeout--;
            bResult = FALSE; //数据接收出现故障
        }
        else
        {
            Read = Read+(int)res;  
            for (int i = startaddressB; i < Read; i++)
            {
                if (BMSBuffer[i]=='\r')//找到尾
                {
                    endaddres=i;
                }
                if (BMSBuffer[i]=='~'&&i!=startaddressB)//找头
                {
                    startaddressA=i;
                    Read=Read-i;
                    memcpy(BMSBuffer,BMSBuffer+i,Read);
                }
                if (startaddressA!=0&&endaddres!=0)
                {
                    break;
                }
            }
            char ReadChksum[5]={0};//装校验数据
            if (BMSBuffer[endaddres]=='\r'&&BMSBuffer[startaddressA]=='~')//没找到尾就继续找
            {
                ReadChksum[0]=BMSBuffer[endaddres-4];
                ReadChksum[1]=BMSBuffer[endaddres-3];
                ReadChksum[2]=BMSBuffer[endaddres-2];
                ReadChksum[3]=BMSBuffer[endaddres-1];
                ReadChksum[4]='\0';
                if (startaddressA<endaddres)//防止头的位置在尾后面即错误数据
                {

                    int num=endaddres-4;//从7E到CHKSUM校验前一位
                    memcpy(testBUFF,BMSBuffer,num);
                    CHKSUM(testBUFF, hex, num);
                    if (hex[0]==ReadChksum[0]&&hex[1]==ReadChksum[1]&&hex[2]==ReadChksum[2]&&hex[3]==ReadChksum[3])
                    {
                        memcpy(Buffer,BMSBuffer,endaddres+1);
                        bResult=true;
                        break;
                    }
                }else{
                    startaddressB=startaddressA;
                    timeout--;
                }
            }
            timeout--;
        }
    }
    return bResult;
}


char *serial_transmission(char pucBuffer[], int num)//串行传输
{
    if (serial==-1)
    {
        bool_t bStatus = false;
        char ucPORT = '\003';
        char uart_name[20];
        snprintf((char *)uart_name, 16, "/dev/UART%d", ucPORT);

        if ((serial = open((char *)uart_name, O_RDWR | O_NOCTTY)) < 0) //串口是否正常打开判断
        {
            error_printf("YDS_1363", "open %s fail\r\n", uart_name);
            serial = -1;
            return bStatus;
        }
        Handle_SetTimeOut(fd2Handle(serial),1000*1000);
        struct COMParam com; //配置串口信息
        com.BaudRate = CN_UART_BAUD_9600;
        com.DataBits = CN_UART_DATABITS_8;
        com.StopBits = CN_UART_STOPBITS_1;
        com.Parity = CN_UART_PARITY_NONE;
        bool_t comstate=fcntl(serial, CN_UART_COM_SET, &com);
        if (comstate!=false)
        {
            fcntl(serial, CN_UART_COM_SET, &com);
        }

    }

    bool_t OutputResults = COMWrite(pucBuffer, num); //执行往串口输出数据

    if (OutputResults == true)                //串口输出成功
    {
        bool_t Readstate=COMRead();//监听获取数据
        if (Readstate== true)
        {
            return RWstate = "Success";
        }else
        {
            return RWstate = "TimeOut";
        }
    }


    return RWstate = "TimeOut";
}

bool_t BMSMasterGET(char *buff) //获取存储在缓冲区的报文
{
    char *state = "Success";
    int lenght;
    while (1)
    {
        if (strcmp(RWstate, state) == 0)
        {
            lenght = strlen(Buffer);

            for (int i = 0; i < lenght; i++)
            {
                buff[i] = Buffer[i];
            }
            RWstate = "wait";
            memset(Buffer, 0, sizeof(Buffer));
            return true;
        }
        else
        {
            return false;
        }
    }
}
void LENGTH(char *LENID, char hex[]) // LENGTH校验计算
{
    int num = 0;
    num = (int)strtol(LENID, NULL, 16); // LENID转成10进制
    int binary[12];                     //
    int part = num;
    memset(binary, 0, sizeof(binary));
    for (int i = 11; num > 0; i--)
    { //转成2进制
        binary[i] = num % 2;
        num = num / 2;
    }

    int result = ~part;     //取反
    result = result & 0x0F; //把取反的数据转成16进制
    //把取反的数据和转成2进制的数据拼成两个字节的数据
    int combined = (((result + 1) << 12) | (part & 0xFFFFF)) & 0xFFFF;

    sprintf(hex, "%X", combined);
}

void CHKSUM(char data[], char hex[], int count) // CHKSUM校验计算
{
    int num = 0;
    for (int i = 0; i < count; i++)
    {
        if (i==0&&data[i]=='~')
        {

        }
        else if (i==0&&data[i]=='7'&&data[i+1]=='E')
        {
            i++;
        }
        else{
            num = num + (int)data[i]; //除了报文头其他的加在一起
        }
    }
    int result = ~num;               //取反
    result = (result + 1) & 0x0FFFF; //把取反的数据转成16进制
    sprintf(hex, "%X", result);
}
// address是从机地址，CID2

char *BMSMasterRead(int address, char *CID2, char *LENID, char *DaRen[], char *COMMANDINFO[]) //拼写电总协议
{
    char data[50];
    char intermediary[2];
    char hex[20];
    int num = 0, res;
    char convert[2];
    char *state;
    char DRGKBUFF[100];
    memset(DRGKBUFF, 0, sizeof(DRGKBUFF));
    memset(data, '0', sizeof(data));
    if (address < 16) //地址小于0在之前加字符0
    {
        sprintf(intermediary, "%0*d", 2, address);
    }
    else
    {
        sprintf(intermediary, "%d", address);
    }
    strcpy(data, DaRen[0]);       // SOI
    strcat(data, DaRen[1]);       // VER
    strcat(data, intermediary);   // ADR
    strcat(data, DaRen[2]);       // CID1
    strcat(data, CID2);           // CID2
    if (strcmp(LENID, "00") == 0) // LENID
    {
        strcat(data, "00"); // LENGTH的1号字节
        strcat(data, "00"); // LENGTH的2号字节
    }
    else
    {
        LENGTH(LENID, hex); //计算LENGTH
        strcat(data, hex);  // LENGTH

        char *endptr;
        long int container;

        container = strtol(LENID, &endptr, 16);


        int lenght = (int)container;

        for (int i = 0; i < lenght / 2; i++)
        {
            strcat(data, COMMANDINFO[i]); // LENGTH
        }
    }
    num = strlen(data);
    CHKSUM(data, hex, num); // CHKSUM校验计算
    strcat(data, hex);      // CHKSUM
    strcat(data, DaRen[3]); // EOI
    num = 0;
    num = strlen(data);
    int count = 0;
    for (int i = 0; i < 100;) //把两个相邻的char字符通过偏移拼接成一个字符
    {
        int parameterA = 0;
        int parameterB = 0;
        int parameterC = 0;
        if (i > num - 3 || i < 1)
        {
            convert[0] = data[i];
            convert[1] = data[i + 1];
            i = i + 2;
        }
        else if (i > 1)
        {
            res = (int)data[i];
            sprintf(convert, "%X", res);
            i++;
        }
        for (int j = 0; j < 2; j++)
        {
            switch (convert[j])
            {
            case 'A':
                parameterC = 10;
                break;
            case 'B':
                parameterC = 11;
                break;
            case 'C':
                parameterC = 12;
                break;
            case 'D':
                parameterC = 13;
                break;
            case 'E':
                parameterC = 14;
                break;
            case 'F':
                parameterC = 15;
                break;
            }
            if (parameterC == 0)
            {
                parameterC = convert[j] - '0';
            }
            if (j == 0)
            {
                parameterA = parameterC;
            }
            else
            {
                parameterB = parameterC;
            }
            parameterC = 0;
        }
        DRGKBUFF[count] = parameterA << 4 | parameterB;
        count++;
        if (i == num)
        {
            break;
        }
    }
    num = 0;
    num = strlen(DRGKBUFF);
    state = serial_transmission(DRGKBUFF, num);
    return state;
}
