1
0

protocol-io.js 5.2 KB

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