value-number.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. const {
  2. formatFixedValue
  3. } = require('../../utils/number-format.js')
  4. const {
  5. getDataType,
  6. isHexRegister
  7. } = require('./value-types.js')
  8. function padWordHex(value) {
  9. return Number(value || 0).toString(16).toUpperCase().padStart(4, '0')
  10. }
  11. function formatIntegerValue(value, dataType) {
  12. const type = getDataType(dataType).key
  13. const numberValue = Number(value)
  14. if (!Number.isFinite(numberValue)) return '--'
  15. if (type === 'int8_t') return String(((Math.round(numberValue) << 24) >> 24))
  16. if (type === 'uint8_t') return String(Math.round(numberValue) & 0xFF)
  17. if (type === 'int16_t') return String(((Math.round(numberValue) << 16) >> 16))
  18. if (type === 'uint16_t') return String(Math.round(numberValue) & 0xFFFF)
  19. if (type === 'int32_t') return String((Math.round(numberValue) | 0))
  20. if (type === 'uint32_t') return String(Math.round(numberValue) >>> 0)
  21. return String(Math.round(numberValue))
  22. }
  23. function formatHexValue(value) {
  24. const numberValue = Number(value)
  25. if (!Number.isFinite(numberValue)) return '--'
  26. return `0x${padWordHex(Math.round(numberValue) & 0xFFFF)}`
  27. }
  28. function formatFloatValue(value) {
  29. return formatFixedValue(value, 6).replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '')
  30. }
  31. function parseIntegerText(value) {
  32. const text = String(value === undefined || value === null ? '' : value).trim()
  33. if (!text) return null
  34. const isHex = /^[-+]?0x[0-9a-f]+$/i.test(text) || /^0x[0-9a-f]+$/i.test(text)
  35. const parsed = isHex ? parseInt(text, 16) : Number(text)
  36. return Number.isFinite(parsed) ? parsed : null
  37. }
  38. function parseHexText(value) {
  39. const text = String(value === undefined || value === null ? '' : value).trim()
  40. if (!text) return null
  41. const hexText = text.toUpperCase().startsWith('0X') ? text.slice(2) : text
  42. if (/^[0-9A-F]{1,4}$/i.test(hexText)) {
  43. const parsedHex = parseInt(hexText, 16)
  44. return Number.isFinite(parsedHex) ? parsedHex : null
  45. }
  46. return null
  47. }
  48. function getNumericRange(dataType) {
  49. const type = getDataType(dataType).key
  50. if (type === 'int8_t') return { max: 127, min: -128 }
  51. if (type === 'uint8_t') return { max: 0xFF, min: 0 }
  52. if (type === 'int16_t') return { max: 32767, min: -32768 }
  53. if (type === 'uint16_t') return { max: 0xFFFF, min: 0 }
  54. if (type === 'int32_t') return { max: 2147483647, min: -2147483648 }
  55. if (type === 'uint32_t') return { max: 0xFFFFFFFF, min: 0 }
  56. if (type === 'hex') return { max: 0xFFFF, min: 0 }
  57. return { max: Number.POSITIVE_INFINITY, min: Number.NEGATIVE_INFINITY }
  58. }
  59. function parseNumberText(value, dataType) {
  60. const text = String(value === undefined || value === null ? '' : value).trim()
  61. if (!text || text === '--') return null
  62. if (getDataType(dataType).key === 'float') {
  63. const parsed = Number(text)
  64. return Number.isFinite(parsed) ? parsed : null
  65. }
  66. if (isHexRegister(dataType)) return parseHexText(text)
  67. return parseIntegerText(text)
  68. }
  69. function parseRangeBoundary(value, dataType, label) {
  70. const text = String(value === undefined || value === null ? '' : value).trim()
  71. if (!text) return null
  72. const parsed = parseNumberText(text, dataType)
  73. if (parsed === null) {
  74. throw new Error(`${label}无效`)
  75. }
  76. return parsed
  77. }
  78. function validateNumericValue(register, value) {
  79. const dataType = getDataType(register.dataType).key
  80. const range = getNumericRange(dataType)
  81. const numberValue = Number(value)
  82. if (!Number.isFinite(numberValue)) return false
  83. if (dataType !== 'float' && Math.round(numberValue) !== numberValue) {
  84. throw new Error(`${register.name || '寄存器'} 需要整数`)
  85. }
  86. if (numberValue < range.min || numberValue > range.max) {
  87. throw new Error(`${register.name || '寄存器'} 超出 ${dataType} 范围`)
  88. }
  89. const minValue = parseRangeBoundary(register.minValue, dataType, `${register.name || '寄存器'} 最小值`)
  90. const maxValue = parseRangeBoundary(register.maxValue, dataType, `${register.name || '寄存器'} 最大值`)
  91. if (minValue !== null && numberValue < minValue) {
  92. throw new Error(`${register.name || '寄存器'} 小于限制最小值`)
  93. }
  94. if (maxValue !== null && numberValue > maxValue) {
  95. throw new Error(`${register.name || '寄存器'} 大于限制最大值`)
  96. }
  97. return true
  98. }
  99. function floatToBytes(value) {
  100. const buffer = new ArrayBuffer(4)
  101. const view = new DataView(buffer)
  102. view.setFloat32(0, Number(value), false)
  103. return [
  104. view.getUint8(0),
  105. view.getUint8(1),
  106. view.getUint8(2),
  107. view.getUint8(3)
  108. ]
  109. }
  110. function bytesToFloatValue(bytes) {
  111. if (!Array.isArray(bytes) || bytes.length < 4) return null
  112. const buffer = new ArrayBuffer(4)
  113. const view = new DataView(buffer)
  114. for (let index = 0; index < 4; index += 1) {
  115. view.setUint8(index, Number(bytes[index]) & 0xFF)
  116. }
  117. return view.getFloat32(0, false)
  118. }
  119. function unsignedIntegerToBytes(value, byteLength) {
  120. let numberValue = Math.round(Number(value) || 0)
  121. const bytes = []
  122. if (numberValue < 0) {
  123. numberValue += Math.pow(2, byteLength * 8)
  124. }
  125. for (let index = byteLength - 1; index >= 0; index -= 1) {
  126. bytes[index] = numberValue & 0xFF
  127. numberValue = Math.floor(numberValue / 0x100)
  128. }
  129. return bytes
  130. }
  131. function bytesToUnsignedInteger(bytes) {
  132. return bytes.reduce((value, byte) => ((value * 0x100) + (Number(byte) & 0xFF)), 0)
  133. }
  134. function bytesToSignedInteger(bytes) {
  135. const unsignedValue = bytesToUnsignedInteger(bytes)
  136. const signLimit = Math.pow(2, bytes.length * 8 - 1)
  137. const fullRange = Math.pow(2, bytes.length * 8)
  138. return unsignedValue >= signLimit ? unsignedValue - fullRange : unsignedValue
  139. }
  140. module.exports = {
  141. bytesToFloatValue,
  142. bytesToSignedInteger,
  143. bytesToUnsignedInteger,
  144. floatToBytes,
  145. formatFloatValue,
  146. formatHexValue,
  147. formatIntegerValue,
  148. getNumericRange,
  149. parseHexText,
  150. parseIntegerText,
  151. parseNumberText,
  152. parseRangeBoundary,
  153. unsignedIntegerToBytes,
  154. validateNumericValue
  155. }