#include <QDir>
#include <QCoreApplication>
#include "rfid.h"
#include "config.h"
#include "ModuleReader.h"

extern config *pconfig;

rfid::rfid(QObject *parent) : QThread(parent)
{
}

void rfid::slot_set_thread_stop(void)
{
    this->threadstatus = false;
}

#define PRESET_VALUE 0xFFFF
#define POLYNOMIAL  0x1021
quint16 rfid::uiCrc16Cal(QByteArray &data, quint8 count)
{
    quint8 ucI,ucJ;
    quint16 uiCrcValue = PRESET_VALUE;
    for(ucI = 0; ucI < count; ucI++)
    {
        // uiCrcValue = uiCrcValue ^ (quint8)(data.at(ucI));
        quint16 xorFlag = 0;
        quint16 bit = 0;
        quint16 dcdBitMask = 0x80;
        for(ucJ = 0; ucJ < 8; ucJ++)
        {
            xorFlag = uiCrcValue & 0x8000;
            uiCrcValue <<= 1;
            bit = (((quint8)(data.at(ucI)) & dcdBitMask) == dcdBitMask);
            uiCrcValue |= bit;
            if(xorFlag)
            {
                uiCrcValue = uiCrcValue ^ POLYNOMIAL;
            }
            dcdBitMask >>= 1;
        }
    }
    return uiCrcValue;
}

// 发送数据给下位机
void rfid::sendData(QByteArray &sendData)
{
    // qDebug() << "sendData: " << sendData.toHex();
    quint16 crc = uiCrc16Cal(sendData, sendData.size());
    // 输出CRC16校验和
    // qDebug() << "CRC16:" << QString::number(crc, 16).toUpper();
    sendData.prepend(0xFF);
    sendData.append((quint8)(crc >> 8));
    sendData.append((quint8)crc);
    qDebug() << "rfid-sendData: " << sendData.toHex();
    // 发送数据帧
    this->devserial->clear(QSerialPort::AllDirections);
    qint64 bytesWritten = this->devserial->write(sendData);
    if (bytesWritten == -1) {
        qWarning() << "Failed to write data:" << this->devserial->errorString();
    }

    // 刷新输出缓冲区
    // devserial->flush();

    // 等待数据写入完成
    if (!this->devserial->waitForBytesWritten(1000)) {
        qWarning() << "Timeout: Failed to write data within 5000 milliseconds.";
    }
}

// 读取下位机发来数据
bool rfid::readData(QByteArray *data, quint16 timeout)
{
    data->clear();
    while(this->devserial->waitForReadyRead(timeout))
    {
        *data += this->devserial->readAll();
    }
    qDebug() << "rfid-readData: " << data->size() << "," << data->toHex();
    if(data->size() == 0)
    {
        return false;
    }
    // 刷新输入缓冲区
    // devserial->flush();
    quint8 addr = data->at(0);
    if(addr == 0xFF)
    {
        QByteArray subData = data->mid(1, data->size() - 3);
        quint16 crc1 = uiCrc16Cal(subData, subData.size());
        quint16 crc2 = quint8(data->at(data->size() - 2));
        crc2 <<= 8;
        crc2 += quint8(data->at(data->size() - 1));
        if(crc1 == crc2)
        {
            return true;
        }
    }
    return false;
}

bool rfid::openSerial(void)
{
    this->devserial->setPortName(pconfig->rfidPort); // 设定串口名称，根据你的系统修改
    this->devserial->setBaudRate(pconfig->rfidBaud);
    this->devserial->setDataBits(QSerialPort::Data8);
    this->devserial->setParity(QSerialPort::NoParity);
    this->devserial->setStopBits(QSerialPort::OneStop);
    this->devserial->setFlowControl(QSerialPort::NoFlowControl);
    // this->devserial->setTextModeEnabled(true);

    if (this->devserial->open(QIODevice::ReadWrite)) {
        qDebug() << "RFID串口打开成功";
        this->devserial->setReadBufferSize(0);
        msleep(1000);
        //信号与槽函数关联
        // connect(devserial, &QSerialPort::readyRead, this, &uart::slot_uartReadData);
        return true;
    }
    return false;
}

void rfid::slot_uartinfo_change(void)
{
    if(openPort == true)
    {
        this->devserial->close();
        openPort = false;
        workstat = readerWorkStat::init;
    }
}

void rfid::slot_start_read_tid(void)
{
    m_user = QVariant();
    if(workstat == readerWorkStat::sleep)
    {
        workstat = readerWorkStat::startreadtid;
    }
}

void rfid::slot_start_read_tid_Ex(const QVariant &user)
{
    m_user = user;
}

void rfid::getReadType(void)
{
    quint8 dataArray[] = {0x00, 0x04};
    QByteArray ba(reinterpret_cast<char*>(dataArray), sizeof(dataArray));
    this->sendData(ba);

    QByteArray data;
    if(true == readData(&data, 100))
    {
        workstat = readerWorkStat::setant;
    }
}

// void rfid::setAnt(void)
// {
//     quint8 dataArray[] = {0x0D, 0x91, 0x02, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06};
//     QByteArray ba(reinterpret_cast<char*>(dataArray), sizeof(dataArray));
//     this->sendData(ba);

//     QByteArray data;
//     if(true == readData(&data, 1000))
//     {
//         workstat = readerWorkStat::setpower;
//     }
// }

// void rfid::setPower(void)
// {
//     quint8 dataArray[] = {0x2B, 0x91, 0x04,
//                           0x01, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),
//                           0x02, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),
//                           0x03, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),
//                           0x04, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),
//                           0x05, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),
//                           0x06, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
//                                 (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),

//     };
//     QByteArray ba(reinterpret_cast<char*>(dataArray), sizeof(dataArray));
//     this->sendData(ba);

//     QByteArray data;
//     if(true == readData(&data, 100))
//     {
//         workstat = readerWorkStat::startreadtid;
//     }
// }

void rfid::setAnt(void)
{
    quint8 dataArray[] = {0x09, 0x91, 0x02, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04};
    QByteArray ba(reinterpret_cast<char*>(dataArray), sizeof(dataArray));
    this->sendData(ba);

    QByteArray data;
    if(true == readData(&data, 1000))
    {
        workstat = readerWorkStat::setpower;
    }
}

void rfid::setPower(void)
{
    quint8 dataArray[] = {0x1D, 0x91, 0x04,
                          0x01, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
                          (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
                          (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),
                          0x02, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
                          (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
                          (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),
                          0x03, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
                          (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
                          (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),
                          0x04, (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
                          (quint8)(pconfig->rfidPower >> 8), (quint8)(pconfig->rfidPower),
                          (quint8)(pconfig->rfidSetTime >> 8), (quint8)(pconfig->rfidSetTime),

                          };
    QByteArray ba(reinterpret_cast<char*>(dataArray), sizeof(dataArray));
    this->sendData(ba);

    QByteArray data;
    if(true == readData(&data, 100))
    {
        workstat = readerWorkStat::startreadtid;
    }
}
void rfid::setStartreadtid(void)
{
    quint8 dataArray[] = {0x05, 0x22, 0x80, 0x00, 0x00, (quint8)((pconfig->rfidWorkTime - 500) >> 8), (quint8)(pconfig->rfidWorkTime - 500)};
    QByteArray ba(reinterpret_cast<char*>(dataArray), sizeof(dataArray));
    this->sendData(ba);

    tidList.clear();
    QByteArray data;
    msleep(pconfig->rfidWorkTime);

    while(this->devserial->waitForReadyRead(100))
    {
        data += this->devserial->readAll();
    }
    if(data.size() > 0)
    {
        int size = data.size();
        qDebug() << "rfid-readData: " << size << "," << data.toHex();
        if(size > 0)
        {
            if((quint8)(data.at(0)) != 0xFF)
            {
                return;
            }
            quint8 dataSize = data.at(1);
            QByteArray subData = data.mid(1, dataSize + 4);
            quint16 crc1 = uiCrc16Cal(subData, subData.size());
            quint16 crc2 = quint8(data.at(dataSize + 5));
            crc2 <<= 8;
            crc2 += quint8(data.at(dataSize + 6));

            if(crc1 != crc2)
            {
                return;
            }

            if((quint8)(subData.at(1)) != 0x22
                || (quint8)(subData.at(2)) != 0x00
                || (quint8)(subData.at(3)) != 0x00
                || (quint8)(subData.at(4)) != 0x80
            )
            {
                return;
            }

            quint16 flags = quint8(subData.at(5));
            tidCount <<= 8;
            tidCount += quint8(subData.at(6));

            if((flags & 0x0010) == 0x0010)
            {
                if(dataSize == 7)
                {
                    tidCount = quint8(subData.at(7));
                    tidCount <<= 8;
                    tidCount += quint8(subData.at(8));
                    tidCount <<= 8;
                    tidCount += quint8(subData.at(9));
                    tidCount <<= 8;
                    tidCount += quint8(subData.at(10));
                }
                else{
                    return;
                }
            }
            else{
                tidCount = quint8(subData.at(7));
            }

            qDebug()<<"tid count is "<<tidCount;

            if(tidCount > 0)
            {
                workstat = readerWorkStat::readid;
            }
            else{
                if (m_user.isNull())
                {
                    emit signal_tid_update(0, tidList);
                }
                else
                {
                    emit signal_tid_update_Ex(0, tidList, m_user);
                }

                workstat = readerWorkStat::sleep;
            }
        }
    }
}

void rfid::readTid(void)
{
    quint8 dataArray[] = {0x03, 0x29, 0x00, 0x07, 0x00};

    quint32 m_tidCount = tidCount;
    while (m_tidCount > 0)
    {
        QByteArray ba(reinterpret_cast<char*>(dataArray), sizeof(dataArray));
        this->sendData(ba);
        QByteArray data;
        while(this->devserial->waitForReadyRead(100))
        {
            data += this->devserial->readAll();
        }
        if(data.size() > 0)
        {
            int size = data.size();
            qDebug() << "rfid-readData: " << size << "," << data.toHex();
            if(size > 0)
            {
                if((quint8)(data.at(0)) != 0xFF)
                {
                    return;
                }
                quint8 dataSize = data.at(1);
                QByteArray subData = data.mid(1, dataSize + 4);
                quint16 crc1 = uiCrc16Cal(subData, subData.size());
                quint16 crc2 = quint8(data.at(dataSize + 5));
                crc2 <<= 8;
                crc2 += quint8(data.at(dataSize + 6));

                if(crc1 != crc2)
                {
                    return;
                }

                if((quint8)(subData.at(1)) != 0x29
                    || (quint8)(subData.at(2)) != 0x00
                    || (quint8)(subData.at(3)) != 0x00
                    || (quint8)(subData.at(4)) != 0x00
                    || (quint8)(subData.at(5)) != 0x07
                    || (quint8)(subData.at(6)) != 0x00
                    )
                {
                    return;
                }
                quint8 idx = 8;
                quint8 count = (quint8)(subData.at(7));
                m_tidCount = (m_tidCount > count)?(m_tidCount - count):0;
                while(count--)
                {
                    quint8 readCount = (quint8)(subData.at(idx++));
                    qint8 rssi = (qint8)(subData.at(idx++));
                    quint8 ant_id = (quint8)(subData.at(idx++));
                    idx = idx + 4;
                    QByteArray epcbyte = subData.mid(idx, 12);
                    QString epc = epcbyte.toHex().toUpper();
                    idx = idx + 14;

                    if(!tidList.contains(epc))
                    {
                        qDebug() << "EPC=" << epc << "," << readCount << "," << rssi << "," << ant_id;
                        tidList.append(epc);
                    }
                }
            }
        }
    }
    signal_tid_update(tidCount, tidList);
    workstat = readerWorkStat::sleep;
}

void rfid::run()
{
    this->devserial = new QSerialPort;
    while(this->threadstatus)
    {
        if(pconfig->rfidInit == true)
        {
            if(openPort == false)
            {
                openPort = this->openSerial();
            }
            else{
                switch(workstat)
                {
                case readerWorkStat::init:getReadType();break;
                case readerWorkStat::setant:setAnt();break;
                case readerWorkStat::setpower:setPower();break;
                case readerWorkStat::startreadtid:setStartreadtid();break;
                case readerWorkStat::readid:readTid();break;
                }
            }
        }
        msleep(20);
    }

    if(openPort == true)
    {
        this->devserial->close();
    }
    qDebug() << "rfid thread exit!";
}
