|
- #include "modbussimulator.h"
- #include <QSerialPort>
- #include <QDebug>
- #include <algorithm>
- #include <QCoreApplication>
- #include <atomic>
-
- // PollingWorker 实现
- PollingWorker::PollingWorker(QModbusRtuSerialMaster *client,
- QMutex *mutex,
- QSet<int> *addresses,
- std::atomic<bool> *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<int> 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<QSet<int>>::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<int> &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();
- });
- }
- }
|