#include "appserial.h"
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
#include <QApplication>
#include <QMutex>
#include <dbt.h>

AppSerial::AppSerial(QObject *parent) : QObject(parent)
{
    qApp->installNativeEventFilter(this);        // 安装事件过滤器
    m_SerialPort = new QSerialPort;
    connect(m_SerialPort, &QSerialPort::readyRead, this, &AppSerial::slot_RecvSerialData);
}

AppSerial::~AppSerial()
{
    m_SerialPort->close();
    delete m_SerialPort;
}

/**
 * @brief   获取系统中所有可用的串口名
 * @return
 */
QStringList AppSerial::getAvailablePort()
{
    QStringList strName;
    foreach(const QSerialPortInfo& info, QSerialPortInfo::availablePorts())
    {
        QSerialPort port(info);
        if(port.open(QIODevice::ReadWrite))
        {
            strName << info.portName() + "(" + info.manufacturer() + ")";
            // qDebug() << strName;
            port.close();
        }
    }
    strName.sort();
    return strName;
}

/**
 * @brief  设置窗口句柄用于过滤事件
 * @param hwnd
 */
void AppSerial::setHWND(HWND hwnd)
{
    this->m_hwnd = hwnd;
}

bool AppSerial::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    Q_UNUSED(eventType);
    Q_UNUSED(result);
    MSG* msg = reinterpret_cast<MSG*>(message);
    int msgType = msg->message;
    if (msgType == WM_DEVICECHANGE) {
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
        switch (msg->wParam) {
        case DBT_DEVICEARRIVAL:
            /*  串口插入事件  */
            if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT) {
                PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
                QString portName = QString::fromWCharArray(lpdbv->dbcp_name);//插入的串口名
                emit comChangeStatus(portName, true);
            }
            break;
        case DBT_DEVICEREMOVECOMPLETE:
            /*  串口拔出事件  */
            if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT) {
                PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
                QString portName = QString::fromWCharArray(lpdbv->dbcp_name);//拔出的串口名
                emit comChangeStatus(portName, false);
            }
            break;
        case DBT_DEVNODES_CHANGED:
            break;
        default:
            break;
        }
    }

    return false;
}

void AppSerial::slot_RecvSerialData()
{
    QByteArray recvData = m_SerialPort->readAll();
    emit sig_RecvSerialData(recvData, TypeRecvData);
    // qDebug() << __FUNCTION__ << "recvData:" << recvData;
}

void AppSerial::slot_SendSerialData(const QByteArray &sendData)
{
    emit sig_RecvSerialData(sendData, TypeSendData);
    qDebug() << __FUNCTION__ << "recvData:" << sendData;
    m_SerialPort->write(sendData);
    if (m_SerialPort->waitForBytesWritten(3000)) {
        // 数据成功写入
    } else {
        // 写入失败
    }
}
