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.

147 lines
4.6 KiB

  1. #include "modbusmanager.h"
  2. #include <QModbusDataUnit>
  3. #include <QDebug>
  4. ModbusManager::ModbusManager(RegisterManager* regManager, QObject *parent)
  5. : QObject(parent), registerManager(regManager)
  6. {
  7. modbusDevice = new QModbusRtuSerialMaster(this);
  8. pollTimer = new QTimer(this);
  9. connect(modbusDevice, &QModbusClient::errorOccurred, this,
  10. [this](QModbusDevice::Error) {
  11. emit errorOccurred(modbusDevice->errorString());
  12. });
  13. connect(pollTimer, &QTimer::timeout, this, &ModbusManager::readRegisters);
  14. }
  15. ModbusManager::~ModbusManager()
  16. {
  17. stopSimulation();
  18. disconnectDevice();
  19. }
  20. bool ModbusManager::connectToDevice(const QString& portName,
  21. QSerialPort::BaudRate baudRate,
  22. QSerialPort::DataBits dataBits,
  23. QSerialPort::Parity parity,
  24. QSerialPort::StopBits stopBits)
  25. {
  26. if (modbusDevice->state() != QModbusDevice::UnconnectedState) {
  27. disconnectDevice();
  28. }
  29. modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, portName);
  30. modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudRate);
  31. modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits);
  32. modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, parity);
  33. modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits);
  34. if (!modbusDevice->connectDevice()) {
  35. emit errorOccurred(tr("连接失败: %1").arg(modbusDevice->errorString()));
  36. return false;
  37. }
  38. emit connectionStatusChanged(true);
  39. return true;
  40. }
  41. void ModbusManager::disconnectDevice()
  42. {
  43. if (modbusDevice->state() != QModbusDevice::UnconnectedState) {
  44. modbusDevice->disconnectDevice();
  45. emit connectionStatusChanged(false);
  46. }
  47. }
  48. void ModbusManager::startSimulation(int interval)
  49. {
  50. pollTimer->start(interval);
  51. }
  52. void ModbusManager::stopSimulation()
  53. {
  54. pollTimer->stop();
  55. }
  56. void ModbusManager::readRegisters()
  57. {
  58. if (!modbusDevice || modbusDevice->state() != QModbusDevice::ConnectedState)
  59. return;
  60. // 读取所有D寄存器 (保持寄存器)
  61. readRegisterGroup(QModbusDataUnit::HoldingRegisters, 0, 4000);
  62. // 读取所有M寄存器 (线圈)
  63. readRegisterGroup(QModbusDataUnit::Coils, 0, 4000);
  64. }
  65. void ModbusManager::readRegisterGroup(QModbusDataUnit::RegisterType type, int startAddr, int count)
  66. {
  67. const int MAX_REG_PER_REQUEST = 125; // Modbus RTU限制
  68. for (int addr = startAddr; addr < count; addr += MAX_REG_PER_REQUEST) {
  69. int readCount = qMin(MAX_REG_PER_REQUEST, count - addr);
  70. QModbusDataUnit unit(type, addr, readCount);
  71. if (auto *reply = modbusDevice->sendReadRequest(unit, slaveAddress)) {
  72. QString regType = (type == QModbusDataUnit::HoldingRegisters) ? "D" : "M";
  73. pendingRequests[reply] = regType;
  74. connect(reply, &QModbusReply::finished, this, &ModbusManager::processModbusReply);
  75. }
  76. }
  77. }
  78. void ModbusManager::processModbusReply()
  79. {
  80. auto *reply = qobject_cast<QModbusReply*>(sender());
  81. if (!reply) return;
  82. if (reply->error() == QModbusDevice::NoError) {
  83. const QModbusDataUnit unit = reply->result();
  84. QString regType = pendingRequests.value(reply);
  85. int startAddr = unit.startAddress();
  86. for (uint i = 0; i < unit.valueCount(); i++) {
  87. int regAddr = startAddr + i;
  88. quint16 value = unit.value(i);
  89. QString regId = QString("%1%2").arg(regType).arg(regAddr);
  90. // 更新图元状态
  91. registerManager->updateRegisterValue(regId, value);
  92. }
  93. } else {
  94. emit errorOccurred(tr("Modbus错误: %1").arg(reply->errorString()));
  95. }
  96. pendingRequests.remove(reply);
  97. reply->deleteLater();
  98. }
  99. void ModbusManager::writeRegister(const QString& registerId, quint16 value)
  100. {
  101. if (registerId.isEmpty()) return;
  102. QModbusDataUnit::RegisterType regType = registerId.startsWith("D")
  103. ? QModbusDataUnit::HoldingRegisters
  104. : QModbusDataUnit::Coils;
  105. int regAddr = registerId.mid(1).toInt();
  106. QModbusDataUnit writeUnit(regType, regAddr, 1);
  107. writeUnit.setValue(0, value);
  108. if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, slaveAddress)) {
  109. connect(reply, &QModbusReply::finished, this, [this, reply]() {
  110. if (reply->error() != QModbusDevice::NoError) {
  111. emit errorOccurred(tr("写入失败: %1").arg(reply->errorString()));
  112. }
  113. reply->deleteLater();
  114. });
  115. }
  116. }