const storageAccessProtocol = require('../../protocols/storage-access/index.js') const transport = require('../../transport/ble-core.js') const { formatHexNumber } = require('../../utils/binary-utils.js') const { createGroupsFromCodeInfo, parseCodeInfo } = require('../../domain/storage-access/code-info-parser.js') const { cloneImportedGroup, normalizeGroup } = require('../../domain/parameter-groups/model.js') const protocolIo = require('./protocol-io.js') function showCodeInfoError(label, message, options = {}) { if (options.showModal === false) return transport.showCommandAlert(label, message) } async function readCodeInfoBlock(label = '同步CodeInfo', kind = 'storage-code-info-read', options = {}) { const protocolIoOptions = protocolIo.normalizeProtocolIoOptions({ ...options, useDeviceCaps: false }) const descriptorBytes = await protocolIo.readMemory( storageAccessProtocol.AREA.CODEINFO, storageAccessProtocol.CODE_INFO_DESCRIPTOR_ADDRESS, storageAccessProtocol.CODE_INFO_DESCRIPTOR_BYTE_LENGTH, label, `${kind}-descriptor`, { ...protocolIoOptions, showModal: false, useDeviceCaps: false } ) if (!descriptorBytes) { showCodeInfoError(label, 'CodeInfo 描述符读取失败或超时', protocolIoOptions) return null } let descriptor try { descriptor = storageAccessProtocol.parseCodeInfoDescriptorBytes(descriptorBytes) } catch (error) { showCodeInfoError(label, error.message || 'CodeInfo 描述符长度无效', protocolIoOptions) return null } let codeInfoAddressWidth try { codeInfoAddressWidth = storageAccessProtocol.normalizeDescriptorAddressWidth( descriptor.codeInfoAddressWidth ) } catch (error) { showCodeInfoError(label, error.message || 'CodeInfo 描述符地址长度无效', protocolIoOptions) return null } const codeInfoAddress = Number(descriptor.codeInfoAddress || 0) const codeInfoByteLength = Number(descriptor.codeInfoByteLength || 0) const codeInfoMaxPacketLength = Number(descriptor.codeInfoMaxPacketLength || 0) & 0xFFFF const codeInfoMemoryEndian = String(descriptor.codeInfoMemoryEndian || 'big').trim() const codeInfoMemoryType = codeInfoAddressWidth === 32 ? storageAccessProtocol.AREA.ADDR32 : storageAccessProtocol.AREA.CODE const codeInfoReadAddress = codeInfoAddressWidth === 32 ? codeInfoAddress : (codeInfoAddress & 0xFFFF) const codeInfoMaxFrameBytes = storageAccessProtocol.resolveDescriptorMaxFrameBytes( protocolIoOptions.maxFrameBytes, codeInfoMaxPacketLength ) if (!codeInfoByteLength || codeInfoByteLength > 0xFFFF) { showCodeInfoError(label, 'CodeInfo 信息块长度无效', protocolIoOptions) return null } const codeInfoBytes = await protocolIo.readMemory( codeInfoMemoryType, codeInfoReadAddress, codeInfoByteLength, label, kind, { ...protocolIoOptions, maxFrameBytes: codeInfoMaxFrameBytes, useDeviceCaps: false } ) if (!codeInfoBytes) return null return { codeInfoAddress, codeInfoAddressWidth, codeInfoByteLength, codeInfoBytes, codeInfoDescriptorBytes: descriptorBytes, codeInfoMaxPacketLength, codeInfoMemoryEndian, codeInfoMemoryEndianMark: Number(descriptor.codeInfoMemoryEndianMark || 0) & 0xFFFF, codeInfoMemoryType } } async function syncCodeInfo(options = {}) { const result = await readCodeInfoBlock( options.label || '同步CodeInfo', options.kind || 'storage-code-info-read', { maxPacketLength: options.maxPacketLength, showModal: options.showModal !== false } ) if (!result) { return { ok: false } } const descriptorCaps = { addressWidth: result.codeInfoAddressWidth, codeInfoByteLength: result.codeInfoByteLength, maxPacketLength: result.codeInfoMaxPacketLength, memoryEndian: result.codeInfoMemoryEndian, memoryEndianMark: result.codeInfoMemoryEndianMark } let codeInfo let importedGroups try { codeInfo = parseCodeInfo(result.codeInfoBytes, descriptorCaps) importedGroups = createGroupsFromCodeInfo(codeInfo, options) .map(cloneImportedGroup) .map(normalizeGroup) } catch (error) { const errorText = error.message || 'CodeInfo 解析失败' showCodeInfoError(options.label || '同步CodeInfo', errorText, options) return { errorText, ok: false } } protocolIo.updateSyncedDeviceCaps(descriptorCaps) return { codeInfoAddress: result.codeInfoAddress, codeInfoAddressText: formatHexNumber(result.codeInfoAddress, 8), codeInfoAddressWidth: result.codeInfoAddressWidth, codeInfoByteLength: result.codeInfoByteLength, codeInfoByteLengthText: formatHexNumber(result.codeInfoByteLength, 8), codeInfoBytes: result.codeInfoBytes, codeInfo, codeInfoDescriptorBytes: result.codeInfoDescriptorBytes, codeInfoMaxPacketLength: result.codeInfoMaxPacketLength, codeInfoMemoryEndian: result.codeInfoMemoryEndian, codeInfoMemoryEndianMark: result.codeInfoMemoryEndianMark, codeInfoMemoryType: result.codeInfoMemoryType, groupCount: importedGroups.length, importedGroups, ok: true, structCount: codeInfo.structCount } } module.exports = { readCodeInfoBlock, syncCodeInfo }