| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- const {
- bytesToWords
- } = require('../../utils/binary-utils.js')
- const transport = require('../../transport/ble-core.js')
- const storageAccessMemory = require('../storage-access/memory-service.js')
- const {
- decodeRegisterFromByteCache,
- decodeRegisterValue,
- formatRegisterValue,
- getGroupEncodedBytes,
- getRegisterBytesFromByteCache,
- getRegisterEncodedBytes,
- getRegisterWordsFromByteCache,
- getRegisterWordsFromWordCache
- } = require('../../domain/parameter-groups/model.js')
- const STORAGE_ACCESS_MEMORY_TYPES = {
- DATA: 0x01,
- BIT: 0x01,
- IDATA: 0x02,
- XDATA: 0x03,
- CODE: 0x04
- }
- const STORAGE_ACCESS_CODE_AREA = 0x04
- function getMemoryType(group = {}) {
- const memoryArea = String(group.sourceMemoryArea || '').trim().toUpperCase()
- return Object.prototype.hasOwnProperty.call(STORAGE_ACCESS_MEMORY_TYPES, memoryArea)
- ? STORAGE_ACCESS_MEMORY_TYPES[memoryArea]
- : null
- }
- function isMemoryGroup(group = {}) {
- return getMemoryType(group) !== null
- }
- function isByteAddressedGroup(group = {}) {
- return group.addressUnit === 'byte' || group.addressUnit === 'bytes' || isMemoryGroup(group)
- }
- function getMemoryAddress(group = {}) {
- const sourceAddress = Number(group.sourceAddress)
- if (Number.isFinite(sourceAddress)) return Math.max(0, Math.floor(sourceAddress)) & 0xFFFF
- return Math.max(0, Number(group.startAddress) || 0) & 0xFFFF
- }
- function getMemoryByteLength(group = {}) {
- const sourceByteLength = Number(group.sourceByteLength)
- if (Number.isFinite(sourceByteLength) && sourceByteLength > 0) return Math.min(0xFFFF, Math.ceil(sourceByteLength))
- const byteLength = Number(group.byteLength)
- if (Number.isFinite(byteLength) && byteLength > 0) return Math.min(0xFFFF, Math.ceil(byteLength))
- return Math.max(1, Math.ceil((Number(group.wordQuantity) || 1) * 2))
- }
- function bytesToPaddedWords(bytes = []) {
- return bytesToWords(bytes.length % 2 === 0 ? bytes : bytes.concat(0))
- }
- function fillByteCacheFromBytes(byteCache, startAddress, bytes = []) {
- bytes.forEach((byte, offset) => {
- byteCache[startAddress + offset] = Number(byte) & 0xFF
- })
- }
- function fillWordCacheFromBytes(wordCache, startAddress, bytes = []) {
- const words = bytesToPaddedWords(bytes)
- words.forEach((word, offset) => {
- wordCache[startAddress + offset] = Number(word) & 0xFFFF
- })
- }
- function createWrittenRegisterSnapshots(group, wordCache) {
- return group.registers.map((register) => {
- const rawBytes = isByteAddressedGroup(group)
- ? (getRegisterBytesFromByteCache(register, wordCache) || [])
- : []
- const rawWords = isByteAddressedGroup(group)
- ? (getRegisterWordsFromByteCache(register, wordCache) || [])
- : (getRegisterWordsFromWordCache(register, wordCache) || [])
- const rawValue = isByteAddressedGroup(group)
- ? decodeRegisterFromByteCache(register, wordCache)
- : decodeRegisterValue(register, rawWords)
- return {
- rawBytes,
- rawWords,
- rawValue,
- displayValue: formatRegisterValue(register, rawValue)
- }
- })
- }
- function createWrittenRegisterSnapshot(group, register, byteCache) {
- const snapshots = createWrittenRegisterSnapshots({
- ...group,
- registers: [register]
- }, byteCache)
- return snapshots[0] || null
- }
- function groupHasBitFields(group = {}) {
- return (Array.isArray(group.registers) ? group.registers : []).some((register) => !!register.isBitField)
- }
- async function writeMemoryRegister(group, register, options = {}) {
- const memoryType = getMemoryType(group)
- const maxPacketLength = storageAccessMemory.resolveMaxPacketLength(options.maxPacketLength)
- const byteLength = Math.max(1, Number(register.byteLength) || 1)
- const address = Math.max(0, Math.floor(Number(register.address) || getMemoryAddress(group))) & 0xFFFF
- let bytes
- if (memoryType === null) {
- transport.showCommandAlert('内存写入', `暂不支持 ${group.sourceMemoryArea || '未知'} 内存区域`)
- return null
- }
- if (memoryType === STORAGE_ACCESS_CODE_AREA) {
- transport.showCommandAlert('内存写入', 'code 区暂不支持写入')
- return null
- }
- try {
- if (register.isBitField) {
- const baseBytes = await storageAccessMemory.readMemory(
- memoryType,
- address,
- byteLength,
- register.name ? `${register.name} 读改写` : '变量读改写',
- 'parameter-group-memory-register-rmw-read',
- {
- maxFrameBytes: maxPacketLength
- }
- )
- if (!baseBytes) return null
- bytes = getGroupEncodedBytes({
- ...group,
- paddedByteLength: byteLength,
- registers: [{
- ...register,
- address,
- byteStart: 0
- }]
- }, baseBytes).slice(0, byteLength)
- } else {
- bytes = getRegisterEncodedBytes(register)
- }
- } catch (error) {
- transport.showCommandAlert('内存写入', error.message || '变量没有有效写入值')
- return null
- }
- if (!Array.isArray(bytes) || !bytes.length) {
- transport.showCommandAlert('内存写入', `${register.name || '变量'} 没有有效写入值`)
- return null
- }
- bytes = bytes.slice(0, byteLength)
- while (bytes.length < byteLength) bytes.push(0)
- const ok = await storageAccessMemory.writeMemory(
- memoryType,
- address,
- bytes,
- register.name || group.name || '变量写入',
- 'parameter-group-memory-register-write',
- {
- maxFrameBytes: maxPacketLength
- }
- )
- if (!ok) return null
- const byteCache = {}
- fillByteCacheFromBytes(byteCache, address, bytes)
- return createWrittenRegisterSnapshot(group, register, byteCache)
- }
- async function readMemoryGroup(group, options = {}) {
- const memoryType = getMemoryType(group)
- const address = getMemoryAddress(group)
- const byteLength = getMemoryByteLength(group)
- const maxPacketLength = storageAccessMemory.resolveMaxPacketLength(options.maxPacketLength)
- if (memoryType === null) {
- transport.showCommandAlert('内存读取', `暂不支持 ${group.sourceMemoryArea || '未知'} 内存区域`)
- return null
- }
- const bytes = await storageAccessMemory.readMemory(
- memoryType,
- address,
- byteLength,
- group.name || '内存读取',
- 'parameter-group-memory-read',
- {
- maxFrameBytes: maxPacketLength,
- showModal: options.showModal !== false
- }
- )
- if (!bytes) return null
- const wordCache = {}
- if (isByteAddressedGroup(group)) {
- fillByteCacheFromBytes(wordCache, address, bytes)
- } else {
- fillWordCacheFromBytes(wordCache, address, bytes)
- }
- return wordCache
- }
- async function writeMemoryGroup(group, options = {}) {
- const memoryType = getMemoryType(group)
- const address = getMemoryAddress(group)
- const byteLength = getMemoryByteLength(group)
- const maxPacketLength = storageAccessMemory.resolveMaxPacketLength(options.maxPacketLength)
- let bytes
- if (memoryType === null) {
- transport.showCommandAlert('内存写入', `暂不支持 ${group.sourceMemoryArea || '未知'} 内存区域`)
- return null
- }
- if (memoryType === STORAGE_ACCESS_CODE_AREA) {
- transport.showCommandAlert('内存写入', 'code 区暂不支持写入')
- return null
- }
- try {
- let baseBytes = null
- if (groupHasBitFields(group)) {
- baseBytes = await storageAccessMemory.readMemory(
- memoryType,
- address,
- byteLength,
- group.name ? `${group.name} 读改写` : '内存读改写',
- 'parameter-group-memory-rmw-read',
- {
- maxFrameBytes: maxPacketLength
- }
- )
- if (!baseBytes) return null
- }
- bytes = getGroupEncodedBytes(group, baseBytes)
- } catch (error) {
- transport.showCommandAlert('内存写入', error.message || '寄存器组没有有效写入值')
- return null
- }
- bytes = bytes.slice(0, byteLength)
- const ok = await storageAccessMemory.writeMemory(
- memoryType,
- address,
- bytes,
- group.name || '内存写入',
- 'parameter-group-memory-write',
- {
- maxFrameBytes: maxPacketLength
- }
- )
- if (!ok) return null
- const wordCache = {}
- if (isByteAddressedGroup(group)) {
- fillByteCacheFromBytes(wordCache, address, bytes)
- } else {
- fillWordCacheFromBytes(wordCache, address, bytes)
- }
- return createWrittenRegisterSnapshots(group, wordCache)
- }
- module.exports = {
- getMemoryAddress,
- getMemoryByteLength,
- getMemoryType,
- isByteAddressedGroup,
- isMemoryGroup,
- readMemoryGroup,
- writeMemoryGroup,
- writeMemoryRegister
- }
|