#include "GBT27930.h"


int can_GBT27930_read(GBT27930_t* dev, int timeout)
{
	can_j1939_t *can_J1939 = (can_j1939_t*)&dev->canJ1939;
    struct can_frame frame;
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for (; now_ms < end_ms; now_ms = systime_ms())
    {
        timeout = end_ms - now_ms;
        int ret = can_J1939_read(can_J1939, &frame, timeout);
        if (ret == sizeof(struct can_frame))
        {
            if (CAN_J939_DA(frame.can_id) == dev->SA && CAN_J939_SA(frame.can_id) == dev->DA)
            {
                switch(CAN_J939_PF(frame.can_id))
                {
                    case 0xEC:
                    {
                        uint32_t PGN = (frame.data[5]|(frame.data[6]<<8)|(frame.data[7]<<16));
                        switch(frame.data[0])
                        {
                            case 0x10: {// recv TPCM_RTS
                                uint16_t bytes = (frame.data[1]|(frame.data[2]<<8));
                                can_J1939_init_TPCM(can_J1939->rxtp, PGN, dev->DA, dev->SA, can_J1939->rxbuff, bytes);
                                can_J1939_send_TPCM_CTS(can_J1939, can_J1939->rxtp, 1);
                            }break;
                            case 0xFF: {// recv TPCM_ABORT
                                can_J1939->rxtp_quit = 2;
                                return -2;
                            }break;
                        }
                    } break;

                    case 0xEB:
                    {
                        uint8_t pkgsn = frame.data[0];
                        memcpy(&can_J1939->rxtp->buff[(pkgsn-1)*7], &frame.data[1], frame.can_dlc-1);
                        if (pkgsn == can_J1939->rxtp->rpkgs)
                        {
                            can_J1939_send_TPCM_EOMACK(can_J1939, can_J1939->rxtp);
                            can_J1939->rxtp_quit = 1;
                            switch(SAE_J1939_PF(can_J1939->rxtp->PGN))
                            {
                                case GBT_27930_2015_BRM: {
                                    uint8_t* buff = dev->canJ1939.rxbuff;
                                    dev->brm.bmsRatedPowerAH = (buff[5]<<8)|buff[4];
                                    dev->brm.bmsRatedVoltage = (buff[7]<<8)|buff[6];
                                    if (dev->canJ1939.rxtp->bytes > 41)
                                    {
                                        memcpy(dev->brm.bmsVIN, &buff[24], 17);
                                        dev->brm.bmsVIN[17] = '\0';
                                    }else{
                                        memset(dev->brm.bmsVIN, 0x00, 18);
                                    }
                                    // printd("rxtp.PGN:%08x, lenth:%d\n", can_J1939->rxtp->PGN, can_J1939->rxtp->bytes);
                                    return GBT_27930_2015_BRM;
                                } break;
                                case GBT_27930_2015_BCP: {
                                    uint8_t* buff = dev->canJ1939.rxbuff;
                                    dev->bcp.bmsMaxUnitVoltage_charging    = (buff[1]<<8)|buff[0];
                                    dev->bcp.bmsPermitttedMaxCurrent        = GBT_27930_CURRENT_OFFSET - ((buff[3]<<8)|buff[2]);
                                    dev->bcp.bmsNominalTotalkWH            = (buff[5]<<8)|buff[4];
                                    dev->bcp.bmsPermitttedMaxVoltage        = (buff[7]<<8)|buff[6];
                                    dev->bcp.bmsPermitttedMaxTemp           = buff[8];
                                    dev->bcp.bmsRatio                      = (buff[10]<<8)|buff[9];
                                    dev->bcp.bmsVoltage                    = (buff[12]<<8)|buff[11];
                                    return GBT_27930_2015_BCP;
                                } break;
                                case GBT_27930_2015_BMV: {
                                    memcpy(dev->bmv.bmsUnitVoltage, dev->canJ1939.rxbuff, 511*2);
                                    return GBT_27930_2015_BMV;
                                } break;
                                case GBT_27930_2015_BMT: {
                                    memcpy(dev->bmt.bmsUnitTemp, dev->canJ1939.rxbuff, 128);
                                    return GBT_27930_2015_BMT;
                                } break;
                                case GBT_27930_2015_BSP: {
                                    memcpy(dev->bsp.bmsUnitResv, dev->canJ1939.rxbuff, 32);
                                    return GBT_27930_2015_BSP;
                                } break;
                                case GBT_27930_2015_BCS: { 
                                    uint8_t* buff = dev->canJ1939.rxbuff;
                                    dev->bcs.chargingVoltage = buff[0]|(buff[1]<<8); 
                                    dev->bcs.chargingCurrent = GBT_27930_CURRENT_OFFSET -(buff[2]|(buff[3]<<8));  
                                    dev->bcs.bmsUnitMaxVoltage = buff[4]|(buff[5]<<8); 
                                    dev->bcs.bmsSOC = buff[6];
                                    dev->bcs.bmsChargingNeedMinutes = buff[7]|(buff[8]<<8); 
                                    return GBT_27930_2015_BCS;
                                } break;
                            }
                        }
                    } break;
                    /**************************************************************************************/
                    case GBT_27930_2015_BHM: { 
                        dev->bhm.bmsMaxVoltage = frame.data[0]|(frame.data[1]<<8); 
                        return GBT_27930_2015_BHM; 
                    } break;
                    case GBT_27930_2015_BRO: { 
                        dev->bro_last.status = dev->bro.status;
                        dev->bro.status = frame.data[0]; 
                        return GBT_27930_2015_BRO; 
                    } break;
                    case GBT_27930_2015_BCL: { 
                        memcpy(&dev->bcl_last, &dev->bcl, sizeof(dev->bcl));
                        dev->bcl.bmsVoltage_request = frame.data[0]|(frame.data[1]<<8); 
                        dev->bcl.bmsCurrent_request = GBT_27930_CURRENT_OFFSET - (frame.data[2]|(frame.data[3]<<8)); 
                        dev->bcl.bmsChargeMode = frame.data[4];
                        return GBT_27930_2015_BCL;
                    }break;
                    case GBT_27930_2015_BSM: { 
                        memcpy(&dev->bsm_last, &dev->bsm, 8);
                        memcpy(&dev->bsm, frame.data, 8);
                        return GBT_27930_2015_BSM;
                    }break;
                    case GBT_27930_2015_BST: { 
                        memcpy(&dev->bst, frame.data, 4);
                        return GBT_27930_2015_BST;
                    }break;
                    case GBT_27930_2015_BSD: { 
                        dev->bsd.bmsSOC_EOF = frame.data[0];
                        dev->bsd.bmsUnitMaxVoltage = frame.data[1]|(frame.data[2]<<8);
                        dev->bsd.bmsUnitMinVoltage = frame.data[3]|(frame.data[4]<<8);
                        dev->bsd.bmsMaxUnitTemp = frame.data[5];
                        dev->bsd.bmsMinUnitTemp = frame.data[6];
                        return GBT_27930_2015_BSD;
                    }break;
                    case GBT_27930_2015_BEM: { 
                        memcpy(&dev->bem, frame.data, 4);
                        return GBT_27930_2015_BEM;
                    }break;
                }
            }
        }
    }
    return 0;
}

int can_GBT27930_wait(GBT27930_t* dev, int waitPF, int timeout)
{
    secc_port_t* secc = (secc_port_t*)dev->secc;
    printd("dev->fd[0]:%d\n", dev->fd[0]);
    if (dev->fd[0] < 0 ) return GBT_27930_2015_ERROR;
    int PF; 
    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(dev->fd[0], &readfds);
    struct timeval tv;
    tv.tv_sec = timeout/1000;
    tv.tv_usec = (timeout%1000)*1000;
    int rv = select(dev->fd[0]+1, &readfds, NULL, NULL, &tv);
    if (rv > 0)
    {
        if(FD_ISSET(dev->fd[0], &readfds))
        {
            int ret = recv(dev->fd[0], &PF, sizeof(PF), 0);
            if (ret == sizeof(PF))
            {
                return PF;
            }
        }
    }
    printd("step, rv:%d\n", rv);
    return GBT_27930_2015_ERROR;
}

static void* can_GBT27930_Txloop(void* args)
{
    GBT27930_t* dev = (GBT27930_t*)args;
	can_j1939_t* canJ1939 = (can_j1939_t*)&dev->canJ1939;
	struct can_frame *frame = (struct can_frame *)&dev->frame;
	while(dev->quitTx == 0)
	{
        if (dev->stop == 0)
        {
            pthread_mutex_lock(&dev->mutex);
            can_J1939_send(canJ1939, frame);
            if (CAN_J939_PF(frame->can_id) == GBT_27930_2015_CML)
            {
                time_t now = time(NULL);
                struct tm *ptm = localtime(&now);
                struct can_frame *frameCTS = (struct can_frame *)&dev->frameCTS;
                memset(frameCTS, 0, sizeof(struct can_frame));
                frameCTS->can_id = CAN_EFF_FLAG|(6<<26)|(GBT_27930_2015_CTS<<16)|(dev->DA<<8)|dev->SA;
                frameCTS->data[0] = DEC2BCD(ptm->tm_sec);
                frameCTS->data[1] = DEC2BCD(ptm->tm_min);
                frameCTS->data[2] = DEC2BCD(ptm->tm_hour);
                frameCTS->data[3] = DEC2BCD(ptm->tm_mday);
                frameCTS->data[4] = DEC2BCD(ptm->tm_mon);
                frameCTS->data[5] = DEC2BCD(ptm->tm_year);
                frameCTS->data[6] = 0x20;
                frameCTS->can_dlc = 7;
                can_J1939_send(canJ1939, frameCTS);
            }
            if (CAN_J939_PF(frame->can_id) == GBT_27930_2015_CRO && dev->cro.status == 0xAA)
            {
                can_J1939_send(canJ1939, &dev->frameCCS);
            }
            pthread_mutex_unlock(&dev->mutex);
        }
        msleep(dev->frame_interval_ms);
	}
    printd(".quitTx = 1\n");
    pthread_exit(NULL);
	return NULL;
}

static void* can_GBT27930_Rxloop(void* args)
{
    GBT27930_t* dev = (GBT27930_t*)args;
    secc_port_t *secc = (secc_port_t*)dev->secc;
	can_j1939_t* canJ1939 = (can_j1939_t*)&dev->canJ1939;
	while(dev->quitRx == 0)
	{
		int PF = can_GBT27930_read(dev, 250);
        if (PF == GBT_27930_2015_BHM && dev->lastPF != GBT_27930_2015_BHM)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BRM && dev->lastPF != GBT_27930_2015_BRM)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BCP && dev->lastPF != GBT_27930_2015_BCP)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BRO && dev->lastPF != GBT_27930_2015_BRO)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BRO )
        {
            if (dev->bro.status == 0xAA && dev->bro_last.status != 0xAA)
            {
                send(dev->fd[1], &PF, sizeof(PF), 0);
            }
        }

        if (PF == GBT_27930_2015_BCL)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BCS)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BSM)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BMV && dev->lastPF != GBT_27930_2015_BMV)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BMT && dev->lastPF != GBT_27930_2015_BMT)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BSP && dev->lastPF != GBT_27930_2015_BSP)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BST && dev->lastPF != GBT_27930_2015_BST)
        {
            secc_set_state(secc, GUN_STOPPING);
            can_GBT27930_show_BST(dev);
        }

        if (PF == GBT_27930_2015_BSD && dev->lastPF != GBT_27930_2015_BSD)
        {
            send(dev->fd[1], &PF, sizeof(PF), 0);
        }

        if (PF == GBT_27930_2015_BEM && dev->lastPF != GBT_27930_2015_BEM)
        {
            secc_set_error(secc, CAN_BEM_TIMEOUT);
            can_GBT27930_show_BEM(dev);
        }

        dev->lastPF = PF;
	}
    printd(".quitRx = 1\n");
    pthread_exit(NULL);
	return NULL;
}

void can_GBT27930_close_pipe(GBT27930_t* dev)
{
    printd("step\n");
    if (dev->quitRx == 0)
    {
        dev->quitRx = 1;
        mthread_exit(&dev->threadRx);
    }

    printd("step\n");
    if (dev->quitTx == 0)
    {
        dev->quitTx = 1;
        mthread_exit(&dev->threadTx); 
    }
    printd("step\n");
    if (dev->fd[0] > 0)
    {
        shutdown(dev->fd[0], SHUT_RDWR);
        close(dev->fd[0]);
        dev->fd[0] = -1;
    }
    if (dev->fd[1] > 0)
    {
        shutdown(dev->fd[1], SHUT_RDWR);
        close(dev->fd[1]);
        dev->fd[1] = -1;
    }
    can_J1939_exit(&dev->canJ1939);
}

void can_GBT27930_open_pipe(GBT27930_t* dev)
{
    socketpair(AF_UNIX, SOCK_STREAM, 0, dev->fd);
    can_J1939_init(&dev->canJ1939, dev->can_name, 250000);
    if (dev->quitRx == 1)
    {
        dev->quitRx = 0;
        mthread_init(&dev->threadRx, can_GBT27930_Rxloop, dev);
    }
    if (dev->quitTx == 1)
    {
        dev->quitTx = 0;
        mthread_init(&dev->threadTx, can_GBT27930_Txloop, dev);
    }
}

int can_GBT27930_init(GBT27930_t* dev, const char *can_name)
{
    if (dev)
    {
        printd("step\n");
        secc_port_t* secc = (secc_port_t*)dev->secc;
        dev->fd[0] = -1;
        dev->fd[1] = -1;
        dev->SA = GBT_27930_2015_CHG;
        dev->DA = GBT_27930_2015_BMS;
        dev->quit = 0;
        dev->quitRx = 1;
        dev->quitTx = 1;
        dev->stop = 1;
        dev->bsm.bmsPowerPermitted = 1;
        dev->bsm_last.bmsPowerPermitted = 1;
        dev->cro.status = 0x00;
        dev->can_name = can_name;
        dev->frame_interval_ms = 250;
        printd("CAN(%s).connectorId[%d]...\n", dev->can_name, secc->config->connectorId);
        pthread_mutex_init(&dev->mutex, NULL);
        printd("step\n");
        mthread_init(&dev->thread, can_GBT27930_loop, dev);
    }
    return 0;
}

void can_GBT27930_exit(GBT27930_t* dev)
{
    if (dev)
    {
        printd("step\n");
        secc_port_t* secc = (secc_port_t*)dev->secc;
        if (dev->quit == 0)
        {
            printd("Exit.SECC.connectorId[%d]...\n", secc->config->connectorId);
            dev->quit = 1;
            mthread_exit(&dev->thread);
            pthread_mutex_destroy(&dev->mutex);
            can_GBT27930_close_pipe(dev);
            printd("Exit done.\n");
        }
        dev->quit = 1;
        dev->stop = 1;
    }
}


/*
*******************************************************************************
10.5.2 PGN7936 充电机错误报文(CEM)
报文功能: 当充电机检测到错误时, 发送给 BMS 充电错误报文, 直到充电机接收到 BMS 发送的
BRM 报文或拔掉充电插头为止。 PGN7936 报文格式见表29。
*******************************************************************************
*/
int can_GBT27930_send_CEM(GBT27930_t* dev, GBT27930_CEM_t *req)
{
    if (dev)
    {
        uint32_t Priority = 0x2;
        struct can_frame txframe;
        memset(&txframe, 0, sizeof(struct can_frame));
        uint32_t *errn = (uint32_t*)req;
        txframe.can_id = (Priority<<26)|(GBT_27930_2015_CEM<<16)|(dev->DA<<8)|dev->SA;
        txframe.can_id |= CAN_EFF_FLAG;
        txframe.data[0] = (errn[0]>>0)&0xFF;
        txframe.data[1] = (errn[0]>>8)&0xFF;
        txframe.data[2] = (errn[0]>>16)&0xFF;
        txframe.data[3] = (errn[0]>>24)&0xFF;
        txframe.can_dlc = 4;
        dev->stop = 0;

        pthread_mutex_lock(&dev->mutex);
        memcpy(&dev->frame, &txframe, sizeof(struct can_frame));
        pthread_mutex_unlock(&dev->mutex);
        return GBT_27930_2015_NORMAL;

        if (can_J1939_send(&dev->canJ1939, &txframe)==sizeof(struct can_frame))
        {
            return GBT_27930_2015_NORMAL;
        }
    }
    return GBT_27930_2015_ERROR;
}

/*
*******************************************************************************
10.1 .1 PGN9728 充电机握手报文(CHM)
报文功能: 当充电机和电动汽车物理连接并完成上电, 且电压检测正常后, 由充电机向 BMS 每隔
250 ms 发送一次充电机握手报文, 用于确定双方是否握手正常。 PGN9728 报文格式见表8。
*******************************************************************************
*/
int can_GBT27930_send_CHM(GBT27930_t* dev)
{
    if (dev)
    {
        uint32_t Priority = 0x6;
        struct can_frame txframe;
        memset(&txframe, 0, sizeof(struct can_frame));
        txframe.can_id = (Priority<<26)|(GBT_27930_2015_CHM<<16)|(dev->DA<<8)|dev->SA;
        txframe.can_id |= CAN_EFF_FLAG;
        txframe.data[0] = (GTB_27930_2015_VER>>0)&0xFF;
        txframe.data[1] = (GTB_27930_2015_VER>>8)&0xFF;
        txframe.data[2] = (GTB_27930_2015_VER>>16)&0xFF;
        txframe.can_dlc = 3;
        dev->stop = 0;

        pthread_mutex_lock(&dev->mutex);
        memcpy(&dev->frame, &txframe, sizeof(struct can_frame));
        printTxCanFrame(dev->can_name, &dev->frame);
        pthread_mutex_unlock(&dev->mutex);
        return GBT_27930_2015_NORMAL;

        if (can_J1939_send(&dev->canJ1939, &txframe)==sizeof(struct can_frame))
        {
            return GBT_27930_2015_NORMAL;
        }
    }
    return GBT_27930_2015_ERROR;
}

/*
*******************************************************************************
10.1 .2 PGN9984 BMS 握手报文(BHM)
报文功能: 当 BMS 收到 PGN9728 充电机握手报文后, 向充电机每隔250 ms 返回 BMS 握手报文,
提供 BMS 最高允许充电总电压。 PGN9984 报文格式见表9。
*******************************************************************************
*/
int can_GBT27930_wait_BHM(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BHM)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.1 .3 PGN256 充电机辨识报文(CRM)
报文功能: 当充电机通过握手确认, 并确定绝缘检测正常后, 向 BMS 每隔250 ms 发送一次充电机
辨识报文, 用于确认充电机和 BMS 之间通信链路正确。 在收到 BMS 辨识报文前, 确认码=0x00; 在收
到 BMS 辨识报文后, 确认码=0xAA。 PGN256 报文格式见表10。
*******************************************************************************
*/
int can_GBT27930_send_CRM(GBT27930_t* dev, uint8_t status, uint32_t CHG_No, uint8_t *ZoneCode)
{
    if (dev)
    {
        struct can_frame txframe;
        uint32_t Priority = 0x6;
        memset(&txframe, 0, sizeof(struct can_frame));
        txframe.can_id = (Priority<<26)|(GBT_27930_2015_CRM<<16)|(dev->DA<<8)|dev->SA;
        txframe.can_id |= CAN_EFF_FLAG;
        txframe.data[0] = status;
        txframe.data[1] = (CHG_No>>0)&0xFF;
        txframe.data[2] = (CHG_No>>8)&0xFF;
        txframe.data[3] = (CHG_No>>16)&0xFF;
        txframe.data[4] = (CHG_No>>24)&0xFF;
        // txframe.can_dlc = 5;
        // txframe.data[5] = '0';
        // txframe.data[6] = '8';
        // txframe.data[7] = '6';
        txframe.can_dlc = 8;
        dev->stop = 0;

        pthread_mutex_lock(&dev->mutex);
        memcpy(&dev->frame, &txframe, sizeof(struct can_frame));
        pthread_mutex_unlock(&dev->mutex);
        return GBT_27930_2015_NORMAL;

        if (can_J1939_send(&dev->canJ1939, &txframe)==sizeof(struct can_frame))
        {
            return GBT_27930_2015_NORMAL;
        }
    }
    return GBT_27930_2015_ERROR;
}

/*
*******************************************************************************
10.1 .4 PGN512 BMS 和车辆辨识报文(BRM)
报文功能: 充电握手阶段向充电机提供BMS 和车辆辨识信息。 当BMS 收到SPN2560=0x00 的充
电机辨识报文后向充电机每隔250 ms 发送一次, 数据域长度超出8 字节时, 需使用传输协议功能传输,
格式详见6.5 的规定, 帧与帧间发送间隔为10 ms, 直到在5 s 内收到 SPN2560=0xAA 的充电机辨识
报文为止。 PGN512 报文格式见表11。
*******************************************************************************
*/
int can_GTB27930_wait_BRM(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BRM)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.2.1 PGN1536 动力蓄电池充电参数报文(BCP)
报文功能: 充电参数配置阶段 BMS 发送给充电机的动力蓄电池充电参数。 如果充电机在5 s 内没
有收到该报文, 即为超时错误, 充电机应立即结束充电。 PGN1536 报文格式见表12。
*******************************************************************************
*/
int can_GBT27930_wait_BCP(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BCP)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.2.2 PGN1792 充电机发送时间同步信息报文(CTS)
报文功能: 充电参数配置阶段充电机发送给 BMS 的时间同步信息。 PGN1792 报文格式见表13。
*******************************************************************************
*/
int can_GBT27930_send_CTS(GBT27930_t* dev, struct tm *ptm)
{
    if (dev)
    {
        struct can_frame txframe;
        uint32_t Priority = 0x6;

        if (ptm == NULL)
        {
            time_t now = time(NULL);
            ptm = localtime(&now);
        }
        
        memset(&txframe, 0, sizeof(struct can_frame));
        txframe.can_id = (Priority<<26)|(GBT_27930_2015_CTS<<16)|(dev->DA<<8)|dev->SA;
        txframe.can_id |= CAN_EFF_FLAG;
        txframe.data[0] = DEC2BCD(ptm->tm_sec);
        txframe.data[1] = DEC2BCD(ptm->tm_min);
        txframe.data[2] = DEC2BCD(ptm->tm_hour);
        txframe.data[3] = DEC2BCD(ptm->tm_mday);
        txframe.data[4] = DEC2BCD(ptm->tm_mon);
        txframe.data[5] = DEC2BCD(ptm->tm_year);
        txframe.data[6] = 0x20;
        txframe.can_dlc = 7;
        dev->stop = 0;

        pthread_mutex_lock(&dev->mutex);
        memcpy(&dev->frameCTS, &txframe, sizeof(struct can_frame));
        pthread_mutex_unlock(&dev->mutex);
        return GBT_27930_2015_NORMAL;

        if (can_J1939_send(&dev->canJ1939, &txframe) == sizeof(struct can_frame))
        {
            return GBT_27930_2015_NORMAL;
        }
    }
    return GBT_27930_2015_ERROR;
}

/*
*******************************************************************************
10.2.3 PGN2048 充电机最大输出能力报文(CML)
报文功能: 充电机发送给 BMS 充电机最大输出能力, 以便估算剩余充电时间。 PGN2048 报文格式
见表14。
*******************************************************************************
*/
int can_GBT27930_send_CML(GBT27930_t* dev, GBT27930_CML_t* info)
{
    if (dev)
    {
        struct can_frame txframe;
        uint32_t Priority = 0x6;

        uint16_t chgMaxOutputCurrent = GBT_27930_CURRENT_OFFSET - info->chgMaxOutputCurrent;
        uint16_t chgMinOutputCurrent = GBT_27930_CURRENT_OFFSET - info->chgMinOutputCurrent;
        
        memset(&txframe, 0, sizeof(struct can_frame));
        txframe.can_id = (Priority<<26)|(GBT_27930_2015_CML<<16)|(dev->DA<<8)|dev->SA;
        txframe.can_id |= CAN_EFF_FLAG;
        txframe.data[0] = (info->chgMaxOutputVoltage>>0)&0xFF;
        txframe.data[1] = (info->chgMaxOutputVoltage>>8)&0xFF;
        txframe.data[2] = (info->chgMinOutputVoltage>>0)&0xFF;
        txframe.data[3] = (info->chgMinOutputVoltage>>8)&0xFF;
        txframe.data[4] = (chgMaxOutputCurrent>>0)&0xFF;
        txframe.data[5] = (chgMaxOutputCurrent>>8)&0xFF;
        txframe.data[6] = (chgMinOutputCurrent>>0)&0xFF;
        txframe.data[7] = (chgMinOutputCurrent>>8)&0xFF;
        txframe.can_dlc = 8;
        dev->stop = 0;

        pthread_mutex_lock(&dev->mutex);
        memcpy(&dev->frame, &txframe, sizeof(struct can_frame));
        pthread_mutex_unlock(&dev->mutex);
        return GBT_27930_2015_NORMAL;

        if (can_J1939_send(&dev->canJ1939, &txframe) == sizeof(struct can_frame))
        {
            return GBT_27930_2015_NORMAL;
        }
    }
    return GBT_27930_2015_ERROR;
}

/*
*******************************************************************************
10.2.4 PGN2304 BMS 充电准备就绪报文(BRO)
报文功能:BMS 发送给充电机电池充电准备就绪报文, 让充电机确认 BMS 已经准备充电。 BMS
在60 s 内未准备好, 则充电机进行等待; 否则, 参见 C.1 进行处理。 PGN2304 报文格式见表15。
*******************************************************************************
*/
int can_GBT27930_wait_BRO(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BRO)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.2.5 PGN2560 充电机输出准备就绪报文(CRO)
报文功能: 充电机发送给 BMS 充电机输出准备就绪报文, 让 BMS 确认充电机已经准备输出。 充
电机在60 s 内未准备好, 则 BMS 进行等待; 否则, 参见附录 C.1 进行处理。 PGN2560 报文格式见
表16。
*******************************************************************************
*/
int can_GBT27930_send_CRO(GBT27930_t* dev, uint8_t status)
{
    if (dev)
    {
        struct can_frame txframe;
        uint32_t Priority = 0x4;
        
        memset(&txframe, 0, sizeof(struct can_frame));
        txframe.can_id = (Priority<<26)|(GBT_27930_2015_CRO<<16)|(dev->DA<<8)|dev->SA;
        txframe.can_id |= CAN_EFF_FLAG;
        txframe.data[0] = status;
        txframe.can_dlc = 1;
        dev->stop = 0;
        dev->cro.status = status;
        if (status == 0xAA)
        {
            uint32_t Priority = 0x6;
            GBT27930_CCS_t* ccs = (GBT27930_CCS_t*)&dev->ccs;
            uint16_t chgOutputCurrent = GBT_27930_CURRENT_OFFSET - ccs->chgOutputCurrent;
            struct can_frame ccsframe;
            memset(&ccsframe, 0, sizeof(struct can_frame));
            ccsframe.can_id = (Priority<<26)|(GBT_27930_2015_CCS<<16)|(dev->DA<<8)|dev->SA;
            ccsframe.can_id |= CAN_EFF_FLAG;
            ccsframe.data[0] = (ccs->chgOutputVoltage>>0)&0xFF;
            ccsframe.data[1] = (ccs->chgOutputVoltage>>8)&0xFF;
            ccsframe.data[2] = (chgOutputCurrent>>0)&0xFF;
            ccsframe.data[3] = (chgOutputCurrent>>8)&0xFF;
            ccsframe.data[4] = (ccs->chgChargedMinutes>>0)&0xFF;
            ccsframe.data[5] = (ccs->chgChargedMinutes>>8)&0xFF;
            ccsframe.data[6] = (ccs->chgOutputting>>0)&0xFF;
            ccsframe.data[7] = 0x00;
            ccsframe.can_dlc = 8;
            memcpy(&dev->frameCCS, &ccsframe, sizeof(struct can_frame));
        }

        pthread_mutex_lock(&dev->mutex);
        memcpy(&dev->frame, &txframe, sizeof(struct can_frame));
        pthread_mutex_unlock(&dev->mutex);
        return GBT_27930_2015_NORMAL;

        if (can_J1939_send(&dev->canJ1939, &txframe)==sizeof(struct can_frame))
        {
            return GBT_27930_2015_NORMAL;
        }
    }
    return GBT_27930_2015_ERROR;
}

/*
*******************************************************************************
10.3.1 PGN4096 电池充电需求报文(BCL)
报文功能: 让充电机根据电池充电需求来调整充电电压和充电电流, 确保充电过程正常进行。 如果
充电机在1 s 内没有收到该报文, 即为超时错误, 充电机应立即结束充电。
在恒压充电模式下, 充电机的输出的电压应满足电压需求值, 输出的电流不能超过电流需求值; 在
恒流充电模式下, 充电机输出的电流应满足电流需求值, 输出的电压不能超过电压需求值。 当 BCL 报
文中充电电流请求大于 CML 报文中最大输出电流时, 充电机按最大输出能力输出; 当 BCL 报文中充
电电流请求小于等于 CML 报文中最大输出电流时, 充电机按请求电流输出; 当电压需求或电流需求为
0 时, 充电机按最小输出能力输出。 PGN4096 报文格式见表17。
*******************************************************************************
*/
int can_GBT27930_wait_BCL(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BCL)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.3.2 PGN4352 电池充电总状态报文(BCS)
报文功能: 让充电机监视充电过程中电池组充电电压、 充电电流等充电状态。 如果充电机在5 s 内
没有收到该报文, 即为超时错误, 充电机应立即结束充电。 PGN4352 报文格式见表18。
*******************************************************************************
*/
int can_GBT27930_wait_BCS(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BCS)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.3.3 PGN4608 充电机充电状态报文(CCS)
报文功能: 让 BMS 监视充电机当前输出的充电电流、 电压值等信息。 如果 BMS 在1 s 内没有收到
该报文, 即为超时错误,BMS 应立即结束充电。 PGN4608 报文格式见表19。
*******************************************************************************
*/
int can_GBT27930_send_CCS(GBT27930_t* dev, GBT27930_CCS_t* req)
{
    if (dev)
    {
        struct can_frame txframe;
        uint32_t Priority = 0x6;

        uint16_t chgOutputCurrent = GBT_27930_CURRENT_OFFSET - req->chgOutputCurrent;
        
        memset(&txframe, 0, sizeof(struct can_frame));
        txframe.can_id = (Priority<<26)|(GBT_27930_2015_CCS<<16)|(dev->DA<<8)|dev->SA;
        txframe.can_id |= CAN_EFF_FLAG;
        txframe.data[0] = (req->chgOutputVoltage>>0)&0xFF;
        txframe.data[1] = (req->chgOutputVoltage>>8)&0xFF;
        txframe.data[2] = (chgOutputCurrent>>0)&0xFF;
        txframe.data[3] = (chgOutputCurrent>>8)&0xFF;
        txframe.data[4] = (req->chgChargedMinutes>>0)&0xFF;
        txframe.data[5] = (req->chgChargedMinutes>>8)&0xFF;
        txframe.data[6] = (req->chgOutputting>>0)&0xFF;
        txframe.data[7] = 0x00;
        txframe.can_dlc = 8;
        dev->stop = 0;
		
        pthread_mutex_lock(&dev->mutex);
        memcpy(&dev->frame, &txframe, sizeof(struct can_frame));
        // memcpy(&dev->frameCCS, &txframe, sizeof(struct can_frame));
        pthread_mutex_unlock(&dev->mutex);
        return GBT_27930_2015_NORMAL;

        if (can_J1939_send(&dev->canJ1939, &txframe)==sizeof(struct can_frame))
        {
            return GBT_27930_2015_NORMAL;
        }
    }
    return GBT_27930_2015_ERROR;
}

/*
*******************************************************************************
10.3.4 PGN4864 BMS 发送动力蓄电池状态信息报文(BSM)
报文功能: 充电阶段 BMS 发送给充电机的动力蓄电池状态信息。 PGN4864 报文格式见表20。
*******************************************************************************
*/
int can_GBT27930_wait_BSM(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BSM)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.3.5 PGN5376 单体动力蓄电池电压报文(BMV)
报文功能: 各个单体动力蓄电池电压值。 由于 PGN5376 的数据域的最大长度超出8 字节, 需使用
传输协议功能传输, 详见6.5 的规定。 PGN5376 报文格式见表21。
*******************************************************************************
*/
int can_GBT27930_wait_BMV(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BMV)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.3.6 PGN5632 动力蓄电池温度报文(BMT)
报文功能: 动力蓄电池温度。 数据长度超出8 字节时, 需使用传输协议功能传输, 格式详见6.5 的
规定。 PGN5632 报文格式见表22。
*******************************************************************************
*/
int can_GBT27930_wait_BMT(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BMT)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.3.7 PGN5888 动力蓄电池预留报文(BSP)
报文功能: 动力蓄电池预留报文。 数据域长度超出8 字节时, 需使用传输协议功能传输, 格式详见
6.5 的规定。 PGN5888 报文格式见表23。
*******************************************************************************
*/
int can_GBT27930_wait_BSP(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BSP)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.3.8 PGN6400 BMS 中止充电报文(BST)
报文功能: 让充电机确认 BMS 将发送中止充电报文以令充电机结束充电过程以及结束充电原因。
PGN6400 报文格式见表24。
*******************************************************************************
*/
int can_GBT27930_wait_BST(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BST)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}
/*
*******************************************************************************
10.3.9 PGN6656 充电机中止充电报文(CST)
报文功能: 让 BMS 确认充电机即将结束充电以及结束充电原因。 PGN6656 报文格式见表25。
*******************************************************************************
*/
int can_GBT27930_send_CST(GBT27930_t* dev, GBT27930_CST_t* req)
{
    if (dev)
    {
        struct can_frame txframe;
        uint32_t Priority = 0x4;
        
        memset(&txframe, 0, sizeof(struct can_frame));
        txframe.can_id = (Priority<<26)|(GBT_27930_2015_CST<<16)|(dev->DA<<8)|dev->SA;
        txframe.can_id |= CAN_EFF_FLAG;
        memcpy(txframe.data, req, 4);
        txframe.can_dlc = 4;
        dev->stop = 0;
		
        pthread_mutex_lock(&dev->mutex);
        memcpy(&dev->frame, &txframe, sizeof(struct can_frame));
        pthread_mutex_unlock(&dev->mutex);
        return GBT_27930_2015_NORMAL;

        if (can_J1939_send(&dev->canJ1939, &txframe)==sizeof(struct can_frame))
        {
            return GBT_27930_2015_NORMAL;
        }
    }
    return GBT_27930_2015_ERROR;
}
/*
*******************************************************************************
10.4.1 PGN7168 BMS 统计数据报文(BSD)
报文功能: 让充电机确认 BMS 对于本次充电过程的充电统计数据。 PGN7168 报文格式见表26。
*******************************************************************************
*/
int can_GBT27930_wait_BSD(GBT27930_t* dev, int timeout)
{
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + timeout;
    for(; now_ms < end_ms; now_ms = systime_ms())
    {
        int ret = can_GBT27930_read(dev, timeout);
        if (ret == GBT_27930_2015_BSD)
        {
            return GBT_27930_2015_NORMAL;
        }
        if (ret == GBT_27930_2015_BEM)
        {
            return GBT_27930_2015_ERROR;
        }
    }
    return GBT_27930_2015_TIMEOUT;
}

/*
*******************************************************************************
10.4.2 PGN7424 充电机统计数据报文(CSD)
报文功能: 确认充电机本次充电过程的充电统计数据。 PGN7424 报文格式见表27。
*******************************************************************************
*/
int can_GBT27930_send_CSD(GBT27930_t* dev, GBT27930_CSD_t* req)
{
    if (dev)
    {
        struct can_frame txframe;
        uint32_t Priority = 0x6;
        
        memset(&txframe, 0, sizeof(struct can_frame));
        txframe.can_id = (Priority<<26)|(GBT_27930_2015_CSD<<16)|(dev->DA<<8)|dev->SA;
        txframe.data[0] = (req->chgCumulativeMintues>>0)&0xFF;
        txframe.data[1] = (req->chgCumulativeMintues>>8)&0xFF;
        txframe.data[2] = (req->chgCumulativeKWH>>0)&0xFF;
        txframe.data[3] = (req->chgCumulativeKWH>>8)&0xFF;
        txframe.data[4] = (req->chgCode>>0)&0xFF;
        txframe.data[5] = (req->chgCode>>8)&0xFF;
        txframe.data[6] = (req->chgCode>>16)&0xFF;
        txframe.data[7] = (req->chgCode>>24)&0xFF;
        txframe.can_dlc = 8;
        dev->stop = 0;
		
        pthread_mutex_lock(&dev->mutex);
        memcpy(&dev->frame, &txframe, sizeof(struct can_frame));
        pthread_mutex_unlock(&dev->mutex);
        return GBT_27930_2015_NORMAL;

        if (can_J1939_send(&dev->canJ1939, &txframe)==sizeof(struct can_frame))
        {
            return GBT_27930_2015_NORMAL;
        }
    }
    return GBT_27930_2015_ERROR;
}

void can_GBT27930_show_BST(GBT27930_t* can)
{
    printi("BMS.BST:%08x\n", (*((uint32_t*)&can->bst)));
    if (can->bst.bmsInsulationFault==1)
    {
        printi("BSM Insulation Fault.\n");
    }
    if (can->bst.bmsOutputConnectorOverTemp==1)
    {
        printi("BSM OutputConnector OverTemp.\n");
    }
    if (can->bst.bmsUnitsOverTemp==1)
    {
        printi("BSM Units OverTemp.\n");
    }
    if (can->bst.bmsChargeConnectorFault==1)
    {
        printi("BSM ChargeConnector Fault.\n");
    }
    if (can->bst.bmsBatteryPackOverTemp==1)
    {
        printi("BSM BatteryPackage OverTemp.\n");
    }
    if (can->bst.bmsHighVolRelayFault==1)
    {
        printi("BSM HighVoltageRelay Fault.\n");
    }
    if (can->bst.bmsCheckpoint2Fault==1)
    {
        printi("BSM Checkpoint2 Fault.\n");
    }
    if (can->bst.bmsOtherFault==1)
    {
        printi("BSM Other Fault.\n");
    }
    if (can->bst.bmsCurrentOverReqeust==1)
    {
        printi("BSM Current OverRequest.\n");
    }
    if (can->bst.bmsVoltageAbnormal==1)
    {
        printi("BSM Voltage Abnormal Fault.\n");
    }
}

void can_GBT27930_show_BEM(GBT27930_t* can)
{
    printi("BMS.BEM:%08x\n", (*((uint32_t*)&can->bem)));
    if (can->bem.crm_0x00_timeout==1)
    {
        printi("BSM recv CRM_0x00 timeout.\n");
    }
    if (can->bem.crm_0xAA_timeout==1)
    {
        printi("BSM recv CRM_0xAA timeout.\n");
    }
    if (can->bem.cts_or_cml_timeout==1)
    {
        printi("BSM recv CTS or CML timeout.\n");
    }
    if (can->bem.cro_timeout==1)
    {
        printi("BSM recv CRO timeout.\n");
    }
    if (can->bem.ccs_timeout==1)
    {
        printi("BSM recv CSS timeout.\n");
    }
    if (can->bem.cst_timeout==1)
    {
        printi("BSM recv CST timeout.\n");
    }
    if (can->bem.csd_timeout==1)
    {
        printi("BSM recv CSD timeout.\n");
    }
}