1
0

register-io.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. const {
  2. normalizeTextValue
  3. } = require('../../utils/base-utils.js')
  4. const {
  5. bytesToWords
  6. } = require('../../utils/binary-utils.js')
  7. const {
  8. MAX_MODBUS_ADDRESS
  9. } = require('./constants.js')
  10. const {
  11. decodeRegisterValue,
  12. encodeBitFieldIntoBytes,
  13. encodeRegisterBytes,
  14. encodeRegisterWords,
  15. isBitFieldRegister,
  16. validateRegisterValue: validateCodecRegisterValue
  17. } = require('./value-codec.js')
  18. function normalizeAddress(value, fallback = 0) {
  19. if (typeof value === 'number') {
  20. return Number.isFinite(value) ? Math.max(0, Math.min(Math.round(value), MAX_MODBUS_ADDRESS)) : fallback
  21. }
  22. const text = String(value === undefined || value === null ? '' : value).trim()
  23. if (!text) return fallback
  24. const hexText = text.toUpperCase().startsWith('0X') ? text.slice(2) : text
  25. if (/^[0-9A-F]+$/i.test(hexText)) {
  26. const parsedHex = parseInt(hexText, 16)
  27. return Number.isFinite(parsedHex) ? Math.max(0, Math.min(parsedHex, MAX_MODBUS_ADDRESS)) : fallback
  28. }
  29. const numberValue = Number(text)
  30. return Number.isFinite(numberValue) ? Math.max(0, Math.min(Math.round(numberValue), MAX_MODBUS_ADDRESS)) : fallback
  31. }
  32. function splitWordSpans(startAddress, quantity, maxQuantity) {
  33. const spans = []
  34. let address = normalizeAddress(startAddress, 0)
  35. let remaining = Math.max(0, Math.floor(Number(quantity) || 0))
  36. while (remaining > 0) {
  37. const spanQuantity = Math.min(remaining, maxQuantity)
  38. spans.push({
  39. address,
  40. quantity: spanQuantity
  41. })
  42. address += spanQuantity
  43. remaining -= spanQuantity
  44. }
  45. return spans
  46. }
  47. function getRegisterWriteValueText(register) {
  48. if (register.inputValue !== undefined && register.inputValue !== null) return normalizeTextValue(register.inputValue)
  49. if (register.defaultValue !== undefined && register.defaultValue !== null) return normalizeTextValue(register.defaultValue)
  50. return ''
  51. }
  52. function getRegisterWordsFromWordCache(register, wordCache) {
  53. const words = []
  54. for (let offset = 0; offset < register.registerCount; offset += 1) {
  55. const word = wordCache[register.address + offset]
  56. if (word === undefined) return null
  57. words.push(word)
  58. }
  59. return words
  60. }
  61. function getRegisterBytesFromByteCache(register, byteCache) {
  62. const bytes = []
  63. for (let offset = 0; offset < register.byteLength; offset += 1) {
  64. const byte = byteCache[register.address + offset]
  65. if (byte === undefined) return null
  66. bytes.push(Number(byte) & 0xFF)
  67. }
  68. return bytes
  69. }
  70. function getRegisterWordsFromByteCache(register, byteCache) {
  71. const bytes = getRegisterBytesFromByteCache(register, byteCache)
  72. if (!bytes) return null
  73. return bytesToWords(bytes.length % 2 === 0 ? bytes : bytes.concat(0))
  74. }
  75. function decodeRegisterFromBytes(register, bytes) {
  76. if (!Array.isArray(bytes) || bytes.length < register.byteLength) return null
  77. return decodeRegisterValue(
  78. {
  79. ...register,
  80. byteOffset: 0,
  81. memoryEndian: register.memoryEndian
  82. },
  83. bytesToWords(bytes.length % 2 === 0 ? bytes : bytes.concat(0))
  84. )
  85. }
  86. function decodeRegisterFromWordCache(register, wordCache) {
  87. const words = getRegisterWordsFromWordCache(register, wordCache)
  88. if (!words) return null
  89. return decodeRegisterValue(register, words)
  90. }
  91. function decodeRegisterFromByteCache(register, byteCache) {
  92. const bytes = getRegisterBytesFromByteCache(register, byteCache)
  93. if (!bytes) return null
  94. return decodeRegisterFromBytes(register, bytes)
  95. }
  96. function getRegisterEncodedWords(register) {
  97. return encodeRegisterWords({
  98. ...register,
  99. inputValue: getRegisterWriteValueText(register)
  100. })
  101. }
  102. function getRegisterEncodedBytes(register) {
  103. return encodeRegisterBytes({
  104. ...register,
  105. inputValue: getRegisterWriteValueText(register)
  106. })
  107. }
  108. function getRegisterByteStart(register, groupStartAddress = 0) {
  109. if (Number.isFinite(Number(register.byteStart))) {
  110. return Math.max(0, Math.floor(Number(register.byteStart)))
  111. }
  112. return Math.max(0, ((Number(register.address) || 0) - (Number(groupStartAddress) || 0)) * 2 + (Number(register.byteOffset) || 0))
  113. }
  114. function getGroupEncodedBytes(group, baseBytes = null) {
  115. const byteLength = Math.max(2, Number(group && group.paddedByteLength) || ((Number(group && group.wordQuantity) || 1) * 2))
  116. const bytes = Array.isArray(baseBytes)
  117. ? baseBytes.slice(0, byteLength).map((byte) => Number(byte) & 0xFF)
  118. : []
  119. const registers = Array.isArray(group && group.registers) ? group.registers : []
  120. while (bytes.length < byteLength) {
  121. bytes.push(0)
  122. }
  123. registers.forEach((register) => {
  124. const byteStart = getRegisterByteStart(register, group.startAddress)
  125. if (isBitFieldRegister(register)) {
  126. const encodedBytes = encodeBitFieldIntoBytes(
  127. {
  128. ...register,
  129. inputValue: getRegisterWriteValueText(register)
  130. },
  131. bytes,
  132. byteStart
  133. )
  134. if (!Array.isArray(encodedBytes)) {
  135. throw new Error(`${register.name || '位域'} 没有有效写入值`)
  136. }
  137. return
  138. }
  139. const registerBytes = encodeRegisterBytes(register)
  140. if (!Array.isArray(registerBytes) || !registerBytes.length) {
  141. throw new Error(`${register.name || '寄存器'} 没有有效写入值`)
  142. }
  143. for (let offset = 0; offset < register.byteLength; offset += 1) {
  144. if (byteStart + offset < bytes.length) {
  145. bytes[byteStart + offset] = Number(registerBytes[offset] || 0) & 0xFF
  146. }
  147. }
  148. })
  149. return bytes
  150. }
  151. function getGroupEncodedWords(group, baseBytes = null) {
  152. return bytesToWords(getGroupEncodedBytes(group, baseBytes))
  153. }
  154. function validateRegisterValue(register, value) {
  155. return validateCodecRegisterValue(
  156. register,
  157. value === undefined || value === null ? getRegisterWriteValueText(register) : value
  158. )
  159. }
  160. module.exports = {
  161. decodeRegisterFromByteCache,
  162. decodeRegisterFromBytes,
  163. decodeRegisterFromWordCache,
  164. getGroupEncodedBytes,
  165. getGroupEncodedWords,
  166. getRegisterBytesFromByteCache,
  167. getRegisterEncodedBytes,
  168. getRegisterEncodedWords,
  169. getRegisterWordsFromByteCache,
  170. getRegisterWordsFromWordCache,
  171. getRegisterWriteValueText,
  172. splitWordSpans,
  173. validateRegisterValue
  174. }