選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

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