#include "dncommthread.h"
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "yt_unit_shm.h"
#include "realvalue.h"


extern YT_UNIT_SHM *ytShm;

int speed_arr[] = {  B115200, B57600, B38400, B19200, B9600, B4800,
            B2400, B1200};
int name_arr[] = {115200, 57600, 38400,  19200,  9600,  4800,  2400, 1200};

unsigned char ef_cmd_0[] = {0x01, 0x03, 0x10, 0x00, 0x00, 0x64, 0x00, 0x00};
unsigned char ef_cmd_1[] = {0x01, 0x03, 0x12, 0x00, 0x00, 0x3e, 0x00, 0x00};
unsigned char ef_cmd_2[] = {0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};

unsigned char ef_cmd_si[] = {0x01, 0x10, 0x10, 0x63, 0x00, 0x01, 0x02, 0x72, 0x59, 0x5a, 0x98};
unsigned char ef_cmd_cl[] = {0x01, 0x10, 0x10, 0x63, 0x00, 0x01, 0x02, 0x12, 0x34, 0xb3, 0x75};
unsigned char ef_cmd_st[] = {0x01, 0x10, 0x10, 0x34, 0x00, 0x01, 0x02, 0x00, 0x3c, 0x00, 0x00};
unsigned char ef_cmd_sc[] = {0x01, 0x10, 0x12, 0x3c, 0x00, 0x01, 0x02, 0x00, 0x64, 0x00, 0x00};

unsigned short T0 = 0x0000;//线缆1温度上限
unsigned short T0W = 0x0000;//线缆1温度上限过滤时间
unsigned short T1 = 0x0000;//线缆2温度上限
unsigned short T1W = 0x0000;//线缆2温度上限过滤时间

unsigned short T2 = 0x0000;//电流上限
unsigned short T2W = 0x0000;//电流上限过滤时间

bool need_st0, need_st1, need_st2, need_cls, isWaitting;

typedef union {
    float f;
    unsigned short s[2];
}UNFI;


DNCommThread::DNCommThread(QObject *parent, quint8 id, bool enabled, QString commpath) :
    QThread(parent)
{
    Id = id;
    isWaitting = false;
    ef_idx = 0;
    noEcho0 = 0;
    noEcho1 = 0;
    Enabled = enabled;
    CommOpened = false;
    CommPath = commpath;
    CommType = 1;
    reopen = false;
    need_st0 = false;
    need_st1 = false;
    need_st2 = false;
}

void DNCommThread::setCommType(quint16 type)
{
    CommType = type;
}

void DNCommThread::setparam(QString path, bool enabled)
{
    Enabled = enabled;
    CommPath = path;
    if(CommOpened)
    {
        reopen = true;
    }
}

void DNCommThread::set_speed(int speed)
{
    uint   i;
    int   status;
    struct termios   Opt;
    tcgetattr(fd, &Opt);
    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)
    {
        if (speed == name_arr[i])
        {
            tcflush(fd, TCIOFLUSH);
            cfsetispeed(&Opt, speed_arr[i]);
            cfsetospeed(&Opt, speed_arr[i]);
            status = tcsetattr(fd, TCSANOW, &Opt);
            if (status != 0)
                perror("tcsetattr fd1");
            return;
        }
        tcflush(fd,TCIOFLUSH);
    }
}

int DNCommThread::set_Parity(int databits, int stopbits, int parity)
{
    struct termios options;
    if  ( tcgetattr( fd,&options)  !=  0)
    {
        perror("SetupSerial 1");
        return -1;
    }
    options.c_cflag &= ~CSIZE;
    switch (databits)
    {
        case 7:
            options.c_cflag |= CS7;
        break;
        case 8:
            options.c_cflag |= CS8;
        break;
        default:
            fprintf(stderr,"Unsupported data size\n");
            return -1;
    }
    switch (parity)
    {
        case 'n':
        case 'N':
            options.c_cflag &= ~PARENB;
            options.c_iflag &= ~INPCK;
        break;
        case 'o':
        case 'O':
            options.c_cflag |= (PARODD | PARENB);
            options.c_iflag |= INPCK;
        break;
        case 'e':
        case 'E':
            options.c_cflag |= PARENB;
            options.c_cflag &= ~PARODD;
            options.c_iflag |= INPCK;
        break;
        case 'S':
        case 's':
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSTOPB;
        break;
        default:
            fprintf(stderr,"Unsupported parity\n");
            return -1;
    }
    switch (stopbits)
    {
        case 1:
            options.c_cflag &= ~CSTOPB;
        break;
        case 2:
            options.c_cflag |= CSTOPB;
        break;
        default:
            fprintf(stderr,"Unsupported stop bits\n");
            return -1;
    }


    options.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
    options.c_oflag &= ~OPOST;
    options.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);

    /* Set input parity option */

    if (parity != 'n')
        options.c_iflag |= INPCK;
    options.c_cc[VTIME] = 150; // 15 seconds
    options.c_cc[VMIN] = 0;


    tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
    if (tcsetattr(fd,TCSANOW,&options) != 0)
    {
        perror("SetupSerial 3");
        return -1;
    }
    return 0;
}

int DNCommThread::open_comm()
{
//    printf("open comm %d %s\n",Id,CommPath.toUtf8().data());
    fd = open(CommPath.toUtf8().data(),O_RDWR);
    if(fd==-1)
        return -1;
    set_speed(9600);
    if(set_Parity(8,1,'N')==-1){
        close(fd);
        return -1;
    }
    return 0;
}

void DNCommThread::chk_rtn(QByteArray Rtn)
{
//    printf("Rtn length:%d\n",Rtn.length());
    if(Rtn.length()>0){
        QDateTime dt = QDateTime::currentDateTime();
        QString str = QString("[%1] %2 recv: ").arg(dt.toString("yyyy-MM-dd HH:mm:ss")).arg(Id);
        for(int i=0;i<Rtn.length();i++)
            str.append(QString("%1 ").arg(Rtn[i]&0xff,2,16,QChar('0')));
        emit log(str);
        uint t = dt.toTime_t();
        if(((Rtn[0]&0xff)==0xdc)
                &&((Rtn[1]&0xff)==0xcd)
                &&((Rtn[2]&0xff)==0xaa)
                &&((Rtn[3]&0xff)==0xaa)
                &&((Rtn[4]&0xff)==0xe0)
                &&((Rtn[Rtn.length()-2]&0xff)==0xcd)
                &&((Rtn[Rtn.length()-1]&0xff)==0xdc))
        {
            if((Rtn.at(5)&0xff)==0xc1){//定时上报
                int cure2 = Rtn.indexOf((char)(0xe2),0);
                int cur55 = Rtn.indexOf((char)(0x55),0);
                int cure3 = Rtn.indexOf((char)(0xe3),0);
                int cure6 = Rtn.indexOf((char)(0xe6),0);
                if(((Rtn.at(cure2+1)&0xff)==0x01)
                        &&((cur55-cure2)>=6)){
                    chk_e2(Rtn.mid(cure2+2,cur55-cure2-2),t);
                }
                if(((Rtn.at(cure3+1)&0xff)==0x01)
                        &&((cure6-cure3)>=10)
                        &&((cure6-cure3)<=18))
                {
                    chk_e3(Rtn.mid(cure3+2,cure6-cure3-1),t);
                }
                QByteArray e6 = Rtn.mid(cure6);
                int base=0;
                while(e6.length()>=7)
                {
                    if(((e6.at(1)&0xff)>=1)
                            &&((e6.at(1)&0xff)<=16)
                            &&((e6.at(2)&0xff)==0x01)
                            &&((e6.at(5)&0xff)==0x02)
                            &&((e6.at(6)&0xff)==0x01))
                    {
                        if(ytShm->sPointList.sPoint[Id][128+base].ENABLED==0x01)
                        {
                            float v = ((e6.at(3)&0xff)*256.0+(e6.at(4)&0xff)*1.0)/150.0;
                            set_realtime_value(Id,128+base,v,t);
                        }
                        base++;
                        cure6 = e6.indexOf((char)(0xe6),6);
                        if(cure6>0)
                            e6 = e6.mid(cure6);
                        else
                            break;
                    }else{
                        break;
                    }
                }
            }else if((Rtn.at(5)&0xff)==0xf1){//主动上报
                int cure2 = Rtn.indexOf((char)(0xe2),0);
                int cur55 = Rtn.indexOf((char)(0x55),0);
                int cure3 = Rtn.indexOf((char)(0xe3),0);
                int cure6 = Rtn.indexOf((char)(0xe6),0);
                if(((Rtn.at(cure2+1)&0xff)==0x01)
                        &&((cur55-cure2)>=6)){
                    chk_e2(Rtn.mid(cure2+2,cur55-cure2-2),t);
                }
                if(((Rtn.at(cure3+1)&0xff)==0x01)
                        &&((cure6-cure3)==4))
                {
                    quint8 e3id = ((Rtn.at(cure3+2)&0xf0)>>4)*10+(Rtn.at(cure3+2)&0x0f);
                    if((e3id>=1)&&(e3id<=16))
                    {
                        if(ytShm->sPointList.sPoint[Id][e3id].ENABLED==0x01)
                        {
                            if((Rtn.at(cure3+3)&0xff)==0x00)
                                set_realtime_value(Id,e3id,0,t);
                            else
                                set_realtime_value(Id,e3id,1,t);
                        }
                    }
                }
                QByteArray e6 = Rtn.mid(cure6);
                int base=0;
                while(e6.length()>=7)
                {
                    if(((e6.at(1)&0xff)>=1)
                            &&((e6.at(1)&0xff)<=16)
                            &&((e6.at(2)&0xff)==0x01)
                            &&((e6.at(5)&0xff)==0x02)
                            &&((e6.at(6)&0xff)==0x01))
                    {
                        if(ytShm->sPointList.sPoint[Id][128+base].ENABLED==0x01)
                        {
                            float v = ((e6.at(3)&0xff)*256.0+(e6.at(4)&0xff)*1.0)/150.0;
                            set_realtime_value(Id,128+base,v,t);
                        }
                        base++;
                        cure6 = e6.indexOf((char)(0xe6),6);
                        if(cure6>0)
                            e6 = e6.mid(cure6);
                        else
                            break;
                    }else{
                        break;
                    }
                }
            }
        }
    }
}

quint16 DNCommThread::chk_crcc(quint8 *d, int len)
{
    int j,i;
    quint16 default_data = 0xa001;
    quint16 crc = 0xffff;
    for(j=0;j<(len-2);j++){
            crc ^= (quint16)(d[j]&0x00ff);
            for(i=0;i<8;i++){
                if(crc&0x01){
                    crc >>= 1;
                    crc ^= default_data;//a001,1021
                }else
                    crc >>= 1;
            }
        }
        return crc;
}

void DNCommThread::ef_comm2_read()
{
    int t_len,len;
    fd_set reads;
    struct timeval timeout;
    unsigned char cmd[8];
    unsigned char tmp[1024];
    unsigned char rtn[1024];
    quint32 v_tmp;
    uint t = QDateTime::currentDateTime().toTime_t();
    read(fd,tmp,1024);
    FD_ZERO(&reads);
    FD_SET(fd,&reads);
    timeout.tv_sec = 1;
    timeout.tv_usec = 500000;
    cmd[0] = 0x01;
    cmd[1] = 0x03;
    cmd[2] = 0x00;
    cmd[3] = 0x00;
    cmd[4] = 0x00;
    cmd[5] = 0x10;
    cmd[6] = 0x44;
    cmd[7] = 0x06;
    write(fd,cmd,8);
    noEcho0++;
    if(select(fd+1,&reads,NULL,NULL,&timeout)>=0)
    {
        if(FD_ISSET(fd,&reads))
        {
            t_len= read(fd,tmp,1024);
            len=t_len;
            if(t_len>0){
                for(int i=0;i<t_len;i++)
                {
                    rtn[i] = tmp[i]&0xff;
                    printf("%02x ",rtn[i]);
                }
                if(len<((rtn[2]&0xff)+5)){
                    usleep(200000);
                    t_len=read(fd,tmp,1024);
                    if(t_len>0){
                        for(int i=0;i<t_len;i++)
                        {
                            rtn[i+len]=tmp[i]&0xff;
                            printf("%02x ",rtn[i+len]);
                        }
                        len += t_len;
                    }
                }
                printf("\n");
                if(len>=69){
                    quint16 crc = chk_crcc((quint8 *)rtn, len);
//                    printf("%02x%02x %04x\n",rtn[len-1],rtn[len-2],crc);
                    if((rtn[len-1]==((crc>>8)&0xff))&&(rtn[len-2]==(crc&0xff))){
                        noEcho0 = 0;
                        v_tmp = static_cast<quint32>(((rtn[7]&0x000000ff)<<24)|((rtn[8]&0x000000ff)<<16)|((rtn[9]&0x000000ff)<<8)|(rtn[10]&0x000000ff));
                        float value = *(float*)&v_tmp;
                        set_realtime_value(Id,1,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[11]&0x000000ff)<<24)|((rtn[12]&0x000000ff)<<16)|((rtn[13]&0x000000ff)<<8)|(rtn[14]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,2,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[15]&0x000000ff)<<24)|((rtn[16]&0x000000ff)<<16)|((rtn[17]&0x000000ff)<<8)|(rtn[18]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,3,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[19]&0x000000ff)<<24)|((rtn[20]&0x000000ff)<<16)|((rtn[21]&0x000000ff)<<8)|(rtn[22]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,4,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[23]&0x000000ff)<<24)|((rtn[24]&0x000000ff)<<16)|((rtn[25]&0x000000ff)<<8)|(rtn[26]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,5,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[27]&0x000000ff)<<24)|((rtn[28]&0x000000ff)<<16)|((rtn[29]&0x000000ff)<<8)|(rtn[30]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,6,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[31]&0x000000ff)<<24)|((rtn[32]&0x000000ff)<<16)|((rtn[33]&0x000000ff)<<8)|(rtn[34]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,7,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[35]&0x000000ff)<<24)|((rtn[36]&0x000000ff)<<16)|((rtn[37]&0x000000ff)<<8)|(rtn[38]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,8,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[39]&0x000000ff)<<24)|((rtn[40]&0x000000ff)<<16)|((rtn[41]&0x000000ff)<<8)|(rtn[42]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,9,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[43]&0x000000ff)<<24)|((rtn[44]&0x000000ff)<<16)|((rtn[45]&0x000000ff)<<8)|(rtn[46]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,10,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[47]&0x000000ff)<<24)|((rtn[48]&0x000000ff)<<16)|((rtn[49]&0x000000ff)<<8)|(rtn[50]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,11,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[51]&0x000000ff)<<24)|((rtn[52]&0x000000ff)<<16)|((rtn[53]&0x000000ff)<<8)|(rtn[54]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,12,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[55]&0x000000ff)<<24)|((rtn[56]&0x000000ff)<<16)|((rtn[57]&0x000000ff)<<8)|(rtn[58]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,13,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[59]&0x000000ff)<<24)|((rtn[60]&0x000000ff)<<16)|((rtn[61]&0x000000ff)<<8)|(rtn[62]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,14,value*1.0,t);
                        v_tmp = static_cast<quint32>(((rtn[63]&0x000000ff)<<24)|((rtn[64]&0x000000ff)<<16)|((rtn[65]&0x000000ff)<<8)|(rtn[66]&0x000000ff));
                        value = *(float*)&v_tmp;
                        set_realtime_value(Id,15,value*1.0,t);
                    }
                }
            }
        }
    }
}

void DNCommThread::chk_e2(QByteArray d, uint t)
{
    if(d.length()>=4){
        for(int i=0;i<d.length();i++)
        {
            if(ytShm->sPointList.sPoint[Id][64+i].ENABLED==0x01)
            {
                if((d.at(i)&0xff)==0x00)
                    set_realtime_value(Id,64+i,0,t);
                else
                    set_realtime_value(Id,64+i,1,t);
            }
        }
    }
}

void DNCommThread::chk_e3(QByteArray d, uint t)
{
    for(int i=0;i<d.length();i++)
    {
        if(ytShm->sPointList.sPoint[Id][1+i].ENABLED==0x01)
        {
            if((d.at(i)&0xff)==0x00)
                set_realtime_value(Id,1+i,0,t);
            else
                set_realtime_value(Id,1+i,1,t);
        }
    }
}

void DNCommThread::run()
{
    if(Enabled)
    {
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].IDX = DNCOMM_THREAD_0+Id;
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].WAITSEC = 30;
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].ENABLED = 0x01;
        emit log(QString("[%1] dncomm[%2] thread start\r\n")
                 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
                 .arg(Id));
    }
    else
    {
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].IDX = DNCOMM_THREAD_0+Id;
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].WAITSEC = 0;
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].ENABLED = 0x00;
        emit log(QString("[%1] dncomm[%2] thread disabled\r\n")
                 .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
                 .arg(Id));
    }
    while(1)
    {
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].IDX = DNCOMM_THREAD_0+Id;
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].WAITSEC = 30;
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].ENABLED = 0x01;
        ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].LASTFEED
                = QDateTime::currentDateTime().toTime_t();
        printf("dncomm %d last feed %d\n",Id,ytShm->dogTimeList.dogTime[DNCOMM_THREAD_0+Id].LASTFEED);
        if(!Enabled)
        {
            if(CommOpened){
                close(fd);
                emit log(QString("[%1] dncomm[%2] thread stop\r\n")
                         .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
                         .arg(Id));
                return;
            }
        }else{
            if(!CommOpened){
                if(open_comm()==-1)
                {
                    emit log(QString("[%1] dncomm[%2] open failed\r\n")
                             .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
                             .arg(CommPath));
                    return;
                }else{
                    emit log(QString("[%1] dncomm[%2] opened\r\n")
                             .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
                             .arg(CommPath));
                    CommOpened = true;
                }
            }else if(reopen){
                if(CommOpened){
                    close(fd);
                    emit log(QString("[%1] dncomm[%2] thread stop\r\n")
                             .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
                             .arg(Id));
                    CommOpened = false;
                }
                reopen = false;
            }else{//read and write
                if(CommType==3){
                    ef_comm2_read();
                }
            }
        }
        usleep(300000);
    }
}
