UNPKG

zigbee-herdsman

Version:

An open source ZigBee gateway solution with node.js.

775 lines 31.3 kB
"use strict"; /* istanbul ignore file */ /* eslint-disable */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.enableRtsTimeout = exports.readyToSend = exports.apsBusyQueue = exports.busyQueue = void 0; exports.enableRTS = enableRTS; exports.disableRTS = disableRTS; const events_1 = __importDefault(require("events")); const net_1 = __importDefault(require("net")); const slip_1 = __importDefault(require("slip")); const logger_1 = require("../../../utils/logger"); const serialPort_1 = require("../../serialPort"); const socketPortUtils_1 = __importDefault(require("../../socketPortUtils")); const constants_1 = __importDefault(require("./constants")); const frameParser_1 = require("./frameParser"); const parser_1 = __importDefault(require("./parser")); const writer_1 = __importDefault(require("./writer")); const NS = 'zh:deconz:driver'; const queue = []; exports.busyQueue = []; const apsQueue = []; exports.apsBusyQueue = []; const apsConfirmIndQueue = []; exports.readyToSend = true; function enableRTS() { if (exports.readyToSend === false) { exports.readyToSend = true; } } function disableRTS() { exports.readyToSend = false; } class Driver extends events_1.default.EventEmitter { path; serialPort; initialized; writer; parser; frameParserEvent = frameParser_1.frameParserEvents; seqNumber; timeoutResetTimeout; apsRequestFreeSlots; apsDataConfirm; apsDataIndication; configChanged; socketPort; DELAY; READY_TO_SEND_TIMEOUT; HANDLE_DEVICE_STATUS_DELAY; PROCESS_QUEUES; timeoutCounter = 0; currentBaudRate = 0; constructor(path) { super(); this.path = path; this.initialized = false; this.seqNumber = 0; this.timeoutResetTimeout = null; this.apsRequestFreeSlots = 1; this.apsDataConfirm = 0; this.apsDataIndication = 0; this.configChanged = 0; this.DELAY = 0; this.READY_TO_SEND_TIMEOUT = 1; this.HANDLE_DEVICE_STATUS_DELAY = 5; this.PROCESS_QUEUES = 5; this.writer = new writer_1.default(); this.parser = new parser_1.default(); const that = this; setInterval(() => { that.deviceStateRequest() .then((result) => { }) .catch((error) => { }); }, 10000); setInterval(() => { that.writeParameterRequest(0x26, 600) // reset watchdog // 10 minutes .then((result) => { }) .catch((error) => { //try again logger_1.logger.debug('try again to reset watchdog', NS); that.writeParameterRequest(0x26, 600) .then((result) => { }) .catch((error) => { logger_1.logger.debug('warning watchdog was not reset', NS); }); }); }, 1000 * 60 * 8); // 8 minutes this.onParsed = this.onParsed.bind(this); this.frameParserEvent.on('receivedDataNotification', (data) => { this.catchPromise(this.checkDeviceStatus(data)); }); this.on('close', () => { this.intervals.forEach((i) => clearInterval(i)); queue.length = 0; exports.busyQueue.length = 0; apsQueue.length = 0; exports.apsBusyQueue.length = 0; apsConfirmIndQueue.length = 0; this.timeoutCounter = 0; }); } intervals = []; registerInterval(interval) { this.intervals.push(interval); } catchPromise(val) { return Promise.resolve(val).catch((err) => logger_1.logger.debug(`Promise was caught with reason: ${err}`, NS)); } setDelay(delay) { logger_1.logger.debug(`Set delay to ${delay}`, NS); this.DELAY = delay; this.READY_TO_SEND_TIMEOUT = delay; this.PROCESS_QUEUES = delay; this.HANDLE_DEVICE_STATUS_DELAY = delay; if (this.READY_TO_SEND_TIMEOUT === 0) { this.READY_TO_SEND_TIMEOUT = 1; } if (this.PROCESS_QUEUES < 5) { this.PROCESS_QUEUES = 5; } if (this.HANDLE_DEVICE_STATUS_DELAY < 5) { this.HANDLE_DEVICE_STATUS_DELAY = 5; } if (this.PROCESS_QUEUES > 60) { this.PROCESS_QUEUES = 60; } if (this.HANDLE_DEVICE_STATUS_DELAY > 60) { this.HANDLE_DEVICE_STATUS_DELAY = 60; } const that = this; this.registerInterval(setInterval(() => { that.processQueue(); }, this.PROCESS_QUEUES)); // fire non aps requests this.registerInterval(setInterval(() => { this.catchPromise(that.processBusyQueue()); }, this.PROCESS_QUEUES)); // check timeouts for non aps requests this.registerInterval(setInterval(() => { this.catchPromise(that.processApsQueue()); }, this.PROCESS_QUEUES)); // fire aps request this.registerInterval(setInterval(() => { that.processApsBusyQueue(); }, this.PROCESS_QUEUES)); // check timeouts for all open aps requests this.registerInterval(setInterval(() => { this.catchPromise(that.processApsConfirmIndQueue()); }, this.PROCESS_QUEUES)); // fire aps indications and confirms this.registerInterval(setInterval(() => { this.catchPromise(that.handleDeviceStatus()); }, this.HANDLE_DEVICE_STATUS_DELAY)); // query confirm and indication requests } onPortClose() { logger_1.logger.debug('Port closed', NS); this.initialized = false; this.emit('close'); } async open(baudrate) { this.currentBaudRate = baudrate; return socketPortUtils_1.default.isTcpPath(this.path) ? this.openSocketPort() : this.openSerialPort(baudrate); } openSerialPort(baudrate) { logger_1.logger.debug(`Opening with ${this.path}`, NS); this.serialPort = new serialPort_1.SerialPort({ path: this.path, baudRate: baudrate, autoOpen: false }); //38400 RaspBee //115200 ConBee3 this.writer.pipe(this.serialPort); this.serialPort.pipe(this.parser); this.parser.on('parsed', this.onParsed); return new Promise((resolve, reject) => { this.serialPort.open((error) => { if (error) { reject(new Error(`Error while opening serialport '${error}'`)); this.initialized = false; if (this.serialPort.isOpen) { this.serialPort.close(); } } else { logger_1.logger.debug('Serialport opened', NS); this.initialized = true; resolve(); } }); }); } async openSocketPort() { const info = socketPortUtils_1.default.parseTcpPath(this.path); logger_1.logger.debug(`Opening TCP socket with ${info.host}:${info.port}`, NS); this.socketPort = new net_1.default.Socket(); this.socketPort.setNoDelay(true); this.socketPort.setKeepAlive(true, 15000); this.writer = new writer_1.default(); this.writer.pipe(this.socketPort); this.parser = new parser_1.default(); this.socketPort.pipe(this.parser); this.parser.on('parsed', this.onParsed); return new Promise((resolve, reject) => { this.socketPort.on('connect', function () { logger_1.logger.debug('Socket connected', NS); }); const self = this; this.socketPort.on('ready', async function () { logger_1.logger.debug('Socket ready', NS); self.initialized = true; resolve(); }); this.socketPort.once('close', this.onPortClose); this.socketPort.on('error', function () { logger_1.logger.debug('Socket error', NS); reject(new Error(`Error while opening socket`)); self.initialized = false; }); this.socketPort.connect(info.port, info.host); }); } close() { return new Promise((resolve, reject) => { if (this.initialized) { if (this.serialPort) { this.serialPort.flush(() => { this.serialPort.close((error) => { this.initialized = false; error == null ? resolve() : reject(new Error(`Error while closing serialport '${error}'`)); this.emit('close'); }); }); } else { this.socketPort.destroy(); resolve(); } } else { resolve(); this.emit('close'); } }); } readParameterRequest(parameterId) { const seqNumber = this.nextSeqNumber(); return new Promise((resolve, reject) => { //logger.debug(`push read parameter request to queue. seqNr: ${seqNumber} paramId: ${parameterId}`, NS); const ts = 0; const commandId = constants_1.default.PARAM.FrameType.ReadParameter; const req = { commandId, parameterId, seqNumber, resolve, reject, ts }; queue.push(req); }); } writeParameterRequest(parameterId, parameter) { const seqNumber = this.nextSeqNumber(); return new Promise((resolve, reject) => { //logger.debug(`push write parameter request to queue. seqNr: ${seqNumber} paramId: ${parameterId} parameter: ${parameter}`, NS); const ts = 0; const commandId = constants_1.default.PARAM.FrameType.WriteParameter; const req = { commandId, parameterId, parameter, seqNumber, resolve, reject, ts }; queue.push(req); }); } readFirmwareVersionRequest() { const seqNumber = this.nextSeqNumber(); return new Promise((resolve, reject) => { //logger.debug(`push read firmware version request to queue. seqNr: ${seqNumber}`, NS); const ts = 0; const commandId = constants_1.default.PARAM.FrameType.ReadFirmwareVersion; const req = { commandId, seqNumber, resolve, reject, ts }; queue.push(req); }); } sendReadParameterRequest(parameterId, seqNumber) { /* command id, sequence number, 0, framelength(U16), payloadlength(U16), parameter id */ if (parameterId === constants_1.default.PARAM.Network.NETWORK_KEY) { this.sendRequest(Buffer.from([constants_1.default.PARAM.FrameType.ReadParameter, seqNumber, 0x00, 0x09, 0x00, 0x02, 0x00, parameterId, 0x00])); } else { this.sendRequest(Buffer.from([constants_1.default.PARAM.FrameType.ReadParameter, seqNumber, 0x00, 0x08, 0x00, 0x01, 0x00, parameterId])); } } sendWriteParameterRequest(parameterId, value, seqNumber) { /* command id, sequence number, 0, framelength(U16), payloadlength(U16), parameter id, pameter */ let parameterLength = 0; if (parameterId === constants_1.default.PARAM.STK.Endpoint) { let arrayParameterValue = value; parameterLength = arrayParameterValue.length; } else { parameterLength = this.getLengthOfParameter(parameterId); } //logger.debug("SEND WRITE_PARAMETER Request - parameter id: " + parameterId + " value: " + value.toString(16) + " length: " + parameterLength, NS); const payloadLength = 1 + parameterLength; const frameLength = 7 + payloadLength; const fLength1 = frameLength & 0xff; const fLength2 = frameLength >> 8; const pLength1 = payloadLength & 0xff; const pLength2 = payloadLength >> 8; if (parameterId === constants_1.default.PARAM.Network.NETWORK_KEY) { this.sendRequest(Buffer.from([constants_1.default.PARAM.FrameType.WriteParameter, seqNumber, 0x00, 0x19, 0x00, 0x12, 0x00, parameterId, 0x00].concat(value))); } else { this.sendRequest(Buffer.from([ constants_1.default.PARAM.FrameType.WriteParameter, seqNumber, 0x00, fLength1, fLength2, pLength1, pLength2, parameterId, ...this.parameterBuffer(value, parameterLength), ])); } } getLengthOfParameter(parameterId) { switch (parameterId) { case 9: case 16: case 21: case 28: case 33: case 36: return 1; case 5: case 7: case 34: return 2; case 10: case 38: return 4; case 1: case 8: case 11: case 14: return 8; case 24: case 25: return 16; default: return 0; } } parameterBuffer(parameter, parameterLength) { if (typeof parameter === 'number') { // for parameter <= 4 Byte if (parameterLength > 4) throw new Error('parameter to big for type number'); const buf = Buffer.alloc(parameterLength); buf.writeUIntLE(parameter, 0, parameterLength); return buf; } else { return Buffer.from(parameter.reverse()); } } sendReadFirmwareVersionRequest(seqNumber) { /* command id, sequence number, 0, framelength(U16) */ this.sendRequest(Buffer.from([constants_1.default.PARAM.FrameType.ReadFirmwareVersion, seqNumber, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00])); } sendReadDeviceStateRequest(seqNumber) { /* command id, sequence number, 0, framelength(U16) */ this.sendRequest(Buffer.from([constants_1.default.PARAM.FrameType.ReadDeviceState, seqNumber, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00])); } sendRequest(buffer) { const frame = Buffer.concat([buffer, this.calcCrc(buffer)]); const slipframe = slip_1.default.encode(frame); if (this.serialPort) { this.serialPort.write(slipframe, function (err) { if (err) { logger_1.logger.debug('Error writing serial Port: ' + err.message, NS); } }); } else { this.socketPort.write(slipframe, function (err) { if (err) { logger_1.logger.debug('Error writing socket Port: ' + err.message, NS); } }); } } processQueue() { if (queue.length === 0) { return; } if (exports.busyQueue.length > 0) { return; } const req = queue.shift(); if (req) { req.ts = Date.now(); switch (req.commandId) { case constants_1.default.PARAM.FrameType.ReadParameter: logger_1.logger.debug(`send read parameter request from queue. seqNr: ${req.seqNumber} paramId: ${req.parameterId}`, NS); this.sendReadParameterRequest(req.parameterId, req.seqNumber); break; case constants_1.default.PARAM.FrameType.WriteParameter: logger_1.logger.debug(`send write parameter request from queue. seqNr: ${req.seqNumber} paramId: ${req.parameterId} param: ${req.parameter}`, NS); this.sendWriteParameterRequest(req.parameterId, req.parameter, req.seqNumber); break; case constants_1.default.PARAM.FrameType.ReadFirmwareVersion: logger_1.logger.debug(`send read firmware version request from queue. seqNr: ${req.seqNumber}`, NS); this.sendReadFirmwareVersionRequest(req.seqNumber); break; case constants_1.default.PARAM.FrameType.ReadDeviceState: logger_1.logger.debug(`send read device state from queue. seqNr: ${req.seqNumber}`, NS); this.sendReadDeviceStateRequest(req.seqNumber); break; case constants_1.default.PARAM.NetworkState.CHANGE_NETWORK_STATE: logger_1.logger.debug(`send change network state request from queue. seqNr: ${req.seqNumber}`, NS); this.sendChangeNetworkStateRequest(req.seqNumber, req.networkState); break; default: throw new Error('process queue - unknown command id'); } exports.busyQueue.push(req); } } async processBusyQueue() { let i = exports.busyQueue.length; while (i--) { const req = exports.busyQueue[i]; const now = Date.now(); if (now - req.ts > 10000) { logger_1.logger.debug(`Timeout for request - CMD: 0x${req.commandId.toString(16)} seqNr: ${req.seqNumber}`, NS); //remove from busyQueue exports.busyQueue.splice(i, 1); this.timeoutCounter++; // after a timeout the timeoutcounter will be reset after 1 min. If another timeout happen then the timeoutcounter // will not be reset clearTimeout(this.timeoutResetTimeout); this.timeoutResetTimeout = null; this.resetTimeoutCounterAfter1min(); req.reject(new Error('TIMEOUT')); if (this.timeoutCounter >= 2) { this.timeoutCounter = 0; logger_1.logger.debug('too many timeouts - restart serial connecion', NS); if (this.serialPort?.isOpen) { this.serialPort.close(); } if (this.socketPort) { this.socketPort.destroy(); } await this.open(this.currentBaudRate); } } } } changeNetworkStateRequest(networkState) { const seqNumber = this.nextSeqNumber(); return new Promise((resolve, reject) => { //logger.debug(`push change network state request to apsQueue. seqNr: ${seqNumber}`, NS); const ts = 0; const commandId = constants_1.default.PARAM.NetworkState.CHANGE_NETWORK_STATE; const req = { commandId, networkState, seqNumber, resolve, reject, ts }; queue.push(req); }); } sendChangeNetworkStateRequest(seqNumber, networkState) { this.sendRequest(Buffer.from([constants_1.default.PARAM.NetworkState.CHANGE_NETWORK_STATE, seqNumber, 0x00, 0x06, 0x00, networkState])); } deviceStateRequest() { const seqNumber = this.nextSeqNumber(); return new Promise((resolve, reject) => { //logger.debug(`DEVICE_STATE Request - seqNr: ${seqNumber}`, NS); const ts = 0; const commandId = constants_1.default.PARAM.FrameType.ReadDeviceState; const req = { commandId, seqNumber, resolve, reject, ts }; queue.push(req); }); } async checkDeviceStatus(currentDeviceStatus) { const networkState = currentDeviceStatus & 0x03; this.apsDataConfirm = (currentDeviceStatus >> 2) & 0x01; this.apsDataIndication = (currentDeviceStatus >> 3) & 0x01; this.configChanged = (currentDeviceStatus >> 4) & 0x01; this.apsRequestFreeSlots = (currentDeviceStatus >> 5) & 0x01; logger_1.logger.debug('networkstate: ' + networkState + ' apsDataConfirm: ' + this.apsDataConfirm + ' apsDataIndication: ' + this.apsDataIndication + ' configChanged: ' + this.configChanged + ' apsRequestFreeSlots: ' + this.apsRequestFreeSlots, NS); } async handleDeviceStatus() { if (this.apsDataConfirm === 1) { try { logger_1.logger.debug('query aps data confirm', NS); this.apsDataConfirm = 0; const x = await this.querySendDataStateRequest(); } catch (error) { // @ts-expect-error TODO: this doesn't look right? if (error.status === 5) { this.apsDataConfirm = 0; } } } if (this.apsDataIndication === 1) { try { logger_1.logger.debug('query aps data indication', NS); this.apsDataIndication = 0; const x = await this.readReceivedDataRequest(); } catch (error) { // @ts-expect-error TODO: this doesn't look right? if (error.status === 5) { this.apsDataIndication = 0; } } } if (this.configChanged === 1) { // when network settings changed } } // DATA_IND readReceivedDataRequest() { const seqNumber = this.nextSeqNumber(); return new Promise((resolve, reject) => { //logger.debug(`push read received data request to apsQueue. seqNr: ${seqNumber}`, NS); const ts = 0; const commandId = constants_1.default.PARAM.APS.DATA_INDICATION; const req = { commandId, seqNumber, resolve, reject, ts }; apsConfirmIndQueue.push(req); }); } // DATA_REQ enqueueSendDataRequest(request) { const seqNumber = this.nextSeqNumber(); return new Promise((resolve, reject) => { //logger.debug(`push enqueue send data request to apsQueue. seqNr: ${seqNumber}`, NS); const ts = 0; const requestId = request.requestId; const commandId = constants_1.default.PARAM.APS.DATA_REQUEST; const req = { commandId, seqNumber, request, resolve, reject, ts }; apsQueue.push(req); }); } // DATA_CONF querySendDataStateRequest() { const seqNumber = this.nextSeqNumber(); return new Promise((resolve, reject) => { //logger.debug(`push query send data state request to apsQueue. seqNr: ${seqNumber}`, NS); const ts = 0; const commandId = constants_1.default.PARAM.APS.DATA_CONFIRM; const req = { commandId, seqNumber, resolve, reject, ts }; apsConfirmIndQueue.push(req); }); } async processApsQueue() { if (apsQueue.length === 0) { return; } if (this.apsRequestFreeSlots !== 1) { logger_1.logger.debug('no free slots. Delay sending of APS Request', NS); await this.sleep(1000); return; } const req = apsQueue.shift(); if (req) { req.ts = Date.now(); switch (req.commandId) { case constants_1.default.PARAM.APS.DATA_REQUEST: if (exports.readyToSend === false) { // wait until last request was confirmed or given time elapsed logger_1.logger.debug('delay sending of APS Request', NS); apsQueue.unshift(req); break; } else { disableRTS(); exports.enableRtsTimeout = setTimeout(function () { enableRTS(); }, this.READY_TO_SEND_TIMEOUT); exports.apsBusyQueue.push(req); this.sendEnqueueSendDataRequest(req.request, req.seqNumber); break; } default: throw new Error('process APS queue - unknown command id'); } } } async processApsConfirmIndQueue() { if (apsConfirmIndQueue.length === 0) { return; } const req = apsConfirmIndQueue.shift(); if (req) { req.ts = Date.now(); exports.apsBusyQueue.push(req); switch (req.commandId) { case constants_1.default.PARAM.APS.DATA_INDICATION: //logger.debug(`read received data request. seqNr: ${req.seqNumber}`, NS); if (this.DELAY === 0) { this.sendReadReceivedDataRequest(req.seqNumber); } else { await this.sendReadReceivedDataRequest(req.seqNumber); } break; case constants_1.default.PARAM.APS.DATA_CONFIRM: //logger.debug(`query send data state request. seqNr: ${req.seqNumber}`, NS); if (this.DELAY === 0) { this.sendQueryDataStateRequest(req.seqNumber); } else { await this.sendQueryDataStateRequest(req.seqNumber); } break; default: throw new Error('process APS Confirm/Ind queue - unknown command id'); } } } sendQueryDataStateRequest(seqNumber) { logger_1.logger.debug(`DATA_CONFIRM - sending data state request - SeqNr. ${seqNumber}`, NS); this.sendRequest(Buffer.from([constants_1.default.PARAM.APS.DATA_CONFIRM, seqNumber, 0x00, 0x07, 0x00, 0x00, 0x00])); } sendReadReceivedDataRequest(seqNumber) { logger_1.logger.debug(`DATA_INDICATION - sending read data request - SeqNr. ${seqNumber}`, NS); // payloadlength = 0, flag = none this.sendRequest(Buffer.from([constants_1.default.PARAM.APS.DATA_INDICATION, seqNumber, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01])); } sendEnqueueSendDataRequest(request, seqNumber) { const payloadLength = 12 + (request.destAddrMode === constants_1.default.PARAM.addressMode.GROUP_ADDR ? 2 : request.destAddrMode === constants_1.default.PARAM.addressMode.NWK_ADDR ? 3 : 9) + request.asduLength; const frameLength = 7 + payloadLength; const cid1 = request.clusterId & 0xff; const cid2 = (request.clusterId >> 8) & 0xff; const asdul1 = request.asduLength & 0xff; const asdul2 = (request.asduLength >> 8) & 0xff; let destArray = []; let dest = ''; if (request.destAddr16 !== undefined) { destArray[0] = request.destAddr16 & 0xff; destArray[1] = (request.destAddr16 >> 8) & 0xff; dest = request.destAddr16.toString(16); } if (request.destAddr64 !== undefined) { dest = request.destAddr64; destArray = this.macAddrStringToArray(request.destAddr64); } if (request.destEndpoint !== undefined) { destArray.push(request.destEndpoint); dest += ' EP:'; dest += request.destEndpoint; } logger_1.logger.debug(`DATA_REQUEST - destAddr: 0x${dest} SeqNr. ${seqNumber} request id: ${request.requestId}`, NS); this.sendRequest(Buffer.from([ constants_1.default.PARAM.APS.DATA_REQUEST, seqNumber, 0x00, frameLength & 0xff, (frameLength >> 8) & 0xff, payloadLength & 0xff, (payloadLength >> 8) & 0xff, request.requestId, 0x00, request.destAddrMode, ...destArray, request.profileId & 0xff, (request.profileId >> 8) & 0xff, cid1, cid2, request.srcEndpoint, asdul1, asdul2, ...request.asduPayload, request.txOptions, request.radius, ])); } processApsBusyQueue() { let i = exports.apsBusyQueue.length; while (i--) { const req = exports.apsBusyQueue[i]; const now = Date.now(); let timeout = 60000; if (req.request != null && req.request.timeout != null) { timeout = req.request.timeout * 1000; // seconds * 1000 = milliseconds } if (now - req.ts > timeout) { logger_1.logger.debug(`Timeout for aps request CMD: 0x${req.commandId.toString(16)} seq: ${req.seqNumber}`, NS); //remove from busyQueue exports.apsBusyQueue.splice(i, 1); req.reject(new Error('APS TIMEOUT')); } } } calcCrc(buffer) { let crc = 0; for (let i = 0; i < buffer.length; i++) { crc += buffer[i]; } const crc0 = (~crc + 1) & 0xff; const crc1 = ((~crc + 1) >> 8) & 0xff; return Buffer.from([crc0, crc1]); } macAddrStringToArray(addr) { if (addr.indexOf('0x') === 0) { addr = addr.slice(2, addr.length); } if (addr.length < 16) { for (let l = 0; l < 16 - addr.length; l++) { addr = '0' + addr; } } let result = new Array(); let y = 0; for (let i = 0; i < 8; i++) { result[i] = parseInt(addr.substr(y, 2), 16); y += 2; } const reverse = result.reverse(); return reverse; } macAddrArrayToString(addr) { if (addr.length != 8) { throw new Error('invalid array length for MAC address: ' + addr.length); } let result = '0x'; let char = ''; let i = 8; while (i--) { char = addr[i].toString(16); if (char.length < 2) { char = '0' + char; } result += char; } return result; } /** * generalArrayToString result is not reversed! */ generalArrayToString(key, length) { let result = '0x'; let char = ''; let i = 0; while (i < length) { char = key[i].toString(16); if (char.length < 2) { char = '0' + char; } result += char; i++; } return result; } nextSeqNumber() { this.seqNumber++; if (this.seqNumber > 254) { this.seqNumber = 1; } return this.seqNumber; } onParsed(frame) { this.emit('rxFrame', frame); } sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } resetTimeoutCounterAfter1min() { if (this.timeoutResetTimeout === null) { this.timeoutResetTimeout = setTimeout(() => { this.timeoutCounter = 0; this.timeoutResetTimeout = null; }, 60000); } } } exports.default = Driver; //# sourceMappingURL=driver.js.map