const { formatFixedValue } = require('../../utils/number-format.js') const { getDataType, isHexRegister } = require('./value-types.js') function padWordHex(value) { return Number(value || 0).toString(16).toUpperCase().padStart(4, '0') } function formatIntegerValue(value, dataType) { const type = getDataType(dataType).key const numberValue = Number(value) if (!Number.isFinite(numberValue)) return '--' if (type === 'int8_t') return String(((Math.round(numberValue) << 24) >> 24)) if (type === 'uint8_t') return String(Math.round(numberValue) & 0xFF) if (type === 'int16_t') return String(((Math.round(numberValue) << 16) >> 16)) if (type === 'uint16_t') return String(Math.round(numberValue) & 0xFFFF) if (type === 'int32_t') return String((Math.round(numberValue) | 0)) if (type === 'uint32_t') return String(Math.round(numberValue) >>> 0) return String(Math.round(numberValue)) } function formatHexValue(value) { const numberValue = Number(value) if (!Number.isFinite(numberValue)) return '--' return `0x${padWordHex(Math.round(numberValue) & 0xFFFF)}` } function formatFloatValue(value) { return formatFixedValue(value, 6).replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '') } function parseIntegerText(value) { const text = String(value === undefined || value === null ? '' : value).trim() if (!text) return null const isHex = /^[-+]?0x[0-9a-f]+$/i.test(text) || /^0x[0-9a-f]+$/i.test(text) const parsed = isHex ? parseInt(text, 16) : Number(text) return Number.isFinite(parsed) ? parsed : null } function parseHexText(value) { const text = String(value === undefined || value === null ? '' : value).trim() if (!text) return null const hexText = text.toUpperCase().startsWith('0X') ? text.slice(2) : text if (/^[0-9A-F]{1,4}$/i.test(hexText)) { const parsedHex = parseInt(hexText, 16) return Number.isFinite(parsedHex) ? parsedHex : null } return null } function getNumericRange(dataType) { const type = getDataType(dataType).key if (type === 'int8_t') return { max: 127, min: -128 } if (type === 'uint8_t') return { max: 0xFF, min: 0 } if (type === 'int16_t') return { max: 32767, min: -32768 } if (type === 'uint16_t') return { max: 0xFFFF, min: 0 } if (type === 'int32_t') return { max: 2147483647, min: -2147483648 } if (type === 'uint32_t') return { max: 0xFFFFFFFF, min: 0 } if (type === 'hex') return { max: 0xFFFF, min: 0 } return { max: Number.POSITIVE_INFINITY, min: Number.NEGATIVE_INFINITY } } function parseNumberText(value, dataType) { const text = String(value === undefined || value === null ? '' : value).trim() if (!text || text === '--') return null if (getDataType(dataType).key === 'float') { const parsed = Number(text) return Number.isFinite(parsed) ? parsed : null } if (isHexRegister(dataType)) return parseHexText(text) return parseIntegerText(text) } function parseRangeBoundary(value, dataType, label) { const text = String(value === undefined || value === null ? '' : value).trim() if (!text) return null const parsed = parseNumberText(text, dataType) if (parsed === null) { throw new Error(`${label}无效`) } return parsed } function validateNumericValue(register, value) { const dataType = getDataType(register.dataType).key const range = getNumericRange(dataType) const numberValue = Number(value) if (!Number.isFinite(numberValue)) return false if (dataType !== 'float' && Math.round(numberValue) !== numberValue) { throw new Error(`${register.name || '寄存器'} 需要整数`) } if (numberValue < range.min || numberValue > range.max) { throw new Error(`${register.name || '寄存器'} 超出 ${dataType} 范围`) } const minValue = parseRangeBoundary(register.minValue, dataType, `${register.name || '寄存器'} 最小值`) const maxValue = parseRangeBoundary(register.maxValue, dataType, `${register.name || '寄存器'} 最大值`) if (minValue !== null && numberValue < minValue) { throw new Error(`${register.name || '寄存器'} 小于限制最小值`) } if (maxValue !== null && numberValue > maxValue) { throw new Error(`${register.name || '寄存器'} 大于限制最大值`) } return true } function floatToBytes(value) { const buffer = new ArrayBuffer(4) const view = new DataView(buffer) view.setFloat32(0, Number(value), false) return [ view.getUint8(0), view.getUint8(1), view.getUint8(2), view.getUint8(3) ] } function bytesToFloatValue(bytes) { if (!Array.isArray(bytes) || bytes.length < 4) return null const buffer = new ArrayBuffer(4) const view = new DataView(buffer) for (let index = 0; index < 4; index += 1) { view.setUint8(index, Number(bytes[index]) & 0xFF) } return view.getFloat32(0, false) } function unsignedIntegerToBytes(value, byteLength) { let numberValue = Math.round(Number(value) || 0) const bytes = [] if (numberValue < 0) { numberValue += Math.pow(2, byteLength * 8) } for (let index = byteLength - 1; index >= 0; index -= 1) { bytes[index] = numberValue & 0xFF numberValue = Math.floor(numberValue / 0x100) } return bytes } function bytesToUnsignedInteger(bytes) { return bytes.reduce((value, byte) => ((value * 0x100) + (Number(byte) & 0xFF)), 0) } function bytesToSignedInteger(bytes) { const unsignedValue = bytesToUnsignedInteger(bytes) const signLimit = Math.pow(2, bytes.length * 8 - 1) const fullRange = Math.pow(2, bytes.length * 8) return unsignedValue >= signLimit ? unsignedValue - fullRange : unsignedValue } module.exports = { bytesToFloatValue, bytesToSignedInteger, bytesToUnsignedInteger, floatToBytes, formatFloatValue, formatHexValue, formatIntegerValue, getNumericRange, parseHexText, parseIntegerText, parseNumberText, parseRangeBoundary, unsignedIntegerToBytes, validateNumericValue }