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.

217 lines
6.9 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::readRegisters()
  79. {
  80. if (!modbusDevice || modbusDevice->state() != QModbusDevice::ConnectedState)
  81. return;
  82. // 获取所有已注册的寄存器ID
  83. QStringList regIds = registerManager->getAllRegisteredRegisters();
  84. QMap<QString, QSet<int>> regMap; // 按类型分组存储地址
  85. // 分组寄存器地址
  86. for (const QString &id : regIds) {
  87. if (id.startsWith("D") || id.startsWith("M")) {
  88. bool ok;
  89. int addr = id.mid(1).toInt(&ok);
  90. if (ok && addr >= 0 && addr <= 4000) {
  91. regMap[id.left(1)].insert(addr);
  92. }
  93. }
  94. }
  95. // 读取D寄存器 (保持寄存器)
  96. if (regMap.contains("D")) {
  97. readRegisterGroup(QModbusDataUnit::HoldingRegisters, regMap["D"].values());
  98. }
  99. // 读取M寄存器 (线圈)
  100. if (regMap.contains("M")) {
  101. readRegisterGroup(QModbusDataUnit::Coils, regMap["M"].values());
  102. }
  103. }
  104. void ModbusManager::readRegisterGroup(QModbusDataUnit::RegisterType type, const QList<int> &addresses)
  105. {
  106. if (addresses.isEmpty()) return;
  107. QList<int> sortedAddrs = addresses;
  108. std::sort(sortedAddrs.begin(), sortedAddrs.end());
  109. // 合并连续地址范围
  110. int start = sortedAddrs.first();
  111. int end = start;
  112. for (int i = 1; i < sortedAddrs.size(); i++) {
  113. if (sortedAddrs[i] == end + 1) {
  114. end = sortedAddrs[i];
  115. } else {
  116. readAddressRange(type, start, end - start + 1);
  117. start = sortedAddrs[i];
  118. end = start;
  119. }
  120. }
  121. readAddressRange(type, start, end - start + 1);
  122. }
  123. void ModbusManager::readAddressRange(QModbusDataUnit::RegisterType type, int startAddr, int count)
  124. {
  125. const int MAX_REG_PER_REQUEST = 120;
  126. for (int offset = 0; offset < count; offset += MAX_REG_PER_REQUEST) {
  127. int readCount = qMin(MAX_REG_PER_REQUEST, count - offset);
  128. QModbusDataUnit unit(type, startAddr + offset, readCount);
  129. if (auto *reply = modbusDevice->sendReadRequest(unit, slaveAddress)) {
  130. QString regType = (type == QModbusDataUnit::HoldingRegisters) ? "D" : "M";
  131. pendingRequests[reply] = regType;
  132. connect(reply, &QModbusReply::finished, this, &ModbusManager::processModbusReply);
  133. }
  134. }
  135. }
  136. void ModbusManager::processModbusReply()
  137. {
  138. auto *reply = qobject_cast<QModbusReply*>(sender());
  139. if (!reply) return;
  140. if (reply->error() == QModbusDevice::NoError) {
  141. const QModbusDataUnit unit = reply->result();
  142. QString regType = pendingRequests.value(reply);
  143. int startAddr = unit.startAddress();
  144. for (uint i = 0; i < unit.valueCount(); i++) {
  145. int regAddr = startAddr + i;
  146. quint16 value = unit.value(i);
  147. QString regId = QString("%1%2").arg(regType).arg(regAddr);
  148. // 更新图元状态
  149. registerManager->updateRegisterValue(regId, value);
  150. }
  151. } else {
  152. emit errorOccurred(tr("Modbus错误: %1").arg(reply->errorString()));
  153. }
  154. pendingRequests.remove(reply);
  155. reply->deleteLater();
  156. }
  157. void ModbusManager::writeRegister(const QString& registerId, quint16 value)
  158. {
  159. if (registerId.isEmpty()) return;
  160. QModbusDataUnit::RegisterType regType = registerId.startsWith("D")
  161. ? QModbusDataUnit::HoldingRegisters
  162. : QModbusDataUnit::Coils;
  163. int regAddr = registerId.mid(1).toInt();
  164. QModbusDataUnit writeUnit(regType, regAddr, 1);
  165. writeUnit.setValue(0, value);
  166. if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, slaveAddress)) {
  167. connect(reply, &QModbusReply::finished, this, [this, reply]() {
  168. if (reply->error() != QModbusDevice::NoError) {
  169. emit errorOccurred(tr("写入失败: %1").arg(reply->errorString()));
  170. }
  171. reply->deleteLater();
  172. });
  173. }
  174. }