const { paramsState: paramsPageState } = require('../../domain/motor-control/data.js') const { expandItems, getAreaKey, getGroupItems, makeReadSpans, mergeReadValues, parseRegisterAddress } = require('../../domain/motor-control/register-groups.js') const transport = require('../../transport/ble-core.js') const modbusClient = require('../../protocols/modbus-rtu/client.js') const { floatToWords, toRegisterWord } = require('../../utils/register-value-utils.js') function hasWriteValue(value) { return value !== '' && value !== undefined && value !== null && value !== '--' } function toWriteNumber(value) { if (!hasWriteValue(value)) return null const numberValue = Number(value) if (!Number.isFinite(numberValue)) return null return numberValue } async function readGroup(data, groupKey) { const slaveAddress = modbusClient.getSharedSlaveAddress() if (slaveAddress === null) return false const items = expandItems(getGroupItems(data, groupKey)) const coilItems = items.filter((item) => getAreaKey(item) === 'coil') const holdingItems = items.filter((item) => getAreaKey(item) === 'holding') const inputItems = items.filter((item) => getAreaKey(item) === 'input') const coilSpans = makeReadSpans(coilItems) const holdingSpans = makeReadSpans(holdingItems) const inputSpans = makeReadSpans(inputItems) const readValues = { coils: {}, words: {} } let sent = false if (coilSpans.length) { sent = true const values = await modbusClient.readSpans( slaveAddress, 0x01, coilSpans, '参数读取', 'params-read' ) if (!values) return false mergeReadValues(readValues, values) } if (holdingSpans.length) { sent = true const values = await modbusClient.readSpans( slaveAddress, 0x03, holdingSpans, '参数读取', 'params-read' ) if (!values) return false mergeReadValues(readValues, values) } if (inputSpans.length) { sent = true const values = await modbusClient.readSpans( slaveAddress, 0x04, inputSpans, '参数读取', 'params-read' ) if (!values) return false mergeReadValues(readValues, values) } if (!sent) { transport.showCommandAlert('参数读取', '当前分组没有可读取的寄存器') return false } if (!Object.keys(readValues.coils).length && !Object.keys(readValues.words).length) { return false } return paramsPageState.applyReadValues(data, readValues) } async function buildHoldingWriteEntries(slaveAddress, items) { const normalEntries = [] const byteGroups = {} items.forEach((item) => { if (getAreaKey(item) !== 'holding') return if (item.type === 'uint8_t' && item.bytePosition) { const address = parseRegisterAddress(item.address) const group = byteGroups[address] || { address, high: null, low: null } group[item.bytePosition] = item byteGroups[address] = group return } const writeNumber = toWriteNumber(item.writeValue) if (writeNumber === null) return const words = item.type === 'float' ? floatToWords(writeNumber) : [toRegisterWord(writeNumber)] if (!words || words.some((word) => word === null)) return normalEntries.push({ address: parseRegisterAddress(item.address), label: item.name, values: words }) }) for (const addressText of Object.keys(byteGroups)) { const group = byteGroups[addressText] const highValue = group.high ? toRegisterWord(group.high.writeValue) : null const lowValue = group.low ? toRegisterWord(group.low.writeValue) : null if (highValue === null && lowValue === null) continue let baseWord = 0 if (highValue === null || lowValue === null) { const readWord = await modbusClient.readSingleHoldingWord( slaveAddress, group.address, '读取配对寄存器', 'params-pair-read' ) if (!Number.isInteger(readWord)) continue baseWord = readWord } const nextHigh = highValue === null ? ((baseWord >> 8) & 0xFF) : highValue const nextLow = lowValue === null ? (baseWord & 0xFF) : lowValue if (nextHigh > 0xFF || nextLow > 0xFF) continue normalEntries.push({ address: group.address, label: '8位参数', values: [(nextHigh << 8) | nextLow] }) } return normalEntries.sort((left, right) => left.address - right.address) } async function writeGroup(data, groupKey) { const slaveAddress = modbusClient.getSharedSlaveAddress() if (slaveAddress === null) return false const items = expandItems(getGroupItems(data, groupKey)) const coilItems = items.filter((item) => getAreaKey(item) === 'coil' && item.isDirty) const holdingItems = items.filter((item) => getAreaKey(item) === 'holding') let sent = false for (const item of coilItems) { const checked = Number(item.writeValue) !== 0 const address = parseRegisterAddress(item.address) sent = true const response = await modbusClient.writeSingleCoil( slaveAddress, address, checked, item.name, 'params-coil-write' ) if (!response) return false } const holdingEntries = await buildHoldingWriteEntries(slaveAddress, holdingItems) for (const entry of holdingEntries) { sent = true const response = await modbusClient.writeMultipleRegisters( slaveAddress, entry.address, entry.values, entry.label, 'params-holding-write' ) if (!response) return false } if (!sent) { transport.showCommandAlert('参数写入', '当前分组没有可写入的参数') } return sent } async function writeSwitchRegister(item) { const slaveAddress = modbusClient.getSharedSlaveAddress() if (slaveAddress === null || !item) return false const address = parseRegisterAddress(item.address) const checked = Number(item.writeValue) !== 0 return modbusClient.writeSingleCoil( slaveAddress, address, checked, item.name, 'params-switch-write' ) } module.exports = { readGroup, writeGroup, writeSwitchRegister }