const settingsService = require('../../store/settings-store.js') const transport = require('../../transport/ble-core.js') const modbusProtocol = require('../../protocols/modbus-rtu/index.js') const { addCoilReadValues, addWordReadValues } = require('../../utils/register-value-utils.js') function getSharedSlaveAddress(title = '从机地址错误') { try { return settingsService.getModbusSlaveAddress() } catch (error) { transport.showCommandAlert(title, error.message) return null } } function formatAddress(value) { return Number(value || 0).toString(16).toUpperCase() } function getChunkLabel(label, chunks, chunk) { if (!label || chunks.length <= 1) return label return `${label} ${formatAddress(chunk.address)}-${formatAddress(chunk.address + chunk.quantity - 1)}` } function isBroadcastAddress(slaveAddress) { return Number(slaveAddress) === 0 } function showBroadcastReadAlert(label) { transport.showCommandAlert(label || '读取命令错误', '广播地址 0x00 不支持读取') } async function sendReadChunk(slaveAddress, functionCode, chunk, label, kind, options = {}) { if (isBroadcastAddress(slaveAddress)) { showBroadcastReadAlert(label) return false } return transport.sendManagedFrame( modbusProtocol.buildReadFrame(slaveAddress, functionCode, chunk.address, chunk.quantity, { maxFrameBytes: options.maxFrameBytes }), label, { address: chunk.address, functionCode, kind, protocol: modbusProtocol.PROTOCOL_NAME, quantity: chunk.quantity, slaveAddress }, { maxFrameBytes: options.maxFrameBytes, showModal: options.showModal } ) } async function readSpans(slaveAddress, functionCode, spans, label, kind, options = {}) { const readValues = { coils: {}, words: {} } const normalizedSpans = (spans || []).filter((span) => span && span.quantity > 0) for (const span of normalizedSpans) { const chunks = modbusProtocol.getReadChunks(functionCode, span.address, span.quantity, options) for (const chunk of chunks) { const responseValue = await sendReadChunk( slaveAddress, functionCode, chunk, getChunkLabel(label, chunks, chunk), kind, options ) if (!responseValue) return null if (functionCode === 0x01 || functionCode === 0x02) { addCoilReadValues(readValues, chunk.address, chunk.quantity, responseValue) } else { addWordReadValues(readValues, chunk.address, responseValue) } if (typeof options.onChunk === 'function') { options.onChunk(responseValue, chunk) } } } return readValues } async function readRegisterWords(slaveAddress, functionCode, startAddress, quantity, label, kind, options = {}) { const words = [] const chunks = modbusProtocol.getReadChunks(functionCode, startAddress, quantity, options) for (const chunk of chunks) { const responseValue = await sendReadChunk( slaveAddress, functionCode, chunk, getChunkLabel(label, chunks, chunk), kind, options ) if (!responseValue) return null const chunkWords = responseValue.words || [] chunkWords.forEach((word, index) => { words[chunk.address - startAddress + index] = Number(word) & 0xFFFF }) if (typeof options.onChunk === 'function') { options.onChunk(responseValue, chunk) } } return words } async function readBitValues(slaveAddress, functionCode, startAddress, quantity, label, kind, options = {}) { const result = await readSpans( slaveAddress, functionCode, [{ address: startAddress, quantity }], label, kind, options ) return result ? result.coils : null } async function readSingleHoldingWord(slaveAddress, address, label = '读取配对寄存器', kind = 'holding-word-read') { const words = await readRegisterWords(slaveAddress, 0x03, address, 1, label, kind) return words && Number.isInteger(words[0]) ? words[0] & 0xFFFF : null } function writeSingleCoil(slaveAddress, address, checked, label, kind = 'coil-write', options = {}) { const coilValue = checked ? 0xFF00 : 0x0000 return transport.sendManagedFrame( modbusProtocol.buildWriteSingleCoilFrame(slaveAddress, address, checked), label, isBroadcastAddress(slaveAddress) ? null : { address, functionCode: 0x05, kind, protocol: modbusProtocol.PROTOCOL_NAME, quantity: 1, slaveAddress, value: coilValue }, { maxFrameBytes: options.maxFrameBytes, showModal: options.showModal } ) } function writeSingleRegister(slaveAddress, address, value, label, kind = 'register-write', options = {}) { return transport.sendManagedFrame( modbusProtocol.buildWriteSingleRegisterFrame(slaveAddress, address, value), label, isBroadcastAddress(slaveAddress) ? null : { address, functionCode: 0x06, kind, protocol: modbusProtocol.PROTOCOL_NAME, quantity: 1, slaveAddress, value }, { maxFrameBytes: options.maxFrameBytes, showModal: options.showModal } ) } function writeMultipleRegisters(slaveAddress, address, values, label, kind = 'registers-write', options = {}) { return transport.sendManagedFrame( modbusProtocol.buildWriteMultipleRegistersFrame(slaveAddress, address, values, { maxFrameBytes: options.maxFrameBytes }), label, isBroadcastAddress(slaveAddress) ? null : { address, functionCode: 0x10, kind, protocol: modbusProtocol.PROTOCOL_NAME, quantity: values.length, slaveAddress }, { maxFrameBytes: options.maxFrameBytes, showModal: options.showModal } ) } module.exports = { getMaxReadQuantity: modbusProtocol.getMaxReadQuantity, getMaxWriteMultipleRegisterQuantity: modbusProtocol.getMaxWriteMultipleRegisterQuantity, getReadChunks: modbusProtocol.getReadChunks, getSharedSlaveAddress, readBitValues, readRegisterWords, readSingleHoldingWord, readSpans, splitQuantity: modbusProtocol.splitQuantity, writeMultipleRegisters, writeSingleCoil, writeSingleRegister }