protocol-io.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. const storageAccessProtocol = require('../../protocols/storage-access/index.js')
  2. const settingsService = require('../../store/settings-store.js')
  3. const transport = require('../../transport/ble-core.js')
  4. let syncedDeviceCaps = {
  5. addressWidth: 0,
  6. maxPacketLength: 0,
  7. memoryEndian: ''
  8. }
  9. function getConfiguredMaxPacketLength(value) {
  10. const settings = settingsService.getState()
  11. const numberValue = Number(value === undefined ? settings.parameterMaxPacketLength : value)
  12. if (Number.isFinite(numberValue) && Math.round(numberValue) === 0) return 0
  13. if (Number.isFinite(numberValue) && numberValue > 0) return Math.round(numberValue)
  14. return 64
  15. }
  16. function resolveMaxPacketLength(value) {
  17. const configuredMaxPacketLength = getConfiguredMaxPacketLength(value)
  18. const deviceMaxPacketLength = Number(syncedDeviceCaps.maxPacketLength || 0)
  19. if (!Number.isFinite(deviceMaxPacketLength) || deviceMaxPacketLength <= 0) return configuredMaxPacketLength
  20. if (configuredMaxPacketLength === 0) return Math.round(deviceMaxPacketLength)
  21. return Math.min(configuredMaxPacketLength, Math.round(deviceMaxPacketLength))
  22. }
  23. function normalizeProtocolIoOptions(options = {}) {
  24. const maxPacketLength = options.maxPacketLength === undefined ? options.maxFrameBytes : options.maxPacketLength
  25. const settings = settingsService.getState()
  26. const optionMemoryEndian = storageAccessProtocol.normalizeMemoryEndian(options.memoryEndian, '')
  27. const syncedMemoryEndian = storageAccessProtocol.normalizeMemoryEndian(syncedDeviceCaps.memoryEndian, '')
  28. const defaultMemoryEndian = storageAccessProtocol.normalizeMemoryEndian(settings.storageAccessDefaultEndian)
  29. return {
  30. expectedByteLength: options.expectedByteLength,
  31. maxFrameBytes: options.useDeviceCaps === false
  32. ? getConfiguredMaxPacketLength(maxPacketLength)
  33. : resolveMaxPacketLength(maxPacketLength),
  34. memoryEndian: optionMemoryEndian || syncedMemoryEndian || defaultMemoryEndian,
  35. onChunk: options.onChunk,
  36. showModal: options.showModal !== false
  37. }
  38. }
  39. function updateSyncedDeviceCaps(caps = {}) {
  40. const addressWidth = Number(caps.addressWidth)
  41. const maxPacketLength = Number(caps.maxPacketLength)
  42. const memoryEndian = String(caps.memoryEndian || '').trim().toLowerCase()
  43. syncedDeviceCaps = {
  44. addressWidth: addressWidth === 16 || addressWidth === 32 ? addressWidth : 0,
  45. maxPacketLength: Number.isFinite(maxPacketLength) && maxPacketLength > 0
  46. ? Math.round(maxPacketLength)
  47. : 0,
  48. memoryEndian: memoryEndian === 'little' ? 'little' : (memoryEndian === 'big' ? 'big' : '')
  49. }
  50. }
  51. function getSyncedDeviceCaps() {
  52. return {
  53. ...syncedDeviceCaps
  54. }
  55. }
  56. function createTransportOptions(protocolIoOptions = {}) {
  57. return {
  58. maxFrameBytes: protocolIoOptions.maxFrameBytes,
  59. showModal: protocolIoOptions.showModal
  60. }
  61. }
  62. function notifyChunk(protocolIoOptions = {}, response, chunk) {
  63. if (typeof protocolIoOptions.onChunk === 'function') {
  64. protocolIoOptions.onChunk(response, chunk)
  65. }
  66. }
  67. function sendStorageFrame(frameBytes, label, expected, protocolIoOptions = {}) {
  68. return transport.sendManagedFrame(
  69. frameBytes,
  70. label,
  71. expected,
  72. createTransportOptions(protocolIoOptions)
  73. )
  74. }
  75. async function readMemory(area, startAddress, byteLength, label, kind, options = {}) {
  76. const protocolIoOptions = normalizeProtocolIoOptions(options)
  77. const normalizedArea = storageAccessProtocol.normalizeMemoryArea(area)
  78. const bytes = []
  79. const chunks = storageAccessProtocol.getReadChunks(startAddress, byteLength, {
  80. ...protocolIoOptions,
  81. area: normalizedArea
  82. })
  83. for (const chunk of chunks) {
  84. const response = await sendStorageFrame(
  85. storageAccessProtocol.buildReadFrame(normalizedArea, chunk.address, chunk.quantity, {
  86. maxFrameBytes: protocolIoOptions.maxFrameBytes,
  87. memoryEndian: protocolIoOptions.memoryEndian
  88. }),
  89. storageAccessProtocol.getChunkLabel(label, chunks, chunk),
  90. storageAccessProtocol.createExpected(normalizedArea, chunk.address, chunk.quantity, false, kind, {
  91. memoryEndian: protocolIoOptions.memoryEndian
  92. }),
  93. protocolIoOptions
  94. )
  95. if (!response) return null
  96. const dataBytes = Array.isArray(response.dataBytes) ? response.dataBytes : []
  97. dataBytes.forEach((byte, index) => {
  98. bytes[chunk.address - startAddress + index] = Number(byte) & 0xFF
  99. })
  100. notifyChunk(protocolIoOptions, response, chunk)
  101. }
  102. return bytes
  103. }
  104. async function writeMemory(area, startAddress, bytes, label, kind, options = {}) {
  105. const protocolIoOptions = normalizeProtocolIoOptions(options)
  106. const normalizedArea = storageAccessProtocol.normalizeMemoryArea(area)
  107. const chunks = storageAccessProtocol.getWriteChunks(startAddress, bytes, {
  108. ...protocolIoOptions,
  109. area: normalizedArea
  110. })
  111. for (const chunk of chunks) {
  112. const response = await sendStorageFrame(
  113. storageAccessProtocol.buildWriteFrame(normalizedArea, chunk.address, chunk.dataBytes, {
  114. maxFrameBytes: protocolIoOptions.maxFrameBytes,
  115. memoryEndian: protocolIoOptions.memoryEndian
  116. }),
  117. storageAccessProtocol.getChunkLabel(label, chunks, chunk),
  118. storageAccessProtocol.createExpected(normalizedArea, chunk.address, chunk.quantity, true, kind, {
  119. memoryEndian: protocolIoOptions.memoryEndian
  120. }),
  121. protocolIoOptions
  122. )
  123. if (!response) return false
  124. notifyChunk(protocolIoOptions, response, chunk)
  125. }
  126. return true
  127. }
  128. async function executeControl(operation, dataBytes, label, kind, options = {}) {
  129. const protocolIoOptions = normalizeProtocolIoOptions(options)
  130. const response = await sendStorageFrame(
  131. storageAccessProtocol.buildControlFrame(operation, dataBytes),
  132. label,
  133. storageAccessProtocol.createControlExpected(operation, kind, {
  134. expectedByteLength: protocolIoOptions.expectedByteLength
  135. }),
  136. protocolIoOptions
  137. )
  138. return response || null
  139. }
  140. module.exports = {
  141. executeControl,
  142. getSyncedDeviceCaps,
  143. normalizeProtocolIoOptions,
  144. readMemory,
  145. resolveMaxPacketLength,
  146. updateSyncedDeviceCaps,
  147. writeMemory
  148. }