#include "serialportmanager.h" #include #include #include #include #include #include #include SerialPortManager::SerialPortManager(QObject *parent) : QObject(parent), serialPort(nullptr) { } SerialPortManager::~SerialPortManager() { if (serialPort) { delete serialPort; } } void SerialPortManager::setConnectionMode(ConnectionMode mode) { connectionMode = mode; } void SerialPortManager::configureSerialPort(const QString &portName, int baudRate, int dataBits, int stopBits, int parity) { this->portName = portName; this->baudRate = baudRate; this->dataBits = dataBits; this->stopBits = stopBits; this->parity = parity; } bool SerialPortManager::connectSerialPort() { if (serialPort) { disconnectSerialPort(); } if (connectionMode == Manual) { serialPort = new QSerialPort(this); serialPort->setPortName(portName); serialPort->setBaudRate(baudRate); serialPort->setDataBits(static_cast(dataBits)); serialPort->setStopBits(static_cast(stopBits)); serialPort->setParity(static_cast(parity)); } else { QString portName = autoConnect(command, expectedResponse); if (portName != "-1") { serialPort = new QSerialPort(portName, this); serialPort->setBaudRate(QSerialPort::Baud9600); serialPort->setDataBits(QSerialPort::Data8); serialPort->setStopBits(QSerialPort::OneStop); serialPort->setParity(QSerialPort::NoParity); } } if (serialPort && serialPort->open(QIODevice::ReadWrite)) { qDebug() << "open serialPort ok"; return true; } else { if (serialPort) { delete serialPort; serialPort = nullptr; } qDebug() << "open serialPort fail"; return false; } } void SerialPortManager::disconnectSerialPort() { if (serialPort && serialPort->isOpen()) { serialPort->close(); } if (serialPort) { delete serialPort; serialPort = nullptr; } } QSerialPort* SerialPortManager::getSerialPort() const { return serialPort; } QString SerialPortManager::autoConnect(const QByteArray &command, const QByteArray &expectedResponse) { const auto ports = QSerialPortInfo::availablePorts(); for (const QSerialPortInfo &portInfo : ports) { QSerialPort port(portInfo); port.setBaudRate(QSerialPort::Baud9600); port.setDataBits(QSerialPort::Data8); port.setStopBits(QSerialPort::OneStop); port.setParity(QSerialPort::NoParity); qDebug() << "Trying port:" << portInfo.portName(); if (port.open(QIODevice::ReadWrite)) { if (testPort(port, command, expectedResponse)) { port.close(); qDebug() << "Port found:" << portInfo.portName(); return portInfo.portName(); } port.close(); } else { qDebug() << "Failed to open port:" << portInfo.portName(); } } return "-1"; } bool SerialPortManager::testPort(QSerialPort &port, const QByteArray &command, const QByteArray &expectedResponse) { for (int attempt = 0; attempt < 3; ++attempt) { port.write(hexStringToByteArray(command)); if (port.waitForBytesWritten(1000) && port.waitForReadyRead(1000)) { QByteArray responseData = port.readAll(); while (port.waitForReadyRead(100)) { responseData += port.readAll(); } qDebug() << "Attempt" << attempt + 1 << ": Received response:" << responseData.toHex(); QString responseHex = responseData.toHex(); QString expectedResponseHex = expectedResponse.toHex(); // qDebug() << "test responseHex " <(hex.mid(i, 2).toInt(&ok, 16))); } return byteArray; } uint16_t SerialPortManager::CRC16_Calculate(const QByteArray &data) { uint16_t crc = 0xFFFF; for (int pos = 0; pos < data.size(); pos++) { crc ^= static_cast(data[pos]); for (int i = 8; i != 0; i--) { if ((crc & 0x0001) != 0) { crc >>= 1; crc ^= 0xA001; } else { crc >>= 1; } } } return crc; } void SerialPortManager::sendModbusCommand(const QString &hexCommand) { if (serialPort && serialPort->isOpen()) { QByteArray command = hexStringToByteArray(hexCommand); uint16_t crc = CRC16_Calculate(command); command.append(static_cast(crc & 0xFF)); //低 command.append(static_cast((crc >> 8) & 0xFF)); //高 serialPort->write(command); } else { qWarning() << "Serial port is not open!"; } } double SerialPortManager::receiveModbusResponse(int RESPONSE_LENGTH) { if (serialPort && serialPort->isOpen()) { QByteArray responseData = serialPort->readAll(); while (serialPort->waitForReadyRead(100)) { responseData += serialPort->readAll(); } // qDebug() << "Raw response data:" << responseData.toHex(); while (responseData.size() >= RESPONSE_LENGTH) { QByteArray singleResponse = responseData.left(RESPONSE_LENGTH); responseData.remove(0, RESPONSE_LENGTH); // qDebug() << "Processing single response:" << singleResponse.toHex(); // Extract the received CRC uint16_t receivedCrc = static_cast(singleResponse[singleResponse.size() - 2]) | (static_cast(singleResponse[singleResponse.size() - 1]) << 8); // Remove the CRC from the response data singleResponse.chop(2); // Calculate the CRC of the received data uint16_t calculatedCrc = CRC16_Calculate(singleResponse); qDebug() << "Data without CRC:" << singleResponse.toHex(); qDebug() << "Received CRC:" << QString::number(receivedCrc, 16).toUpper(); qDebug() << "Calculated CRC:" << QString::number(calculatedCrc, 16).toUpper(); if (receivedCrc == calculatedCrc) { qDebug() << "Received valid response with correct CRC:" << singleResponse; // Extract the specific data part (e.g., 03E80003) if (singleResponse.size() == 5 ) { QByteArray specificData = singleResponse.mid(3, 2); // Extract 4 bytes starting from the 4th byte // qDebug() << "Specific data part:" << specificData.toHex(); if(specificData.toHex() == "7fff"){ return -2; } else if(specificData.toHex() == "7ffc"){ return -3; } // Extract the first 2 bytes for the integer part uint16_t integerPart = (static_cast(specificData[0]) << 8) | static_cast(specificData[1]); // Extract the second 2 bytes for the decimal places uint16_t decimalPlaces = (static_cast(specificData[2]) << 8) | static_cast(specificData[3]); /** * @brief value 1000 */ //一位小数除10,三位除1000 double value = static_cast(integerPart) / 1000; qDebug() << "Converted value:" << value; qDebug() << "Converted value:" << QString::number(value, 'f', decimalPlaces); return value; // Return the calculated value } else if (singleResponse.size() == 7 ) { QByteArray specificData = singleResponse.mid(3, 4); // Extract 4 bytes starting from the 4th byte qDebug() << "Specific data part:" << specificData.toHex(); if(specificData.toHex() == "7fff"){ return -2; } else if(specificData.toHex() == "7ffc"){ return -3; } // Extract the first 2 bytes for the integer part uint16_t integerPart = (static_cast(specificData[0]) << 8) | static_cast(specificData[1]); // Extract the second 2 bytes for the decimal places uint16_t decimalPlaces = (static_cast(specificData[2]) << 8) | static_cast(specificData[3]); double value = static_cast(integerPart) / std::pow(10, decimalPlaces); qDebug() << "Converted value:" << value; qDebug() << "Converted value:" << QString::number(value, 'f', decimalPlaces); } else { qWarning() << "The response is too short to extract the specific data part."; } } else { qWarning() << "CRC check failed. Received CRC:" << receivedCrc << "Calculated CRC:" << calculatedCrc; } } if (!responseData.isEmpty()) { qWarning() << "Remaining data after processing:" << responseData.toHex(); } } else { qWarning() << "receiveModbusResponse"; } return -1; } double SerialPortManager::sendModbus_receive(const QString &hexCommand ,int RESPONSE_LENGTH) { if (serialPort && serialPort->isOpen()) { QByteArray command = hexStringToByteArray(hexCommand); uint16_t crc = CRC16_Calculate(command); command.append(static_cast(crc & 0xFF)); //低 command.append(static_cast((crc >> 8) & 0xFF)); //高 serialPort->write(command); if (serialPort->waitForBytesWritten(1000)) { return receiveModbusResponse(RESPONSE_LENGTH); } else { qWarning() << "Failed to write command to serial port."; } } else { qWarning() << "sendModbus_receive Serial port is not open!"; } return -1; } bool SerialPortManager::sendModbus_receive_2(const QString &hexCommand, int RESPONSE_LENGTH) { if (serialPort && serialPort->isOpen()) { QByteArray command = hexStringToByteArray(hexCommand); uint16_t crc = CRC16_Calculate(command); command.append(static_cast(crc & 0xFF)); //低 command.append(static_cast((crc >> 8) & 0xFF)); //高 serialPort->write(command); if (serialPort->waitForBytesWritten(1000)) { QByteArray responseData = serialPort->readAll(); while (serialPort->waitForReadyRead(100)) { responseData += serialPort->readAll(); } // qDebug() << "Raw response data:" << responseData.toHex(); while (responseData.size() >= RESPONSE_LENGTH) { QByteArray singleResponse = responseData.left(RESPONSE_LENGTH); responseData.remove(0, RESPONSE_LENGTH); // qDebug() << "Processing single response:" << singleResponse.toHex(); uint16_t receivedCrc = static_cast(singleResponse[singleResponse.size() - 2]) | (static_cast(singleResponse[singleResponse.size() - 1]) << 8); singleResponse.chop(2); uint16_t calculatedCrc = CRC16_Calculate(singleResponse); // qDebug() << "Data without CRC:" << singleResponse.toHex(); // qDebug() << "Received CRC:" << QString::number(receivedCrc, 16).toUpper(); // qDebug() << "Calculated CRC:" << QString::number(calculatedCrc, 16).toUpper(); if (receivedCrc == calculatedCrc) { // qDebug() << "Received valid response with correct CRC:" << singleResponse; return true; } else { qWarning() << "CRC check failed. Received CRC:" << receivedCrc << "Calculated CRC:" << calculatedCrc; return false; } } if (!responseData.isEmpty()) { qWarning() << "Remaining data after processing:" << responseData.toHex(); } } else { qWarning() << "Failed to write command to serial port."; } } else { qWarning() << "Serial port is not open!"; } return false; }