1
0

protocol-io.js 5.8 KB

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