const { DATA_TYPE_OPTIONS, DEFAULT_DATA_TYPE, DEFAULT_TEXT_BYTE_LENGTH, GROUP_LAYOUT_STRUCT, MAX_TEXT_BYTE_LENGTH } = require('./constants.js') function getDataType(dataType) { return DATA_TYPE_OPTIONS.find((item) => item.key === dataType) || DATA_TYPE_OPTIONS.find((item) => item.key === DEFAULT_DATA_TYPE) || DATA_TYPE_OPTIONS[0] } function getDataTypeIndex(dataType) { return Math.max(0, DATA_TYPE_OPTIONS.findIndex((item) => item.key === getDataType(dataType).key)) } function normalizeTextByteLength(value, fallback = DEFAULT_TEXT_BYTE_LENGTH) { const numberValue = Number(value) const rounded = Number.isFinite(numberValue) ? Math.round(numberValue) : fallback return Math.min(Math.max(rounded, 1), MAX_TEXT_BYTE_LENGTH) } function alignEvenByteLength(byteLength) { const length = Math.max(1, Math.round(Number(byteLength) || 1)) return length % 2 === 0 ? length : length + 1 } function getRegisterTextByteLength(register = {}) { return normalizeTextByteLength(register.textByteLength, DEFAULT_TEXT_BYTE_LENGTH) } function isStructLayout(layout) { return layout === GROUP_LAYOUT_STRUCT } function isBitFieldRegister(register = {}) { return !!register.isBitField } function normalizeBitOffset(value) { const numberValue = Math.floor(Number(value) || 0) return Math.min(Math.max(numberValue, 0), 7) } function normalizeBitWidth(value) { const numberValue = Math.round(Number(value) || 1) return Math.min(Math.max(numberValue, 1), 32) } function getBitFieldByteLength(register = {}) { const bitOffset = normalizeBitOffset(register.bitOffset) const bitWidth = normalizeBitWidth(register.bitWidth) return Math.max(1, Math.ceil((bitOffset + bitWidth) / 8)) } function getBitFieldMaxValue(register = {}) { const bitWidth = normalizeBitWidth(register.bitWidth) return bitWidth >= 32 ? 0xFFFFFFFF : Math.pow(2, bitWidth) - 1 } function getRegisterByteLength(dataType, register = {}) { if (isBitFieldRegister(register)) return getBitFieldByteLength(register) const type = getDataType(dataType) if (type.kind === 'text') { const byteLength = getRegisterTextByteLength(register) return isStructLayout(register.layout) ? byteLength : alignEvenByteLength(byteLength) } return type.byteLength || ((type.wordCount || 1) * 2) } function getRegisterWordCount(dataType, register = {}) { return Math.max(1, Math.ceil(getRegisterByteLength(dataType, register) / 2)) } function getByteSpanWordCount(byteOffset, byteLength) { return Math.max(1, Math.ceil((Math.max(0, Number(byteOffset) || 0) + Math.max(1, Number(byteLength) || 1)) / 2)) } function getRegisterWordCountAtOffset(dataType, byteOffset, register = {}) { const byteLength = getRegisterByteLength(dataType, register) return getByteSpanWordCount(byteOffset, byteLength) } function isTextRegister(dataType) { return getDataType(dataType).kind === 'text' } function getEncodeByteLimit(register) { return isTextRegister(register.dataType) ? getRegisterTextByteLength(register) : getRegisterByteLength(register.dataType, register) } function isByteRegister(dataType) { const key = getDataType(dataType).key return key === 'int8_t' || key === 'uint8_t' } function isBitRegisterType(registerType) { return registerType === 'coil' || registerType === 'discrete' } function isHexRegister(dataType) { return getDataType(dataType).key === 'hex' } function isNumericRegister(dataType) { return getDataType(dataType).kind === 'number' } function supportsRange(dataType) { return isNumericRegister(dataType) || isHexRegister(dataType) } function supportsUnit(dataType) { return isNumericRegister(dataType) } function getRegisterValueTypeLabel(dataType) { return getDataType(dataType).label } module.exports = { alignEvenByteLength, getBitFieldByteLength, getBitFieldMaxValue, getDataType, getDataTypeIndex, getEncodeByteLimit, getRegisterByteLength, getRegisterTextByteLength, getRegisterValueTypeLabel, getRegisterWordCount, getRegisterWordCountAtOffset, isBitFieldRegister, isBitRegisterType, isByteRegister, isHexRegister, isNumericRegister, isTextRegister, normalizeBitOffset, normalizeBitWidth, normalizeTextByteLength, supportsRange, supportsUnit }