| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- const {
- normalizeTextValue
- } = require('../../utils/base-utils.js')
- const {
- bytesToWords
- } = require('../../utils/binary-utils.js')
- const {
- MAX_MODBUS_ADDRESS
- } = require('./constants.js')
- const {
- decodeRegisterValue,
- encodeBitFieldIntoBytes,
- encodeRegisterBytes,
- encodeRegisterWords,
- isBitFieldRegister,
- validateRegisterValue: validateCodecRegisterValue
- } = require('./value-codec.js')
- function normalizeAddress(value, fallback = 0) {
- if (typeof value === 'number') {
- return Number.isFinite(value) ? Math.max(0, Math.min(Math.round(value), MAX_MODBUS_ADDRESS)) : fallback
- }
- const text = String(value === undefined || value === null ? '' : value).trim()
- if (!text) return fallback
- const hexText = text.toUpperCase().startsWith('0X') ? text.slice(2) : text
- if (/^[0-9A-F]+$/i.test(hexText)) {
- const parsedHex = parseInt(hexText, 16)
- return Number.isFinite(parsedHex) ? Math.max(0, Math.min(parsedHex, MAX_MODBUS_ADDRESS)) : fallback
- }
- const numberValue = Number(text)
- return Number.isFinite(numberValue) ? Math.max(0, Math.min(Math.round(numberValue), MAX_MODBUS_ADDRESS)) : fallback
- }
- function splitWordSpans(startAddress, quantity, maxQuantity) {
- const spans = []
- let address = normalizeAddress(startAddress, 0)
- let remaining = Math.max(0, Math.floor(Number(quantity) || 0))
- while (remaining > 0) {
- const spanQuantity = Math.min(remaining, maxQuantity)
- spans.push({
- address,
- quantity: spanQuantity
- })
- address += spanQuantity
- remaining -= spanQuantity
- }
- return spans
- }
- function getRegisterWriteValueText(register) {
- if (register.inputValue !== undefined && register.inputValue !== null) return normalizeTextValue(register.inputValue)
- if (register.defaultValue !== undefined && register.defaultValue !== null) return normalizeTextValue(register.defaultValue)
- return ''
- }
- function getRegisterWordsFromWordCache(register, wordCache) {
- const words = []
- for (let offset = 0; offset < register.registerCount; offset += 1) {
- const word = wordCache[register.address + offset]
- if (word === undefined) return null
- words.push(word)
- }
- return words
- }
- function getRegisterBytesFromByteCache(register, byteCache) {
- const bytes = []
- for (let offset = 0; offset < register.byteLength; offset += 1) {
- const byte = byteCache[register.address + offset]
- if (byte === undefined) return null
- bytes.push(Number(byte) & 0xFF)
- }
- return bytes
- }
- function getRegisterWordsFromByteCache(register, byteCache) {
- const bytes = getRegisterBytesFromByteCache(register, byteCache)
- if (!bytes) return null
- return bytesToWords(bytes.length % 2 === 0 ? bytes : bytes.concat(0))
- }
- function decodeRegisterFromBytes(register, bytes) {
- if (!Array.isArray(bytes) || bytes.length < register.byteLength) return null
- return decodeRegisterValue(
- {
- ...register,
- byteOffset: 0
- },
- bytesToWords(bytes.length % 2 === 0 ? bytes : bytes.concat(0))
- )
- }
- function decodeRegisterFromWordCache(register, wordCache) {
- const words = getRegisterWordsFromWordCache(register, wordCache)
- if (!words) return null
- return decodeRegisterValue(register, words)
- }
- function decodeRegisterFromByteCache(register, byteCache) {
- const bytes = getRegisterBytesFromByteCache(register, byteCache)
- if (!bytes) return null
- return decodeRegisterFromBytes(register, bytes)
- }
- function getRegisterEncodedWords(register) {
- return encodeRegisterWords({
- ...register,
- inputValue: getRegisterWriteValueText(register)
- })
- }
- function getRegisterEncodedBytes(register) {
- return encodeRegisterBytes({
- ...register,
- inputValue: getRegisterWriteValueText(register)
- })
- }
- function getRegisterByteStart(register, groupStartAddress = 0) {
- if (Number.isFinite(Number(register.byteStart))) {
- return Math.max(0, Math.floor(Number(register.byteStart)))
- }
- return Math.max(0, ((Number(register.address) || 0) - (Number(groupStartAddress) || 0)) * 2 + (Number(register.byteOffset) || 0))
- }
- function getGroupEncodedBytes(group, baseBytes = null) {
- const byteLength = Math.max(2, Number(group && group.paddedByteLength) || ((Number(group && group.wordQuantity) || 1) * 2))
- const bytes = Array.isArray(baseBytes)
- ? baseBytes.slice(0, byteLength).map((byte) => Number(byte) & 0xFF)
- : []
- const registers = Array.isArray(group && group.registers) ? group.registers : []
- while (bytes.length < byteLength) {
- bytes.push(0)
- }
- registers.forEach((register) => {
- const byteStart = getRegisterByteStart(register, group.startAddress)
- if (isBitFieldRegister(register)) {
- const encodedBytes = encodeBitFieldIntoBytes(
- {
- ...register,
- inputValue: getRegisterWriteValueText(register)
- },
- bytes,
- byteStart
- )
- if (!Array.isArray(encodedBytes)) {
- throw new Error(`${register.name || '位域'} 没有有效写入值`)
- }
- return
- }
- const registerBytes = encodeRegisterBytes(register)
- if (!Array.isArray(registerBytes) || !registerBytes.length) {
- throw new Error(`${register.name || '寄存器'} 没有有效写入值`)
- }
- for (let offset = 0; offset < register.byteLength; offset += 1) {
- if (byteStart + offset < bytes.length) {
- bytes[byteStart + offset] = Number(registerBytes[offset] || 0) & 0xFF
- }
- }
- })
- return bytes
- }
- function getGroupEncodedWords(group, baseBytes = null) {
- return bytesToWords(getGroupEncodedBytes(group, baseBytes))
- }
- function validateRegisterValue(register, value) {
- return validateCodecRegisterValue(
- register,
- value === undefined || value === null ? getRegisterWriteValueText(register) : value
- )
- }
- module.exports = {
- decodeRegisterFromByteCache,
- decodeRegisterFromBytes,
- decodeRegisterFromWordCache,
- getGroupEncodedBytes,
- getGroupEncodedWords,
- getRegisterBytesFromByteCache,
- getRegisterEncodedBytes,
- getRegisterEncodedWords,
- getRegisterWordsFromByteCache,
- getRegisterWordsFromWordCache,
- getRegisterWriteValueText,
- splitWordSpans,
- validateRegisterValue
- }
|