#include "SerialPortTool.h" #include "Log.h" SerialPortTool::SerialPortTool(QObject* parent) : QObject(parent) { serialPort = new QSerialPort(); connect(serialPort, SIGNAL(readyRead()), this, SLOT(onReayRead())); connect(serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onSerialError(QSerialPort::SerialPortError))); timer = new QTimer(); timer->setInterval(3000); timer->stop(); connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout())); auto makeCommand = [=](QString lightNum, QString enable) { return QByteArray::fromHex(QString("A2 B2 08 02 %1 %2 C2 D2").arg(lightNum).arg(enable).toLatin1()); }; cmdMap[PlaybackStart] = makeCommand("01", "01"); cmdMap[PlaybackEnd] = makeCommand("01", "00"); cmdMap[RecordStart] = makeCommand("02", "01"); cmdMap[RecordEnd] = makeCommand("02", "00"); cmdMap[PlayPause] = makeCommand("03", "01"); cmdMap[PlayResume] = makeCommand("03", "00"); cmdMap[DiskWillFull] = makeCommand("04", "01"); cmdMap[DiskNotFull] = makeCommand("04", "00"); cmdMap[PowerOn] = makeCommand("05", "01"); cmdMap[PowerOff] = makeCommand("05", "00"); cmdMap[Forward] = makeCommand("06", "01"); cmdMap[LoopOn] = makeCommand("07", "01"); cmdMap[LoopOff] = makeCommand("07", "00"); cmdMap[Back] = makeCommand("08", "01"); cmdMap[MainChannelOn] = makeCommand("09", "01"); cmdMap[MainChannelOff] = makeCommand("09", "00"); cmdMap[SecondaryChannelOn] = makeCommand("0A", "01"); cmdMap[SecondaryChannelOff] = makeCommand("0A", "00"); } SerialPortTool::~SerialPortTool() { serialPort->close(); delete serialPort; } /** * @brief 打开串口 */ void SerialPortTool::open() { serialPort->setPortName("ttyAMA2"); serialPort->setBaudRate(QSerialPort::Baud115200); serialPort->setDataBits(QSerialPort::Data8); serialPort->setParity(QSerialPort::NoParity); serialPort->setStopBits(QSerialPort::OneStop); serialPort->setFlowControl(QSerialPort::NoFlowControl); if (serialPort->open(QIODevice::ReadWrite)) { Log::info("open serial port: /dev/ttyAMA2 success"); } else { Log::error("open serial port: /dev/ttyAMA2 failed, ready to retry..."); timer->start(); } } /** * @brief 关闭串口 */ void SerialPortTool::close() { serialPort->close(); } /** * @brief 串口报错槽函数 */ void SerialPortTool::onSerialError(QSerialPort::SerialPortError error) { if (error == QSerialPort::ResourceError) { Log::error("serial port break, try to reopen"); serialPort->close(); timer->start(); } } /** * @brief 重连串口 */ void SerialPortTool::onTimeout() { timer->stop(); bool ret = serialPort->open(QIODevice::ReadWrite); if (!ret) { Log::info("reopen serial port: /dev/ttyAMA2 success"); timer->start(); } else { Log::error("reopen serial port: /dev/ttyAMA2 failed, ready to retry..."); } } /** * @brief 读取并处理收到的串口指令 */ void SerialPortTool::onReayRead() { // 当缓冲区中有大于8个字节的数据时才处理 if (serialPort->bytesAvailable() < 8) return; // 由于本项目串口的数据频率小,可以将全部读到的数据当做一条指令来解析 // 当发送数据频率很大时,可以使用另外的缓冲区来存储读到的数据,然后读取缓冲区的数据进行指令的解析 // 将缓冲区的数据全部读取出来 QByteArray data = serialPort->readAll(); qDebug() << "data:" << data; // 对接受的数据进行协议解析 // 查找包头和包尾 QByteArray head = QByteArray::fromHex("A2 B2"); QByteArray tail = QByteArray::fromHex("C2 D2"); //... 0xA2 0xB2 0x08 0x01 0x01 0x00 0xC2 0xD2 ... // || || // indexHead indexTail int indexHead = data.indexOf(head); int indexTail = data.indexOf(tail); // 没有查找到包头和包尾 if (indexHead == -1 || indexTail == -1) return; // 从接收的数据中截取出一帧数据 QByteArray frame = data.mid(indexHead, indexTail + 2 - indexHead); if (frame.length() <= 4) return; // 对一帧数据进行校验 // 长度校验不通过 if (frame[2] != frame.length()) return; // 命令类型 if (data.at(3) != 0x01) return; switch (frame[4]) { case 1: emit btnPlaybackClicked(); break; case 2: emit btnPreviousClicked(); break; case 3: emit btnPauseClicked(); break; case 4: emit btnReturnClicked(); break; case 5: emit btnBackClicked(); break; case 6: emit btnNextClicked(); break; case 7: emit btnForwardClicked(); break; case 8: emit btnDoneClicked(); break; default: break; } } void SerialPortTool::onPlaybackStart() { serialPort->write(cmdMap.value(PlaybackStart)); serialPort->flush(); } void SerialPortTool::onPlaybackEnd() { serialPort->write(cmdMap.value(PlaybackEnd)); serialPort->flush(); } void SerialPortTool::onRecordStart() { serialPort->write(cmdMap.value(RecordStart)); serialPort->flush(); } void SerialPortTool::onRecordEnd() { serialPort->write(cmdMap.value(RecordEnd)); serialPort->flush(); } void SerialPortTool::onPlayPause() { serialPort->write(cmdMap.value(PlayPause)); serialPort->flush(); } void SerialPortTool::onPlayResume() { serialPort->write(cmdMap.value(PlayResume)); serialPort->flush(); } void SerialPortTool::onDiskWillFull() { serialPort->write(cmdMap.value(DiskWillFull)); serialPort->flush(); } void SerialPortTool::onDiskNotFull() { serialPort->write(cmdMap.value(DiskNotFull)); serialPort->flush(); } void SerialPortTool::onPowerOn() { serialPort->write(cmdMap.value(PowerOn)); serialPort->flush(); } void SerialPortTool::onPowerOff() { serialPort->write(cmdMap.value(PowerOff)); serialPort->flush(); } void SerialPortTool::onFoward() { serialPort->write(cmdMap.value(Forward)); serialPort->flush(); } void SerialPortTool::onBack() { serialPort->write(cmdMap.value(Back)); serialPort->flush(); } void SerialPortTool::onLoopOn() { serialPort->write(cmdMap.value(LoopOn)); serialPort->flush(); } void SerialPortTool::onLoopOff() { serialPort->write(cmdMap.value(LoopOff)); serialPort->flush(); } void SerialPortTool::onMainChannelOn() { serialPort->write(cmdMap.value(MainChannelOn)); serialPort->flush(); } void SerialPortTool::onMainChannelOff() { serialPort->write(cmdMap.value(MainChannelOff)); serialPort->flush(); } void SerialPortTool::onSecondaryChannelOn() { serialPort->write(cmdMap.value(SecondaryChannelOn)); serialPort->flush(); } void SerialPortTool::onSecondaryChannelOff() { serialPort->write(cmdMap.value(SecondaryChannelOff)); serialPort->flush(); }