Parcourir la source

移除最小包长限制

avery il y a 4 jours
Parent
commit
83fb23df57

+ 0 - 1
features/settings/view-model.js

@@ -40,7 +40,6 @@ function getSettingsPageState(
     nightModeEnabledSwitch,
     statusPollMaxInterval: settingsService.STATUS_POLL_MAX_INTERVAL,
     statusPollMinInterval: settingsService.STATUS_POLL_MIN_INTERVAL,
-    parameterMinPacketLength: settingsService.PARAMETER_MIN_PACKET_LENGTH,
     protocolIndex,
     storageProtocolImplementationEntryMeta: '从机实现与结构体定义参考',
     storageProtocolImplementationView: protocolImplementation.VIEW_ID,

+ 2 - 1
features/storage-access/protocol-io.js

@@ -32,6 +32,7 @@ function normalizeProtocolIoOptions(options = {}) {
   const maxPacketLength = options.maxPacketLength === undefined ? options.maxFrameBytes : options.maxPacketLength
   const settings = settingsService.getState()
   const optionMemoryEndian = storageAccessProtocol.normalizeMemoryEndian(options.memoryEndian, '')
+  const syncedMemoryEndian = storageAccessProtocol.normalizeMemoryEndian(syncedDeviceCaps.memoryEndian, '')
   const defaultMemoryEndian = storageAccessProtocol.normalizeMemoryEndian(settings.storageAccessDefaultEndian)
 
   return {
@@ -39,7 +40,7 @@ function normalizeProtocolIoOptions(options = {}) {
     maxFrameBytes: options.useDeviceCaps === false
       ? getConfiguredMaxPacketLength(maxPacketLength)
       : resolveMaxPacketLength(maxPacketLength),
-    memoryEndian: optionMemoryEndian || defaultMemoryEndian,
+    memoryEndian: optionMemoryEndian || syncedMemoryEndian || defaultMemoryEndian,
     onChunk: options.onChunk,
     showModal: options.showModal !== false
   }

+ 1 - 1
pages/settings/settings.wxml

@@ -906,7 +906,7 @@
       <view class="settings-row settings-row--input">
         <view class="settings-row-main">
           <view class="param-name">最大包长</view>
-          <view class="param-meta">0 为无限制,最小 {{parameterMinPacketLength}} 字节</view>
+          <view class="param-meta">0 为无限制,按完整协议帧计算</view>
         </view>
         <view class="settings-input-wrap settings-input-wrap--unit">
           <input

+ 59 - 11
protocols/storage-access/index.js

@@ -183,6 +183,20 @@ function toUint32(value, label) {
   return value
 }
 
+function toAccessLength(value, label = '访问字节长度') {
+  const numberValue = Number(value)
+  if (!Number.isFinite(numberValue)) {
+    throw new Error(`${label}必须大于 0`)
+  }
+
+  const byteLength = Math.floor(numberValue)
+  if (byteLength <= 0) {
+    throw new Error(`${label}必须大于 0`)
+  }
+
+  return byteLength
+}
+
 function normalizeArea(value) {
   if (typeof value === 'string') {
     const area = AREA_BY_NAME[value.trim().toUpperCase()]
@@ -205,6 +219,30 @@ function getAddressFieldByteLength(area) {
   return isAddress32Area(area) ? ADDRESS32_BYTE_LENGTH : ADDRESS16_BYTE_LENGTH
 }
 
+function getAddressMaxValue(area) {
+  return getAddressFieldByteLength(area) === ADDRESS32_BYTE_LENGTH ? MAX_UINT32 : MAX_UINT16
+}
+
+function validateMemoryAccessRange(area, address, byteLength, label = '访问') {
+  const normalizedArea = normalizeMemoryArea(area)
+  const addressBytes = getAddressFieldByteLength(normalizedArea)
+  const startAddress = addressBytes === ADDRESS32_BYTE_LENGTH
+    ? toUint32(Number(address), '内存地址')
+    : toWord(Number(address), '内存地址')
+  const length = toAccessLength(byteLength, `${label}字节长度`)
+  const maxAddress = getAddressMaxValue(normalizedArea)
+  const endAddress = startAddress + length - 1
+
+  if (endAddress > maxAddress) {
+    throw new Error(`${label}范围超过 0x${formatHexNumber(maxAddress, addressBytes * 2)} 地址上限`)
+  }
+
+  return {
+    length,
+    startAddress
+  }
+}
+
 function getMemoryHeaderLength(area) {
   return 1 + getAddressFieldByteLength(area) + 2
 }
@@ -392,16 +430,15 @@ function buildReadFrame(area, address, byteLength, options = {}) {
   }
 
   const memoryEndian = normalizeMemoryEndian(options.memoryEndian)
-  const addressBytes = getAddressFieldByteLength(normalizedArea)
-  const startAddress = addressBytes === ADDRESS32_BYTE_LENGTH
-    ? toUint32(Number(address), '内存地址')
-    : toWord(Number(address), '内存地址')
   const maxByteLength = getRequiredPayloadLimit(
     options.maxFrameBytes,
     getReadResponseOverhead(normalizedArea),
     '读取 1 字节'
   )
   const length = toByteLength(Number(byteLength), '读取字节长度', maxByteLength || MAX_PAYLOAD_BYTES)
+  const addressBytes = getAddressFieldByteLength(normalizedArea)
+  const range = validateMemoryAccessRange(normalizedArea, address, length, '读取')
+  const startAddress = range.startAddress
   const command = buildCommand(normalizedArea, false)
   const addressParts = addressBytes === ADDRESS32_BYTE_LENGTH
     ? splitDword(startAddress, memoryEndian)
@@ -418,10 +455,6 @@ function buildWriteFrame(area, address, bytes, options = {}) {
   }
 
   const memoryEndian = normalizeMemoryEndian(options.memoryEndian)
-  const addressBytes = getAddressFieldByteLength(normalizedArea)
-  const startAddress = addressBytes === ADDRESS32_BYTE_LENGTH
-    ? toUint32(Number(address), '内存地址')
-    : toWord(Number(address), '内存地址')
   const dataBytes = toByteArray(bytes).map((byte) => toByte(Number(byte), '写入字节'))
   const maxByteLength = getRequiredPayloadLimit(
     options.maxFrameBytes,
@@ -429,6 +462,9 @@ function buildWriteFrame(area, address, bytes, options = {}) {
     '写入 1 字节'
   )
   const length = toByteLength(dataBytes.length, '写入字节长度', maxByteLength || MAX_PAYLOAD_BYTES)
+  const addressBytes = getAddressFieldByteLength(normalizedArea)
+  const range = validateMemoryAccessRange(normalizedArea, address, length, '写入')
+  const startAddress = range.startAddress
   const command = buildCommand(normalizedArea, true)
   const addressParts = addressBytes === ADDRESS32_BYTE_LENGTH
     ? splitDword(startAddress, memoryEndian)
@@ -837,7 +873,17 @@ function readResponseFromBuffer(buffer, expected, options = {}) {
     }
 
     const frameBytes = buffer.slice(0, responseLength)
-    const response = parseStorageAccessResponse(frameBytes, expected)
+    let response
+    try {
+      response = parseStorageAccessResponse(frameBytes, expected)
+    } catch (error) {
+      return {
+        frameBytes,
+        message: error && error.message ? error.message : '存储访问响应帧解析失败',
+        status: 'invalid'
+      }
+    }
+
     if (!response) {
       return {
         frameBytes,
@@ -951,24 +997,26 @@ function getReadChunks(startAddress, byteLength, options = {}) {
       quantity: CODE_INFO_DESCRIPTOR_BYTE_LENGTH
     }]
   }
+  const range = validateMemoryAccessRange(normalizedArea, startAddress, byteLength, '读取')
   const maxByteLength = getRequiredPayloadLimit(
     options.maxFrameBytes,
     getReadResponseOverhead(normalizedArea),
     '读取 1 字节'
   )
 
-  return splitQuantity(startAddress, byteLength, maxByteLength)
+  return splitQuantity(range.startAddress, range.length, maxByteLength)
 }
 
 function getWriteChunks(startAddress, bytes, options = {}) {
   const sourceBytes = Array.prototype.slice.call(bytes || []).map((byte) => Number(byte) & 0xFF)
   const normalizedArea = normalizeMemoryArea(options.area === undefined ? AREA.ADDR32 : options.area)
+  const range = validateMemoryAccessRange(normalizedArea, startAddress, sourceBytes.length, '写入')
   const maxByteLength = getRequiredPayloadLimit(
     options.maxFrameBytes,
     getWriteRequestOverhead(normalizedArea),
     '写入 1 字节'
   )
-  const chunks = splitQuantity(startAddress, sourceBytes.length, maxByteLength)
+  const chunks = splitQuantity(range.startAddress, range.length, maxByteLength)
   let offset = 0
 
   return chunks.map((chunk) => {

+ 1 - 3
store/settings-store.js

@@ -31,7 +31,6 @@ const DEFAULT_SETTINGS = {
 }
 const STATUS_POLL_MIN_INTERVAL = 100
 const STATUS_POLL_MAX_INTERVAL = 3000
-const PARAMETER_MIN_PACKET_LENGTH = 14
 
 const state = {
   ...DEFAULT_SETTINGS
@@ -47,7 +46,7 @@ function normalizeParameterPacketLength(value, fallback = DEFAULT_SETTINGS.param
   const rounded = Math.round(numberValue)
   if (rounded <= 0) return 0
 
-  return Math.max(rounded, PARAMETER_MIN_PACKET_LENGTH)
+  return rounded
 }
 
 function normalizeStorageAccessEndian(value, fallback = DEFAULT_SETTINGS.storageAccessDefaultEndian) {
@@ -233,7 +232,6 @@ function setStorageAccessDefaultEndian(value) {
 }
 
 module.exports = {
-  PARAMETER_MIN_PACKET_LENGTH,
   PROTOCOL_MODE,
   PROTOCOL_OPTIONS,
   STATUS_POLL_MAX_INTERVAL,

+ 3 - 1
transport/ble-core.js

@@ -426,7 +426,9 @@ function consumePendingResponseBuffer() {
   }
 
   if (result.status === 'invalid') {
-    const content = `${pending.label} 收到无效响应帧,已丢弃`
+    const content = result.message
+      ? `${pending.label} 收到无效响应帧:${result.message}`
+      : `${pending.label} 收到无效响应帧,已丢弃`
     addLog('SYS', content)
     finishPendingRequest(false)
     if (pending.showModal) {