modbus-connect
Version:
Modbus RTU over Web Serial and Node.js SerialPort
82 lines (66 loc) • 3.07 kB
JavaScript
// function-codes/SGM130/read-device-comment.js
const FUNCTION_CODE = 0x14;
const MAX_CHANNEL = 255;
const MAX_COMMENT_LENGTH = 16;
const REQUEST_SIZE = 2;
const RESPONSE_HEADER_SIZE = 3;
// Оптимизированная таблица символов как Uint8Array (индекс = код символа)
const SYMBOL_TABLE = new Uint8Array(256).fill(32); // Заполняем пробелами по умолчанию
// Инициализация таблицы символов (выполняется один раз при загрузке модуля)
(function initSymbolTable() {
// Цифры и латинские буквы
const symbols = ' 0123456789ABCDEFGHIJKLMNOPQRSTUVXYZ';
for (let i = 0; i < symbols.length; i++) {
SYMBOL_TABLE[i] = symbols.charCodeAt(i);
}
// Русские буквы
const cyrillic = 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ';
for (let i = 0; i < cyrillic.length; i++) {
SYMBOL_TABLE[37 + i] = cyrillic.charCodeAt(i);
}
})();
function buildReadDeviceCommentRequest(channel) {
// Быстрая проверка канала
if ((channel | 0) !== channel || channel < 0 || channel > MAX_CHANNEL) {
throw new RangeError(`Channel must be 0-${MAX_CHANNEL}`);
}
const request = new Uint8Array(REQUEST_SIZE);
request[0] = FUNCTION_CODE;
request[1] = channel;
return request;
}
function parseReadDeviceCommentResponse(pdu) {
if (!(pdu instanceof Uint8Array)) {
throw new TypeError('PDU must be Uint8Array');
}
const pduLength = pdu.length;
if (pduLength < RESPONSE_HEADER_SIZE) {
throw new Error(`PDU too short: expected at least ${RESPONSE_HEADER_SIZE} bytes`);
}
if (pdu[0] !== FUNCTION_CODE) {
throw new Error(`Invalid function code: expected 0x${FUNCTION_CODE.toString(16)}, got 0x${pdu[0].toString(16)}`);
}
const channel = pdu[1];
const length = pdu[2];
if (length > MAX_COMMENT_LENGTH) {
throw new Error(`Comment too long: max ${MAX_COMMENT_LENGTH} bytes, got ${length}`);
}
if (pduLength < RESPONSE_HEADER_SIZE + length) {
throw new Error(`PDU length mismatch: expected ${RESPONSE_HEADER_SIZE + length} bytes, got ${pduLength}`);
}
// Оптимизированное чтение и преобразование данных
const raw = new Uint8Array(pdu.buffer, pdu.byteOffset + RESPONSE_HEADER_SIZE, length);
const commentBuffer = new Uint8Array(length);
for (let i = 0; i < length; i++) {
commentBuffer[i] = SYMBOL_TABLE[raw[i]] || 32; // 32 = пробел
}
return {
channel,
raw: Array.from(raw), // Конвертируем в обычный массив для совместимости
comment: new TextDecoder('windows-1251').decode(commentBuffer)
};
}
module.exports = {
buildReadDeviceCommentRequest,
parseReadDeviceCommentResponse
};