#include "modbussimulator.h" #include #include #include #include #include // PollingWorker 实现 PollingWorker::PollingWorker(QModbusRtuSerialMaster *client, QMutex *mutex, QSet *addresses, std::atomic *runningFlag, QObject *parent) : QObject(parent), m_modbusClient(client), m_mutex(mutex), m_coilAddresses(addresses), m_runningFlag(runningFlag), m_stop(false) { } void PollingWorker::startPolling(int interval) { while (!m_stop) { QThread::msleep(interval); // 使用线程休眠替代定时器 if (!m_stop && *m_runningFlag) { performCoilReading(); } } } void PollingWorker::performCoilReading() { QSet addressesCopy; { QMutexLocker locker(m_mutex); if (m_coilAddresses->isEmpty()) return; addressesCopy = *m_coilAddresses; } int minAddress = *std::min_element(addressesCopy.begin(), addressesCopy.end()); int maxAddress = *std::max_element(addressesCopy.begin(), addressesCopy.end()); int count = maxAddress - minAddress + 1; QModbusDataUnit readUnit(QModbusDataUnit::Coils, minAddress, count); if (auto *reply = m_modbusClient->sendReadRequest(readUnit, 1)) { if (!reply->isFinished()) { auto safeAddresses = QSharedPointer>::create(addressesCopy); connect(reply, &QModbusReply::finished, [this, reply, safeAddresses]() { if (reply->error() == QModbusDevice::NoError) { const QModbusDataUnit unit = reply->result(); for (int i = 0; i < unit.valueCount(); ++i) { int address = unit.startAddress() + i; bool state = unit.value(i); if (safeAddresses->contains(address)) { emit coilReadResult(address, state); } } } else { emit errorOccurred(reply->errorString()); } reply->deleteLater(); }); } else { delete reply; } } } // ModbusSimulator 实现 ModbusSimulator::ModbusSimulator(QObject *parent) : QObject(parent), m_coilAddresses(), m_running(false), m_workerThread(nullptr), m_worker(nullptr) { m_modbusClient = new QModbusRtuSerialMaster(this); } ModbusSimulator::~ModbusSimulator() { stopSimulation(); } bool ModbusSimulator::isRunning() const { return m_running; } void ModbusSimulator::startSimulation() { if (m_running) return; // 配置Modbus连接 m_modbusClient->setConnectionParameter(QModbusDevice::SerialPortNameParameter, "COM1"); m_modbusClient->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity); m_modbusClient->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud9600); m_modbusClient->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8); m_modbusClient->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop); if (!m_modbusClient->connectDevice()) { emit errorOccurred("无法连接Modbus设备"); return; } m_modbusClient->moveToThread(m_workerThread); m_running = true; // 创建工作线程和Worker m_workerThread = new QThread(this); m_worker = new PollingWorker(m_modbusClient, &m_mutex, &m_coilAddresses, &m_running); m_worker->moveToThread(m_workerThread); // 连接信号槽 connect(m_worker, &PollingWorker::coilReadResult, this, &ModbusSimulator::coilStatusRead); connect(m_worker, &PollingWorker::errorOccurred, this, &ModbusSimulator::errorOccurred); connect(m_workerThread, &QThread::started, [this]() { m_worker->startPolling(500); // 每秒轮询一次 }); connect(m_workerThread, &QThread::finished, m_worker, &QObject::deleteLater); connect(m_workerThread, &QThread::finished, m_workerThread, &QObject::deleteLater); m_workerThread->start(); } void ModbusSimulator::stopSimulation() { if (!m_running) return; m_running = false; if (m_worker) { m_worker->stop(); // 通过公共接口设置停止标志 } if (m_workerThread && m_workerThread->isRunning()) { m_workerThread->quit(); m_workerThread->wait(); } if (m_modbusClient) { m_modbusClient->disconnectDevice(); } } void ModbusSimulator::setCoilAddresses(const QSet &addresses) { QMutexLocker locker(&m_mutex); m_coilAddresses = addresses; } void ModbusSimulator::writeCoil(int address, bool state) { if (!m_running) return; if (auto reply = m_modbusClient->sendWriteRequest( QModbusDataUnit(QModbusDataUnit::Coils, address, {state}), 1)) { connect(reply, &QModbusReply::finished, [reply, address]() { if (reply->error() != QModbusDevice::NoError) { qWarning() << "写线圈失败:" << reply->errorString() << "地址:" << address; } reply->deleteLater(); }); } }