| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- const {
- buildReadFrame,
- buildWriteMultipleRegistersFrame,
- buildWriteSingleCoilFrame,
- buildWriteSingleRegisterFrame,
- getMaxReadQuantity,
- getMaxWriteMultipleRegisterQuantity
- } = require('./modbus-rtu')
- const settingsService = require('./settings-service')
- const transport = require('./ble-transport')
- const {
- addCoilReadValues,
- addWordReadValues
- } = require('./register-value-utils')
- 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 splitQuantity(startAddress, quantity, maxQuantity) {
- const chunks = []
- let address = Number(startAddress) || 0
- let remaining = Math.max(0, Math.floor(Number(quantity) || 0))
- const chunkLimit = Math.max(1, Math.floor(Number(maxQuantity) || remaining || 1))
- while (remaining > 0) {
- const chunkQuantity = Math.min(remaining, chunkLimit)
- chunks.push({
- address,
- quantity: chunkQuantity
- })
- address += chunkQuantity
- remaining -= chunkQuantity
- }
- return chunks
- }
- function getReadChunks(functionCode, startAddress, quantity, options = {}) {
- const maxQuantity = getMaxReadQuantity(functionCode, options.maxFrameBytes)
- return splitQuantity(startAddress, quantity, maxQuantity || quantity)
- }
- async function sendReadChunk(slaveAddress, functionCode, chunk, label, kind, options = {}) {
- return transport.sendManagedFrame(
- buildReadFrame(slaveAddress, functionCode, chunk.address, chunk.quantity, {
- maxFrameBytes: options.maxFrameBytes
- }),
- label,
- {
- address: chunk.address,
- functionCode,
- kind,
- 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 = getReadChunks(functionCode, span.address, span.quantity, options)
- for (const chunk of chunks) {
- const response = await sendReadChunk(
- slaveAddress,
- functionCode,
- chunk,
- getChunkLabel(label, chunks, chunk),
- kind,
- options
- )
- if (!response) return null
- if (functionCode === 0x01 || functionCode === 0x02) {
- addCoilReadValues(readValues, chunk.address, chunk.quantity, response)
- } else {
- addWordReadValues(readValues, chunk.address, response)
- }
- if (typeof options.onChunk === 'function') {
- options.onChunk(response, chunk)
- }
- }
- }
- return readValues
- }
- async function readRegisterWords(slaveAddress, functionCode, startAddress, quantity, label, kind, options = {}) {
- const words = []
- const chunks = getReadChunks(functionCode, startAddress, quantity, options)
- for (const chunk of chunks) {
- const response = await sendReadChunk(
- slaveAddress,
- functionCode,
- chunk,
- getChunkLabel(label, chunks, chunk),
- kind,
- options
- )
- if (!response) return null
- const chunkWords = response.words || []
- chunkWords.forEach((word, index) => {
- words[chunk.address - startAddress + index] = Number(word) & 0xFFFF
- })
- if (typeof options.onChunk === 'function') {
- options.onChunk(response, 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(
- buildWriteSingleCoilFrame(slaveAddress, address, checked),
- label,
- {
- address,
- functionCode: 0x05,
- kind,
- quantity: 1,
- slaveAddress,
- value: coilValue
- },
- {
- maxFrameBytes: options.maxFrameBytes,
- showModal: options.showModal
- }
- )
- }
- function writeSingleRegister(slaveAddress, address, value, label, kind = 'register-write', options = {}) {
- return transport.sendManagedFrame(
- buildWriteSingleRegisterFrame(slaveAddress, address, value),
- label,
- {
- address,
- functionCode: 0x06,
- kind,
- quantity: 1,
- slaveAddress,
- value
- },
- {
- maxFrameBytes: options.maxFrameBytes,
- showModal: options.showModal
- }
- )
- }
- function writeMultipleRegisters(slaveAddress, address, values, label, kind = 'registers-write', options = {}) {
- return transport.sendManagedFrame(
- buildWriteMultipleRegistersFrame(slaveAddress, address, values, {
- maxFrameBytes: options.maxFrameBytes
- }),
- label,
- {
- address,
- functionCode: 0x10,
- kind,
- quantity: values.length,
- slaveAddress
- },
- {
- maxFrameBytes: options.maxFrameBytes,
- showModal: options.showModal
- }
- )
- }
- module.exports = {
- getReadChunks,
- getSharedSlaveAddress,
- getMaxReadQuantity,
- readBitValues,
- readRegisterWords,
- readSingleHoldingWord,
- readSpans,
- splitQuantity,
- getMaxWriteMultipleRegisterQuantity,
- writeMultipleRegisters,
- writeSingleCoil,
- writeSingleRegister
- }
|