storage-access-io.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. const {
  2. bytesToWords
  3. } = require('../../utils/binary-utils.js')
  4. const transport = require('../../transport/ble-core.js')
  5. const storageAccessMemory = require('../storage-access/memory-service.js')
  6. const {
  7. decodeRegisterFromByteCache,
  8. decodeRegisterValue,
  9. formatRegisterValue,
  10. getGroupEncodedBytes,
  11. getRegisterBytesFromByteCache,
  12. getRegisterEncodedBytes,
  13. getRegisterWordsFromByteCache,
  14. getRegisterWordsFromWordCache
  15. } = require('../../domain/parameter-groups/model.js')
  16. const STORAGE_ACCESS_MEMORY_TYPES = {
  17. DATA: 0x01,
  18. BIT: 0x01,
  19. IDATA: 0x02,
  20. XDATA: 0x03,
  21. CODE: 0x04
  22. }
  23. const STORAGE_ACCESS_CODE_AREA = 0x04
  24. function getMemoryType(group = {}) {
  25. const memoryArea = String(group.sourceMemoryArea || '').trim().toUpperCase()
  26. return Object.prototype.hasOwnProperty.call(STORAGE_ACCESS_MEMORY_TYPES, memoryArea)
  27. ? STORAGE_ACCESS_MEMORY_TYPES[memoryArea]
  28. : null
  29. }
  30. function isMemoryGroup(group = {}) {
  31. return getMemoryType(group) !== null
  32. }
  33. function isByteAddressedGroup(group = {}) {
  34. return group.addressUnit === 'byte' || group.addressUnit === 'bytes' || isMemoryGroup(group)
  35. }
  36. function getMemoryAddress(group = {}) {
  37. const sourceAddress = Number(group.sourceAddress)
  38. if (Number.isFinite(sourceAddress)) return Math.max(0, Math.floor(sourceAddress)) & 0xFFFF
  39. return Math.max(0, Number(group.startAddress) || 0) & 0xFFFF
  40. }
  41. function getMemoryByteLength(group = {}) {
  42. const sourceByteLength = Number(group.sourceByteLength)
  43. if (Number.isFinite(sourceByteLength) && sourceByteLength > 0) return Math.min(0xFFFF, Math.ceil(sourceByteLength))
  44. const byteLength = Number(group.byteLength)
  45. if (Number.isFinite(byteLength) && byteLength > 0) return Math.min(0xFFFF, Math.ceil(byteLength))
  46. return Math.max(1, Math.ceil((Number(group.wordQuantity) || 1) * 2))
  47. }
  48. function bytesToPaddedWords(bytes = []) {
  49. return bytesToWords(bytes.length % 2 === 0 ? bytes : bytes.concat(0))
  50. }
  51. function fillByteCacheFromBytes(byteCache, startAddress, bytes = []) {
  52. bytes.forEach((byte, offset) => {
  53. byteCache[startAddress + offset] = Number(byte) & 0xFF
  54. })
  55. }
  56. function fillWordCacheFromBytes(wordCache, startAddress, bytes = []) {
  57. const words = bytesToPaddedWords(bytes)
  58. words.forEach((word, offset) => {
  59. wordCache[startAddress + offset] = Number(word) & 0xFFFF
  60. })
  61. }
  62. function createWrittenRegisterSnapshots(group, wordCache) {
  63. return group.registers.map((register) => {
  64. const rawBytes = isByteAddressedGroup(group)
  65. ? (getRegisterBytesFromByteCache(register, wordCache) || [])
  66. : []
  67. const rawWords = isByteAddressedGroup(group)
  68. ? (getRegisterWordsFromByteCache(register, wordCache) || [])
  69. : (getRegisterWordsFromWordCache(register, wordCache) || [])
  70. const rawValue = isByteAddressedGroup(group)
  71. ? decodeRegisterFromByteCache(register, wordCache)
  72. : decodeRegisterValue(register, rawWords)
  73. return {
  74. rawBytes,
  75. rawWords,
  76. rawValue,
  77. displayValue: formatRegisterValue(register, rawValue)
  78. }
  79. })
  80. }
  81. function createWrittenRegisterSnapshot(group, register, byteCache) {
  82. const snapshots = createWrittenRegisterSnapshots({
  83. ...group,
  84. registers: [register]
  85. }, byteCache)
  86. return snapshots[0] || null
  87. }
  88. function groupHasBitFields(group = {}) {
  89. return (Array.isArray(group.registers) ? group.registers : []).some((register) => !!register.isBitField)
  90. }
  91. async function writeMemoryRegister(group, register, options = {}) {
  92. const memoryType = getMemoryType(group)
  93. const maxPacketLength = storageAccessMemory.resolveMaxPacketLength(options.maxPacketLength)
  94. const byteLength = Math.max(1, Number(register.byteLength) || 1)
  95. const address = Math.max(0, Math.floor(Number(register.address) || getMemoryAddress(group))) & 0xFFFF
  96. let bytes
  97. if (memoryType === null) {
  98. transport.showCommandAlert('内存写入', `暂不支持 ${group.sourceMemoryArea || '未知'} 内存区域`)
  99. return null
  100. }
  101. if (memoryType === STORAGE_ACCESS_CODE_AREA) {
  102. transport.showCommandAlert('内存写入', 'code 区暂不支持写入')
  103. return null
  104. }
  105. try {
  106. if (register.isBitField) {
  107. const baseBytes = await storageAccessMemory.readMemory(
  108. memoryType,
  109. address,
  110. byteLength,
  111. register.name ? `${register.name} 读改写` : '变量读改写',
  112. 'parameter-group-memory-register-rmw-read',
  113. {
  114. maxFrameBytes: maxPacketLength
  115. }
  116. )
  117. if (!baseBytes) return null
  118. bytes = getGroupEncodedBytes({
  119. ...group,
  120. paddedByteLength: byteLength,
  121. registers: [{
  122. ...register,
  123. address,
  124. byteStart: 0
  125. }]
  126. }, baseBytes).slice(0, byteLength)
  127. } else {
  128. bytes = getRegisterEncodedBytes(register)
  129. }
  130. } catch (error) {
  131. transport.showCommandAlert('内存写入', error.message || '变量没有有效写入值')
  132. return null
  133. }
  134. if (!Array.isArray(bytes) || !bytes.length) {
  135. transport.showCommandAlert('内存写入', `${register.name || '变量'} 没有有效写入值`)
  136. return null
  137. }
  138. bytes = bytes.slice(0, byteLength)
  139. while (bytes.length < byteLength) bytes.push(0)
  140. const ok = await storageAccessMemory.writeMemory(
  141. memoryType,
  142. address,
  143. bytes,
  144. register.name || group.name || '变量写入',
  145. 'parameter-group-memory-register-write',
  146. {
  147. maxFrameBytes: maxPacketLength
  148. }
  149. )
  150. if (!ok) return null
  151. const byteCache = {}
  152. fillByteCacheFromBytes(byteCache, address, bytes)
  153. return createWrittenRegisterSnapshot(group, register, byteCache)
  154. }
  155. async function readMemoryGroup(group, options = {}) {
  156. const memoryType = getMemoryType(group)
  157. const address = getMemoryAddress(group)
  158. const byteLength = getMemoryByteLength(group)
  159. const maxPacketLength = storageAccessMemory.resolveMaxPacketLength(options.maxPacketLength)
  160. if (memoryType === null) {
  161. transport.showCommandAlert('内存读取', `暂不支持 ${group.sourceMemoryArea || '未知'} 内存区域`)
  162. return null
  163. }
  164. const bytes = await storageAccessMemory.readMemory(
  165. memoryType,
  166. address,
  167. byteLength,
  168. group.name || '内存读取',
  169. 'parameter-group-memory-read',
  170. {
  171. maxFrameBytes: maxPacketLength,
  172. showModal: options.showModal !== false
  173. }
  174. )
  175. if (!bytes) return null
  176. const wordCache = {}
  177. if (isByteAddressedGroup(group)) {
  178. fillByteCacheFromBytes(wordCache, address, bytes)
  179. } else {
  180. fillWordCacheFromBytes(wordCache, address, bytes)
  181. }
  182. return wordCache
  183. }
  184. async function writeMemoryGroup(group, options = {}) {
  185. const memoryType = getMemoryType(group)
  186. const address = getMemoryAddress(group)
  187. const byteLength = getMemoryByteLength(group)
  188. const maxPacketLength = storageAccessMemory.resolveMaxPacketLength(options.maxPacketLength)
  189. let bytes
  190. if (memoryType === null) {
  191. transport.showCommandAlert('内存写入', `暂不支持 ${group.sourceMemoryArea || '未知'} 内存区域`)
  192. return null
  193. }
  194. if (memoryType === STORAGE_ACCESS_CODE_AREA) {
  195. transport.showCommandAlert('内存写入', 'code 区暂不支持写入')
  196. return null
  197. }
  198. try {
  199. let baseBytes = null
  200. if (groupHasBitFields(group)) {
  201. baseBytes = await storageAccessMemory.readMemory(
  202. memoryType,
  203. address,
  204. byteLength,
  205. group.name ? `${group.name} 读改写` : '内存读改写',
  206. 'parameter-group-memory-rmw-read',
  207. {
  208. maxFrameBytes: maxPacketLength
  209. }
  210. )
  211. if (!baseBytes) return null
  212. }
  213. bytes = getGroupEncodedBytes(group, baseBytes)
  214. } catch (error) {
  215. transport.showCommandAlert('内存写入', error.message || '寄存器组没有有效写入值')
  216. return null
  217. }
  218. bytes = bytes.slice(0, byteLength)
  219. const ok = await storageAccessMemory.writeMemory(
  220. memoryType,
  221. address,
  222. bytes,
  223. group.name || '内存写入',
  224. 'parameter-group-memory-write',
  225. {
  226. maxFrameBytes: maxPacketLength
  227. }
  228. )
  229. if (!ok) return null
  230. const wordCache = {}
  231. if (isByteAddressedGroup(group)) {
  232. fillByteCacheFromBytes(wordCache, address, bytes)
  233. } else {
  234. fillWordCacheFromBytes(wordCache, address, bytes)
  235. }
  236. return createWrittenRegisterSnapshots(group, wordCache)
  237. }
  238. module.exports = {
  239. getMemoryAddress,
  240. getMemoryByteLength,
  241. getMemoryType,
  242. isByteAddressedGroup,
  243. isMemoryGroup,
  244. readMemoryGroup,
  245. writeMemoryGroup,
  246. writeMemoryRegister
  247. }