RB_ningyang/serialportmanager.cpp
2026-01-22 19:08:28 +08:00

370 lines
13 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "serialportmanager.h"
#include <QSerialPortInfo>
#include <QThread>
#include <QDebug>
#include <QModbusRtuSerialMaster>
#include <QModbusDataUnit>
#include <QtEndian>
#include <cmath>
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<QSerialPort::DataBits>(dataBits));
serialPort->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
serialPort->setParity(static_cast<QSerialPort::Parity>(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 " <<responseHex;
if (responseHex.contains(hexStringToByteArray(expectedResponseHex))) {
qDebug() << "auto conn test ok";
return true;
}
} else {
qDebug() << "Attempt" << attempt + 1 << ": No response or timeout.";
}
}
return false;
}
QByteArray SerialPortManager::hexStringToByteArray(const QString &hex) {
QByteArray byteArray;
for (int i = 0; i < hex.length(); i += 2) {
bool ok;
byteArray.append(static_cast<char>(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<uint8_t>(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<char>(crc & 0xFF)); //低
command.append(static_cast<char>((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<uint8_t>(singleResponse[singleResponse.size() - 2]) |
(static_cast<uint8_t>(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<uint8_t>(specificData[0]) << 8) |
static_cast<uint8_t>(specificData[1]);
// Extract the second 2 bytes for the decimal places
uint16_t decimalPlaces = (static_cast<uint8_t>(specificData[2]) << 8) |
static_cast<uint8_t>(specificData[3]);
/**
* @brief value 1000
*/
//一位小数除10三位除1000
double value = static_cast<double>(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<uint8_t>(specificData[0]) << 8) |
static_cast<uint8_t>(specificData[1]);
// Extract the second 2 bytes for the decimal places
uint16_t decimalPlaces = (static_cast<uint8_t>(specificData[2]) << 8) |
static_cast<uint8_t>(specificData[3]);
double value = static_cast<double>(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<char>(crc & 0xFF)); //低
command.append(static_cast<char>((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<char>(crc & 0xFF)); //低
command.append(static_cast<char>((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<uint8_t>(singleResponse[singleResponse.size() - 2]) |
(static_cast<uint8_t>(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;
}