|
@@ -1,6 +1,10 @@
|
|
|
const {
|
|
const {
|
|
|
bytesToHex,
|
|
bytesToHex,
|
|
|
bytesToUtf8Text,
|
|
bytesToUtf8Text,
|
|
|
|
|
+ formatHexNumber,
|
|
|
|
|
+ readUint16BE,
|
|
|
|
|
+ readUint16LE,
|
|
|
|
|
+ readUint32LE,
|
|
|
trimTrailingNullBytes
|
|
trimTrailingNullBytes
|
|
|
} = require('../../utils/binary-utils.js')
|
|
} = require('../../utils/binary-utils.js')
|
|
|
|
|
|
|
@@ -102,30 +106,30 @@ function toBytes(bytes) {
|
|
|
return Array.prototype.slice.call(bytes || []).map((byte) => Number(byte) & 0xFF)
|
|
return Array.prototype.slice.call(bytes || []).map((byte) => Number(byte) & 0xFF)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function readUint16(bytes, offset) {
|
|
|
|
|
- if (offset + 1 >= bytes.length) return 0
|
|
|
|
|
|
|
+function normalizeMemoryEndian(value, fallback = MEMORY_ENDIAN.LITTLE) {
|
|
|
|
|
+ const text = String(value || '').trim().toLowerCase()
|
|
|
|
|
+ if (text === 'little' || text === 'le' || text === '1') return MEMORY_ENDIAN.LITTLE
|
|
|
|
|
+ if (text === 'big' || text === 'be' || text === '0') return MEMORY_ENDIAN.BIG
|
|
|
|
|
|
|
|
- return (((bytes[offset] || 0) << 8) | (bytes[offset + 1] || 0)) & 0xFFFF
|
|
|
|
|
|
|
+ return fallback
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function readUint32(bytes, offset) {
|
|
|
|
|
- if (offset + 3 >= bytes.length) return 0
|
|
|
|
|
|
|
+function applyMemoryEndian(bytes = [], memoryEndian = MEMORY_ENDIAN.LITTLE) {
|
|
|
|
|
+ const source = Array.isArray(bytes) ? bytes.slice() : []
|
|
|
|
|
|
|
|
- return (
|
|
|
|
|
- ((bytes[offset] || 0) * 0x1000000)
|
|
|
|
|
- + (((bytes[offset + 1] || 0) << 16) >>> 0)
|
|
|
|
|
- + (((bytes[offset + 2] || 0) << 8) >>> 0)
|
|
|
|
|
- + (bytes[offset + 3] || 0)
|
|
|
|
|
- ) >>> 0
|
|
|
|
|
|
|
+ return normalizeMemoryEndian(memoryEndian) === MEMORY_ENDIAN.LITTLE
|
|
|
|
|
+ ? source.reverse()
|
|
|
|
|
+ : source
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function readFloat(bytes, offset) {
|
|
|
|
|
|
|
+function readFloat(bytes, offset, memoryEndian = MEMORY_ENDIAN.LITTLE) {
|
|
|
if (offset + 3 >= bytes.length) return 0
|
|
if (offset + 3 >= bytes.length) return 0
|
|
|
|
|
|
|
|
const buffer = new ArrayBuffer(4)
|
|
const buffer = new ArrayBuffer(4)
|
|
|
const view = new DataView(buffer)
|
|
const view = new DataView(buffer)
|
|
|
|
|
+ const source = applyMemoryEndian(bytes.slice(offset, offset + 4), memoryEndian)
|
|
|
for (let index = 0; index < 4; index += 1) {
|
|
for (let index = 0; index < 4; index += 1) {
|
|
|
- view.setUint8(index, bytes[offset + index] || 0)
|
|
|
|
|
|
|
+ view.setUint8(index, source[index] || 0)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return view.getFloat32(0, false)
|
|
return view.getFloat32(0, false)
|
|
@@ -169,7 +173,7 @@ function formatAddress(address, addressWidth = 32) {
|
|
|
const numberValue = Math.max(0, Math.floor(Number(address) || 0))
|
|
const numberValue = Math.max(0, Math.floor(Number(address) || 0))
|
|
|
const hexWidth = normalizeCodeInfoAddressWidth(addressWidth) === 16 ? 4 : 8
|
|
const hexWidth = normalizeCodeInfoAddressWidth(addressWidth) === 16 ? 4 : 8
|
|
|
|
|
|
|
|
- return `0x${numberValue.toString(16).toUpperCase().padStart(hexWidth, '0')}`
|
|
|
|
|
|
|
+ return `0x${formatHexNumber(numberValue, hexWidth)}`
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function normalizeTypeName(value, fallback) {
|
|
function normalizeTypeName(value, fallback) {
|
|
@@ -182,13 +186,6 @@ function getEntryKindText(entryKind) {
|
|
|
return CODE_INFO_ENTRY_KIND_TEXT[entryKind] || 'unknown'
|
|
return CODE_INFO_ENTRY_KIND_TEXT[entryKind] || 'unknown'
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function normalizeMemoryEndian(value) {
|
|
|
|
|
- const text = String(value || '').trim().toLowerCase()
|
|
|
|
|
- if (text === 'little' || text === 'le' || text === '1') return MEMORY_ENDIAN.LITTLE
|
|
|
|
|
-
|
|
|
|
|
- return MEMORY_ENDIAN.BIG
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
function resolveCodeInfoByteLength(sourceLength, options = {}) {
|
|
function resolveCodeInfoByteLength(sourceLength, options = {}) {
|
|
|
const expectedLength = Number(
|
|
const expectedLength = Number(
|
|
|
options.codeInfoByteLength === undefined ? options.byteLength : options.codeInfoByteLength
|
|
options.codeInfoByteLength === undefined ? options.byteLength : options.codeInfoByteLength
|
|
@@ -218,9 +215,9 @@ function parseMemoryEntry(valueBytes, index, type) {
|
|
|
const memType = 0
|
|
const memType = 0
|
|
|
const addressOffset = 0
|
|
const addressOffset = 0
|
|
|
const byteAddr = layout.addressByteLength === 2
|
|
const byteAddr = layout.addressByteLength === 2
|
|
|
- ? readUint16(valueBytes, addressOffset)
|
|
|
|
|
- : readUint32(valueBytes, addressOffset)
|
|
|
|
|
- const byteLength = readUint16(valueBytes, addressOffset + layout.addressByteLength)
|
|
|
|
|
|
|
+ ? readUint16LE(valueBytes, addressOffset)
|
|
|
|
|
+ : readUint32LE(valueBytes, addressOffset)
|
|
|
|
|
+ const byteLength = readUint16LE(valueBytes, addressOffset + layout.addressByteLength)
|
|
|
const nameOffset = layout.nameOffset
|
|
const nameOffset = layout.nameOffset
|
|
|
const entryKind = layout.entryKind
|
|
const entryKind = layout.entryKind
|
|
|
const entryKindText = getEntryKindText(entryKind)
|
|
const entryKindText = getEntryKindText(entryKind)
|
|
@@ -250,7 +247,13 @@ function parseMemoryEntry(valueBytes, index, type) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function applyCodeInfoTlvValue(target, type, valueBytes) {
|
|
|
|
|
|
|
+function readMemoryEndianUint16(bytes, memoryEndian) {
|
|
|
|
|
+ return readUint16BE(applyMemoryEndian(bytes.slice(0, 2), memoryEndian), 0)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function applyCodeInfoTlvValue(target, type, valueBytes, options = {}) {
|
|
|
|
|
+ const memoryEndian = normalizeMemoryEndian(options.memoryEndian)
|
|
|
|
|
+
|
|
|
switch (type) {
|
|
switch (type) {
|
|
|
case CODE_INFO_TLV.CAVE_FREQ:
|
|
case CODE_INFO_TLV.CAVE_FREQ:
|
|
|
if (valueBytes.length < 1) throw new Error('CodeInfo cave_freq TLV 长度无效')
|
|
if (valueBytes.length < 1) throw new Error('CodeInfo cave_freq TLV 长度无效')
|
|
@@ -267,15 +270,15 @@ function applyCodeInfoTlvValue(target, type, valueBytes) {
|
|
|
break
|
|
break
|
|
|
case CODE_INFO_TLV.RS_SHUNT:
|
|
case CODE_INFO_TLV.RS_SHUNT:
|
|
|
if (valueBytes.length < 2) throw new Error('CodeInfo rs_shunt TLV 长度无效')
|
|
if (valueBytes.length < 2) throw new Error('CodeInfo rs_shunt TLV 长度无效')
|
|
|
- target.rsShunt = readUint16(valueBytes, 0)
|
|
|
|
|
|
|
+ target.rsShunt = readMemoryEndianUint16(valueBytes, memoryEndian)
|
|
|
break
|
|
break
|
|
|
case CODE_INFO_TLV.BUS_DIV:
|
|
case CODE_INFO_TLV.BUS_DIV:
|
|
|
if (valueBytes.length < 4) throw new Error('CodeInfo bus_div TLV 长度无效')
|
|
if (valueBytes.length < 4) throw new Error('CodeInfo bus_div TLV 长度无效')
|
|
|
- target.busDiv = readFloat(valueBytes, 0)
|
|
|
|
|
|
|
+ target.busDiv = readFloat(valueBytes, 0, memoryEndian)
|
|
|
break
|
|
break
|
|
|
case CODE_INFO_TLV.ALONG_DIV:
|
|
case CODE_INFO_TLV.ALONG_DIV:
|
|
|
if (valueBytes.length < 4) throw new Error('CodeInfo along_div TLV 长度无效')
|
|
if (valueBytes.length < 4) throw new Error('CodeInfo along_div TLV 长度无效')
|
|
|
- target.alongDiv = readFloat(valueBytes, 0)
|
|
|
|
|
|
|
+ target.alongDiv = readFloat(valueBytes, 0, memoryEndian)
|
|
|
break
|
|
break
|
|
|
case CODE_INFO_TLV.CHIP_MODEL:
|
|
case CODE_INFO_TLV.CHIP_MODEL:
|
|
|
target.chipModel = readTlvText(valueBytes)
|
|
target.chipModel = readTlvText(valueBytes)
|
|
@@ -291,7 +294,7 @@ function applyCodeInfoTlvValue(target, type, valueBytes) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function parseCodeInfoTlvs(bytes) {
|
|
|
|
|
|
|
+function parseCodeInfoTlvs(bytes, options = {}) {
|
|
|
const info = {
|
|
const info = {
|
|
|
entries: [],
|
|
entries: [],
|
|
|
tlvItems: []
|
|
tlvItems: []
|
|
@@ -323,7 +326,7 @@ function parseCodeInfoTlvs(bytes) {
|
|
|
if (entry) {
|
|
if (entry) {
|
|
|
info.entries.push(entry)
|
|
info.entries.push(entry)
|
|
|
} else {
|
|
} else {
|
|
|
- applyCodeInfoTlvValue(info, type, valueBytes)
|
|
|
|
|
|
|
+ applyCodeInfoTlvValue(info, type, valueBytes, options)
|
|
|
}
|
|
}
|
|
|
offset = nextOffset
|
|
offset = nextOffset
|
|
|
}
|
|
}
|
|
@@ -338,7 +341,8 @@ function parseCodeInfo(bytes, options = {}) {
|
|
|
|
|
|
|
|
const addressWidth = normalizeCodeInfoAddressWidth(options.addressWidth)
|
|
const addressWidth = normalizeCodeInfoAddressWidth(options.addressWidth)
|
|
|
const maxPacketLength = Number(options.maxPacketLength || 0) & 0xFFFF
|
|
const maxPacketLength = Number(options.maxPacketLength || 0) & 0xFFFF
|
|
|
- const tlvInfo = parseCodeInfoTlvs(source)
|
|
|
|
|
|
|
+ const memoryEndian = normalizeMemoryEndian(options.memoryEndian)
|
|
|
|
|
+ const tlvInfo = parseCodeInfoTlvs(source, { memoryEndian })
|
|
|
const entries = tlvInfo.entries
|
|
const entries = tlvInfo.entries
|
|
|
const entryCount = entries.length
|
|
const entryCount = entries.length
|
|
|
const entryAddressByteLengths = entries
|
|
const entryAddressByteLengths = entries
|
|
@@ -352,7 +356,7 @@ function parseCodeInfo(bytes, options = {}) {
|
|
|
byteLength: codeInfoByteLength,
|
|
byteLength: codeInfoByteLength,
|
|
|
entryCount,
|
|
entryCount,
|
|
|
maxPacketLength,
|
|
maxPacketLength,
|
|
|
- memoryEndian: normalizeMemoryEndian(options.memoryEndian),
|
|
|
|
|
|
|
+ memoryEndian,
|
|
|
memoryEndianRaw: Number(options.memoryEndianRaw || options.memoryEndianMark || 0) & 0xFFFF,
|
|
memoryEndianRaw: Number(options.memoryEndianRaw || options.memoryEndianMark || 0) & 0xFFFF,
|
|
|
rawHex: bytesToHex(source, ' '),
|
|
rawHex: bytesToHex(source, ' '),
|
|
|
structEntryAddressByteLength: entryAddressByteLengths.length === 1 ? entryAddressByteLengths[0] : 0,
|
|
structEntryAddressByteLength: entryAddressByteLengths.length === 1 ? entryAddressByteLengths[0] : 0,
|
|
@@ -416,6 +420,7 @@ function createCodeInfoContext(codeInfo = {}) {
|
|
|
codeInfoAddressWidth: codeInfo.addressWidth,
|
|
codeInfoAddressWidth: codeInfo.addressWidth,
|
|
|
maxPacketLength: codeInfo.maxPacketLength,
|
|
maxPacketLength: codeInfo.maxPacketLength,
|
|
|
memoryEndian: codeInfo.memoryEndian,
|
|
memoryEndian: codeInfo.memoryEndian,
|
|
|
|
|
+ memoryEndianRaw: Number(codeInfo.memoryEndianRaw || 0) & 0xFFFF,
|
|
|
storageAddressWidth: codeInfo.addressWidth
|
|
storageAddressWidth: codeInfo.addressWidth
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|