modbus-connect
Version:
Modbus RTU over Web Serial and Node.js SerialPort
88 lines (72 loc) • 3.1 kB
JavaScript
// function-codes/read-device-identification.js
const FUNCTION_CODE = 0x2B;
const MEI_TYPE = 0x0E;
const MIN_RESPONSE_SIZE = 7;
const TEXT_ENCODING = 'windows-1251';
// Создаем декодер один раз для повторного использования
const TEXT_DECODER = new TextDecoder(TEXT_ENCODING);
function buildReadDeviceIdentificationRequest(categoryId = 0x01, objectId = 0x00) {
// Используем ArrayBuffer + DataView для единообразия
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
view.setUint8(0, FUNCTION_CODE);
view.setUint8(1, MEI_TYPE);
view.setUint8(2, categoryId);
view.setUint8(3, objectId);
return new Uint8Array(buffer);
}
function parseReadDeviceIdentificationResponse(response) {
if (!(response instanceof Uint8Array)) {
throw new TypeError('Response must be Uint8Array');
}
const responseLength = response.length;
if (responseLength < MIN_RESPONSE_SIZE) {
throw new Error(`Response too short: expected at least ${MIN_RESPONSE_SIZE} bytes`);
}
// Используем оригинальный буфер без копирования
const buffer = response.buffer || response;
const byteOffset = response.byteOffset || 0;
const view = new DataView(buffer, byteOffset, responseLength);
const functionCode = view.getUint8(0);
if (functionCode !== FUNCTION_CODE) {
throw new Error(`Invalid function code: expected 0x${FUNCTION_CODE.toString(16)}, got 0x${functionCode.toString(16)}`);
}
const meiType = view.getUint8(1);
if (meiType !== MEI_TYPE) {
throw new Error(`Invalid MEI type: expected 0x${MEI_TYPE.toString(16)}, got 0x${meiType.toString(16)}`);
}
const result = {
functionCode,
meiType,
category: view.getUint8(2),
conformityLevel: view.getUint8(3),
moreFollows: view.getUint8(4),
nextObjectId: view.getUint8(5),
numberOfObjects: view.getUint8(6),
objects: Object.create(null) // Чистый объект без прототипа
};
let offset = 7;
const objects = result.objects;
const numberOfObjects = result.numberOfObjects;
for (let i = 0; i < numberOfObjects; i++) {
if (offset + 2 > responseLength) {
throw new Error('Invalid object header length');
}
const objectId = view.getUint8(offset);
const length = view.getUint8(offset + 1);
offset += 2;
if (offset + length > responseLength) {
throw new Error('Invalid object data length');
}
// Декодируем строку напрямую из буфера
objects[objectId] = TEXT_DECODER.decode(
new Uint8Array(buffer, byteOffset + offset, length)
);
offset += length;
}
return result;
}
module.exports = {
buildReadDeviceIdentificationRequest,
parseReadDeviceIdentificationResponse
};