RB_ningyang/serialportmanager.cpp

370 lines
13 KiB
C++
Raw Normal View History

2026-01-22 11:08:28 +00:00
#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;
}