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

185 行
5.8 KiB

  1. #include "modbusworker.h"
  2. #include <QModbusDataUnit>
  3. #include <QDebug>
  4. #include <QSerialPort>
  5. ModbusWorker::ModbusWorker(RegisterManager* regManager, QObject *parent)
  6. : QObject(parent), registerManager(regManager)
  7. {
  8. // modbusDevice = new QModbusRtuSerialMaster(this);
  9. // connect(modbusDevice, &QModbusClient::errorOccurred, this,
  10. // [this](QModbusDevice::Error) {
  11. // emit errorOccurred(modbusDevice->errorString());
  12. // });
  13. }
  14. ModbusWorker::~ModbusWorker()
  15. {
  16. disconnectDevice();
  17. }
  18. bool ModbusWorker::connectToDevice(const QString& portName,
  19. QSerialPort::BaudRate baudRate,
  20. QSerialPort::DataBits dataBits,
  21. QSerialPort::Parity parity,
  22. QSerialPort::StopBits stopBits)
  23. {
  24. if (!modbusDevice) { // 新增检查
  25. emit errorOccurred("Modbus设备未初始化");
  26. return false;
  27. }
  28. if (modbusDevice->state() != QModbusDevice::UnconnectedState) {
  29. disconnectDevice();
  30. }
  31. modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, portName);
  32. modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudRate);
  33. modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits);
  34. modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, parity);
  35. modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits);
  36. if (!modbusDevice->connectDevice()) {
  37. emit errorOccurred(tr("连接失败: %1").arg(modbusDevice->errorString()));
  38. return false;
  39. }
  40. emit connectionStatusChanged(true);
  41. return true;
  42. }
  43. void ModbusWorker::disconnectDevice()
  44. {
  45. if (modbusDevice->state() != QModbusDevice::UnconnectedState) {
  46. modbusDevice->disconnectDevice();
  47. emit connectionStatusChanged(false);
  48. }
  49. }
  50. void ModbusWorker::initModbusDevice()
  51. {
  52. modbusDevice = new QModbusRtuSerialMaster(this);
  53. connect(modbusDevice, &QModbusClient::errorOccurred, this,
  54. [this](QModbusDevice::Error) {
  55. emit errorOccurred(modbusDevice->errorString());
  56. });
  57. }
  58. void ModbusWorker::readRegisters()
  59. {
  60. if (!modbusDevice || modbusDevice->state() != QModbusDevice::ConnectedState)
  61. return;
  62. // 获取所有已注册的寄存器ID
  63. QStringList regIds = registerManager->getAllRegisteredRegisters();
  64. QMap<QString, QSet<int>> regMap;
  65. for (const QString &id : regIds) {
  66. if (id.startsWith("D") || id.startsWith("M")) {
  67. bool ok;
  68. int addr = id.mid(1).toInt(&ok);
  69. if (ok && addr >= 0 && addr <= 4000) {
  70. regMap[id.left(1)].insert(addr);
  71. }
  72. }
  73. }
  74. if (regMap.contains("D")) {
  75. readRegisterGroup(QModbusDataUnit::HoldingRegisters, regMap["D"].values());
  76. }
  77. if (regMap.contains("M")) {
  78. readRegisterGroup(QModbusDataUnit::Coils, regMap["M"].values());
  79. }
  80. }
  81. void ModbusWorker::readRegisterGroup(QModbusDataUnit::RegisterType type, const QList<int> &addresses)
  82. {
  83. if (addresses.isEmpty()) return;
  84. QList<int> sortedAddrs = addresses;
  85. std::sort(sortedAddrs.begin(), sortedAddrs.end());
  86. int start = sortedAddrs.first();
  87. int end = start;
  88. for (int i = 1; i < sortedAddrs.size(); i++) {
  89. if (sortedAddrs[i] == end + 1) {
  90. end = sortedAddrs[i];
  91. } else {
  92. readAddressRange(type, start, end - start + 1);
  93. start = sortedAddrs[i];
  94. end = start;
  95. }
  96. }
  97. readAddressRange(type, start, end - start + 1);
  98. }
  99. void ModbusWorker::readAddressRange(QModbusDataUnit::RegisterType type, int startAddr, int count)
  100. {
  101. const int MAX_REG_PER_REQUEST = 120;
  102. for (int offset = 0; offset < count; offset += MAX_REG_PER_REQUEST) {
  103. int readCount = qMin(MAX_REG_PER_REQUEST, count - offset);
  104. QModbusDataUnit unit(type, startAddr + offset, readCount);
  105. if (auto *reply = modbusDevice->sendReadRequest(unit, slaveAddress)) {
  106. QString regType = (type == QModbusDataUnit::HoldingRegisters) ? "D" : "M";
  107. pendingRequests[reply] = regType;
  108. connect(reply, &QModbusReply::finished, this, &ModbusWorker::processModbusReply);
  109. }
  110. }
  111. }
  112. void ModbusWorker::processModbusReply()
  113. {
  114. auto *reply = qobject_cast<QModbusReply*>(sender());
  115. if (!reply) return;
  116. if (reply->error() == QModbusDevice::NoError) {
  117. const QModbusDataUnit unit = reply->result();
  118. QString regType = pendingRequests.value(reply);
  119. int startAddr = unit.startAddress();
  120. for (uint i = 0; i < unit.valueCount(); i++) {
  121. int regAddr = startAddr + i;
  122. quint16 value = unit.value(i);
  123. QString regId = QString("%1%2").arg(regType).arg(regAddr);
  124. emit registerValueUpdated(regId, value);
  125. }
  126. } else {
  127. emit errorOccurred(tr("Modbus错误: %1").arg(reply->errorString()));
  128. }
  129. pendingRequests.remove(reply);
  130. reply->deleteLater();
  131. }
  132. void ModbusWorker::writeRegister(const QString& registerId, quint16 value)
  133. {
  134. if (!modbusDevice) {
  135. emit errorOccurred("Modbus设备未初始化");
  136. return;
  137. }
  138. if (registerId.isEmpty()) return;
  139. QModbusDataUnit::RegisterType regType = registerId.startsWith("D")
  140. ? QModbusDataUnit::HoldingRegisters
  141. : QModbusDataUnit::Coils;
  142. int regAddr = registerId.mid(1).toInt();
  143. QModbusDataUnit writeUnit(regType, regAddr, 1);
  144. writeUnit.setValue(0, value);
  145. if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, slaveAddress)) {
  146. connect(reply, &QModbusReply::finished, this, [this, reply]() {
  147. if (reply->error() != QModbusDevice::NoError) {
  148. emit errorOccurred(tr("写入失败: %1").arg(reply->errorString()));
  149. }
  150. reply->deleteLater();
  151. });
  152. }
  153. }