1
0

service.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. const settingsService = require('../../store/settings-store.js')
  2. const transport = require('../../transport/ble-core.js')
  3. const modbusProtocol = require('../../protocols/modbus-rtu/index.js')
  4. const {
  5. addCoilReadValues,
  6. addWordReadValues
  7. } = require('../../utils/register-value-utils.js')
  8. function getSharedSlaveAddress(title = '从机地址错误') {
  9. try {
  10. return settingsService.getModbusSlaveAddress()
  11. } catch (error) {
  12. transport.showCommandAlert(title, error.message)
  13. return null
  14. }
  15. }
  16. function formatAddress(value) {
  17. return Number(value || 0).toString(16).toUpperCase()
  18. }
  19. function getChunkLabel(label, chunks, chunk) {
  20. if (!label || chunks.length <= 1) return label
  21. return `${label} ${formatAddress(chunk.address)}-${formatAddress(chunk.address + chunk.quantity - 1)}`
  22. }
  23. function isBroadcastAddress(slaveAddress) {
  24. return Number(slaveAddress) === 0
  25. }
  26. function showBroadcastReadAlert(label) {
  27. transport.showCommandAlert(label || '读取命令错误', '广播地址 0x00 不支持读取')
  28. }
  29. async function sendReadChunk(slaveAddress, functionCode, chunk, label, kind, options = {}) {
  30. if (isBroadcastAddress(slaveAddress)) {
  31. showBroadcastReadAlert(label)
  32. return false
  33. }
  34. return transport.sendManagedFrame(
  35. modbusProtocol.buildReadFrame(slaveAddress, functionCode, chunk.address, chunk.quantity, {
  36. maxFrameBytes: options.maxFrameBytes
  37. }),
  38. label,
  39. {
  40. address: chunk.address,
  41. functionCode,
  42. kind,
  43. protocol: modbusProtocol.PROTOCOL_NAME,
  44. quantity: chunk.quantity,
  45. slaveAddress
  46. },
  47. {
  48. maxFrameBytes: options.maxFrameBytes,
  49. showModal: options.showModal
  50. }
  51. )
  52. }
  53. async function readSpans(slaveAddress, functionCode, spans, label, kind, options = {}) {
  54. const readValues = {
  55. coils: {},
  56. words: {}
  57. }
  58. const normalizedSpans = (spans || []).filter((span) => span && span.quantity > 0)
  59. for (const span of normalizedSpans) {
  60. const chunks = modbusProtocol.getReadChunks(functionCode, span.address, span.quantity, options)
  61. for (const chunk of chunks) {
  62. const responseValue = await sendReadChunk(
  63. slaveAddress,
  64. functionCode,
  65. chunk,
  66. getChunkLabel(label, chunks, chunk),
  67. kind,
  68. options
  69. )
  70. if (!responseValue) return null
  71. if (functionCode === 0x01 || functionCode === 0x02) {
  72. addCoilReadValues(readValues, chunk.address, chunk.quantity, responseValue)
  73. } else {
  74. addWordReadValues(readValues, chunk.address, responseValue)
  75. }
  76. if (typeof options.onChunk === 'function') {
  77. options.onChunk(responseValue, chunk)
  78. }
  79. }
  80. }
  81. return readValues
  82. }
  83. async function readRegisterWords(slaveAddress, functionCode, startAddress, quantity, label, kind, options = {}) {
  84. const words = []
  85. const chunks = modbusProtocol.getReadChunks(functionCode, startAddress, quantity, options)
  86. for (const chunk of chunks) {
  87. const responseValue = await sendReadChunk(
  88. slaveAddress,
  89. functionCode,
  90. chunk,
  91. getChunkLabel(label, chunks, chunk),
  92. kind,
  93. options
  94. )
  95. if (!responseValue) return null
  96. const chunkWords = responseValue.words || []
  97. chunkWords.forEach((word, index) => {
  98. words[chunk.address - startAddress + index] = Number(word) & 0xFFFF
  99. })
  100. if (typeof options.onChunk === 'function') {
  101. options.onChunk(responseValue, chunk)
  102. }
  103. }
  104. return words
  105. }
  106. async function readBitValues(slaveAddress, functionCode, startAddress, quantity, label, kind, options = {}) {
  107. const result = await readSpans(
  108. slaveAddress,
  109. functionCode,
  110. [{ address: startAddress, quantity }],
  111. label,
  112. kind,
  113. options
  114. )
  115. return result ? result.coils : null
  116. }
  117. async function readSingleHoldingWord(slaveAddress, address, label = '读取配对寄存器', kind = 'holding-word-read') {
  118. const words = await readRegisterWords(slaveAddress, 0x03, address, 1, label, kind)
  119. return words && Number.isInteger(words[0]) ? words[0] & 0xFFFF : null
  120. }
  121. function writeSingleCoil(slaveAddress, address, checked, label, kind = 'coil-write', options = {}) {
  122. const coilValue = checked ? 0xFF00 : 0x0000
  123. return transport.sendManagedFrame(
  124. modbusProtocol.buildWriteSingleCoilFrame(slaveAddress, address, checked),
  125. label,
  126. isBroadcastAddress(slaveAddress) ? null : {
  127. address,
  128. functionCode: 0x05,
  129. kind,
  130. protocol: modbusProtocol.PROTOCOL_NAME,
  131. quantity: 1,
  132. slaveAddress,
  133. value: coilValue
  134. },
  135. {
  136. maxFrameBytes: options.maxFrameBytes,
  137. showModal: options.showModal
  138. }
  139. )
  140. }
  141. function writeSingleRegister(slaveAddress, address, value, label, kind = 'register-write', options = {}) {
  142. return transport.sendManagedFrame(
  143. modbusProtocol.buildWriteSingleRegisterFrame(slaveAddress, address, value),
  144. label,
  145. isBroadcastAddress(slaveAddress) ? null : {
  146. address,
  147. functionCode: 0x06,
  148. kind,
  149. protocol: modbusProtocol.PROTOCOL_NAME,
  150. quantity: 1,
  151. slaveAddress,
  152. value
  153. },
  154. {
  155. maxFrameBytes: options.maxFrameBytes,
  156. showModal: options.showModal
  157. }
  158. )
  159. }
  160. function writeMultipleRegisters(slaveAddress, address, values, label, kind = 'registers-write', options = {}) {
  161. return transport.sendManagedFrame(
  162. modbusProtocol.buildWriteMultipleRegistersFrame(slaveAddress, address, values, {
  163. maxFrameBytes: options.maxFrameBytes
  164. }),
  165. label,
  166. isBroadcastAddress(slaveAddress) ? null : {
  167. address,
  168. functionCode: 0x10,
  169. kind,
  170. protocol: modbusProtocol.PROTOCOL_NAME,
  171. quantity: values.length,
  172. slaveAddress
  173. },
  174. {
  175. maxFrameBytes: options.maxFrameBytes,
  176. showModal: options.showModal
  177. }
  178. )
  179. }
  180. module.exports = {
  181. getMaxReadQuantity: modbusProtocol.getMaxReadQuantity,
  182. getMaxWriteMultipleRegisterQuantity: modbusProtocol.getMaxWriteMultipleRegisterQuantity,
  183. getReadChunks: modbusProtocol.getReadChunks,
  184. getSharedSlaveAddress,
  185. readBitValues,
  186. readRegisterWords,
  187. readSingleHoldingWord,
  188. readSpans,
  189. splitQuantity: modbusProtocol.splitQuantity,
  190. writeMultipleRegisters,
  191. writeSingleCoil,
  192. writeSingleRegister
  193. }