modbus-connect
Version:
Modbus RTU over Web Serial and Node.js SerialPort
93 lines (76 loc) • 3.15 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);
/**
* Строит PDU-запрос для чтения идентификации устройства
* @param {number} categoryId - категория идентификации (по умолчанию 0x01)
* @param {number} objectId - идентификатор объекта (по умолчанию 0x00)
* @returns {Uint8Array}
*/
function buildReadDeviceIdentificationRequest(categoryId = 0x01, objectId = 0x00) {
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);
}
/**
* Разбирает PDU-ответ с идентификацией устройства
* @param {Uint8Array} pdu
* @returns {Object} - объект с информацией об идентификации
* @throws {Error} При неверном формате ответа
*/
function parseReadDeviceIdentificationResponse(pdu) {
if (!(pdu instanceof Uint8Array)) {
throw new TypeError('Response must be Uint8Array');
}
const responseLength = pdu.length;
if (responseLength < MIN_RESPONSE_SIZE) {
throw new Error(`Response too short: expected at least ${MIN_RESPONSE_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)}`);
}
if (pdu[1] !== MEI_TYPE) {
throw new Error(`Invalid MEI type: expected 0x${MEI_TYPE.toString(16)}, got 0x${pdu[1].toString(16)}`);
}
const result = {
functionCode: pdu[0],
meiType: pdu[1],
category: pdu[2],
conformityLevel: pdu[3],
moreFollows: pdu[4],
nextObjectId: pdu[5],
numberOfObjects: pdu[6],
objects: {}
};
let offset = 7;
const numberOfObjects = result.numberOfObjects;
for (let i = 0; i < numberOfObjects; i++) {
if (offset + 2 > responseLength) {
throw new Error('Invalid object header length');
}
const objectId = pdu[offset];
const length = pdu[offset + 1];
offset += 2;
if (offset + length > responseLength) {
throw new Error('Invalid object data length');
}
// Декодируем строку напрямую из буфера
result.objects[objectId] = TEXT_DECODER.decode(
new Uint8Array(pdu.buffer, pdu.byteOffset + offset, length)
);
offset += length;
}
return result;
}
module.exports = {
buildReadDeviceIdentificationRequest,
parseReadDeviceIdentificationResponse
};