You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.9 KiB

  1. #include "modbussimulator.h"
  2. #include <QSerialPort>
  3. #include <QDebug>
  4. #include <algorithm>
  5. #include<QThread>
  6. ModbusSimulator::ModbusSimulator(QObject *parent)
  7. : QObject(parent), m_coilAddresses(),m_running(false), m_mutex()
  8. {
  9. m_modbusClient = new QModbusRtuSerialMaster(this);
  10. m_readTimer = new QTimer(this);
  11. connect(m_readTimer, &QTimer::timeout, this, &ModbusSimulator::readCoils);
  12. }
  13. ModbusSimulator::~ModbusSimulator()
  14. {
  15. stopSimulation();
  16. }
  17. bool ModbusSimulator::isRunning() const
  18. {
  19. return m_running;
  20. }
  21. void ModbusSimulator::startSimulation()
  22. {
  23. qDebug() << "进入 startSimulation() 函数";
  24. if (m_running) return;
  25. qDebug() << "启动Modbus仿真555...";
  26. // 配置Modbus连接
  27. m_modbusClient->setConnectionParameter(QModbusDevice::SerialPortNameParameter, "COM1");
  28. m_modbusClient->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);
  29. m_modbusClient->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud9600);
  30. m_modbusClient->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);
  31. m_modbusClient->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);
  32. if (!m_modbusClient->connectDevice())
  33. {
  34. emit errorOccurred("无法连接Modbus设备");
  35. return;
  36. }
  37. qDebug() << "Modbus设备连接成功";
  38. m_running = true;
  39. m_readTimer->start(1000); // 每秒读取一次
  40. }
  41. void ModbusSimulator::stopSimulation()
  42. {
  43. if (!m_running) return;
  44. m_readTimer->stop();
  45. m_modbusClient->disconnectDevice();
  46. m_running = false;
  47. }
  48. void ModbusSimulator::setCoilAddresses(const QSet<int> &addresses)
  49. {
  50. qDebug() <<"执行到此";
  51. qDebug() << "setCoilAddresses called, this:" << this; // 打印对象地址
  52. QMutexLocker locker(&m_mutex); // 必须加锁
  53. m_coilAddresses = QSet<int>(addresses);
  54. }
  55. void ModbusSimulator::writeCoil(int address, bool state)
  56. {
  57. if (!m_running) return;
  58. if (auto reply = m_modbusClient->sendWriteRequest(
  59. QModbusDataUnit(QModbusDataUnit::Coils, address, {state}), 1)) {
  60. connect(reply, &QModbusReply::finished, [reply, address]() {
  61. if (reply->error() != QModbusDevice::NoError) {
  62. qWarning() << "写线圈失败:" << reply->errorString() << "地址:" << address;
  63. }
  64. reply->deleteLater();
  65. });
  66. }
  67. }
  68. void ModbusSimulator::readCoils()
  69. {
  70. QSet<int> addressesCopy;
  71. {
  72. QMutexLocker locker(&m_mutex);
  73. if (!m_running || m_coilAddresses.isEmpty()) return;
  74. addressesCopy = m_coilAddresses; // 在锁保护下复制
  75. }
  76. int minAddress = *std::min_element(addressesCopy.begin(), addressesCopy.end());
  77. int maxAddress = *std::max_element(addressesCopy.begin(), addressesCopy.end());
  78. int count = maxAddress - minAddress + 1;
  79. // 创建读请求
  80. QModbusDataUnit readUnit(QModbusDataUnit::Coils, minAddress, count);
  81. if (auto *reply = m_modbusClient->sendReadRequest(readUnit, 1)) {
  82. if (!reply->isFinished()) {
  83. // 使用智能指针确保地址集合在回调中有效
  84. auto safeAddresses = QSharedPointer<QSet<int>>::create(addressesCopy);
  85. connect(reply, &QModbusReply::finished, this, [this, reply, safeAddresses]() {
  86. if (reply->error() == QModbusDevice::NoError) {
  87. const QModbusDataUnit unit = reply->result();
  88. for (int i = 0; i < unit.valueCount(); ++i) {
  89. int address = unit.startAddress() + i;
  90. bool state = unit.value(i);
  91. if (safeAddresses->contains(address)) {
  92. emit coilStatusRead(address, state);
  93. }
  94. }
  95. }
  96. reply->deleteLater();
  97. });
  98. } else {
  99. delete reply;
  100. }
  101. }
  102. }