From b19d112552be634fdd4360a951b48e7593c6b152 Mon Sep 17 00:00:00 2001 From: Mathew Date: Thu, 28 Sep 2023 13:04:02 +1000 Subject: [PATCH] reduce zcl callstack --- lib/Af.js | 108 ++++++++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 60 deletions(-) diff --git a/lib/Af.js b/lib/Af.js index ae6280e..4da792b 100644 --- a/lib/Af.js +++ b/lib/Af.js @@ -74,7 +74,6 @@ class Af extends EventEmitter { // 4 types of message: dataConfirm, reflectError, incomingMsg, incomingMsgExt, zclIncomingMsg dispatchIncomingMsg(targetEp, remoteEp, type, msg) { let dispatchTo, // which callback on targetEp - zclHeader assert(targetEp, 'targetEp should be given.'); @@ -100,75 +99,65 @@ class Af extends EventEmitter { case 'incomingMsg': assert(remoteEp, 'remoteEp should be given.'); // msg: { groupid, clusterid, srcaddr, srcendpoint, dstendpoint, wasbroadcast, linkquality, securityuse, timestamp, transseqnumber, len, data } - zclHeader = zcl.header(msg.data); // a zcl packet maybe, pre-parse it to get the header + + // todo: just isZcl dispatchTo = (type === "incomingMsg") ? targetEp.onAfIncomingMsg : targetEp.onAfIncomingMsgExt; break; - case 'zclIncomingMsg': { - // msg.data is now msg.zclMsg - - const frameType = msg.zclMsg.frameCntl.frameType; - zclDebug(`0x${msg.srcaddr.toString(16)}:${msg.srcendpoint}->0x00:${msg.dstendpoint} (${msg.zclMsg.seqNum}) ${msg.clusterid} ${frameType === 0 ? 'foundation' : 'functional'}(${msg.zclMsg.cmdId}) ${JSON.stringify(msg.zclMsg.payload)}`); + } - if(msg.zclMsg.frameCntl.direction === 1) { - let prefix = 'ZCL:'+((frameType === 0 && msg.zclMsg.cmdId !== 'defaultRsp') ? 'foundation' : 'functional')+':' - - // for broadcast responses only - this.emit(prefix + msg.dstendpoint + ':' + msg.zclMsg.seqNum, msg); + if (dispatchTo) { + dispatchTo.call(targetEp, msg, remoteEp); + } - prefix += msg.srcaddr.toString(16) + ':' + msg.srcendpoint + ':' + if(type !== 'incomingMsgExt' && type !== 'incomingMsg') return - // { groupid, clusterid, srcaddr, srcendpoint, dstendpoint, wasbroadcast, linkquality, securityuse, timestamp, transseqnumber, zclMsg } - this.emit(prefix + msg.dstendpoint + ':' + msg.zclMsg.seqNum, msg); + let zclData + + // after zcl packet parsed, re-emit it + try { + if (zclData.frameCntl.frameType === 0) { // foundation + zclData = zcl.parse(msg.data); + } else if (zclData.frameCntl.frameType === 1) { // functional + zclData = zcl.parse(msg.data, msg.clusterid); + } + } catch (ex) { + debug(`Error parsing ZCL ${zclData.frameCntl.frameType ? 'functional' : 'foundation'} packet: ${ex}`); + } - this.emit(prefix + msg.zclMsg.seqNum, msg); - } + if (zclData) { + this.emit('ZCL:incomingMsg', {zclData, msg}); - // Necessary, some IAS devices don't respect endpoints - if (remoteEp) { - if (msg.zclMsg.cmdId === 'statusChangeNotification' && frameType === 1 && msg.zclMsg.payload) { - this.emit('ind:statusChange', { ep: remoteEp, cId: msg.clusterid, payload: msg.zclMsg.payload, msg }); - } + const frameType = zclData.frameCntl.frameType; + if(zclDebug.enabled){ + zclDebug(`0x${msg.srcaddr.toString(16)}:${msg.srcendpoint}->0x00:${msg.dstendpoint} (${zclData.seqNum}) ${msg.clusterid} ${frameType === 0 ? 'foundation' : 'functional'}(${zclData.cmdId}) ${JSON.stringify(zclData.payload)}`); + } - if (frameType === 0 && msg.zclMsg.cmdId === 'report') - this.emit('ind:reported', { ep: remoteEp, cId: msg.clusterid, attrs: msg.zclMsg.payload }); - } + if(zclData.frameCntl.direction === 1) { + let prefix = 'ZCL:'+((frameType === 0 && zclData.cmdId !== 'defaultRsp') ? 'foundation' : 'functional')+':' + + // for broadcast responses only + this.emit(prefix + msg.dstendpoint + ':' + zclData.seqNum, msg); - if (frameType === 0) // foundation - dispatchTo = targetEp.onZclFoundation; - else if (frameType === 1) // functional - dispatchTo = targetEp.onZclFunctional; - break; - } - } + prefix += msg.srcaddr.toString(16) + ':' + msg.srcendpoint + ':' - if (dispatchTo) { - dispatchTo.call(targetEp, msg, remoteEp); - } + // { groupid, clusterid, srcaddr, srcendpoint, dstendpoint, wasbroadcast, linkquality, securityuse, timestamp, transseqnumber, zclMsg } + this.emit(prefix + msg.dstendpoint + ':' + zclData.seqNum, msg); - // no need for further parsing - if (type === 'zclIncomingMsg') - return; + this.emit(prefix + zclData.seqNum, msg); + } - // further parse for ZCL packet from incomingMsg and incomingMsgExt - if (zclHeader) { // if (zclHeader && targetEp.isZclSupported()) { - // after zcl packet parsed, re-emit it - let zclData - try { - if (zclHeader.frameCntl.frameType === 0) { // foundation - zclData = zcl.parse(msg.data); - } else if (zclHeader.frameCntl.frameType === 1) { // functional - zclData = zcl.parse(msg.data, msg.clusterid); - } - } catch (ex) { - debug(`Error parsing ZCL ${zclHeader.frameCntl.frameType ? 'functional' : 'foundation'} packet: ${ex}`); + // Necessary, some IAS devices don't respect endpoints + if (zclData.cmdId === 'statusChangeNotification' && frameType === 1 && zclData.payload) { + this.emit('ind:statusChange', { ep: remoteEp, cId: msg.clusterid, payload: zclData.payload, msg }); } - if (zclData) { - let parsedMsg = JSON.parse(JSON.stringify(msg)) - parsedMsg.zclMsg = zclData; + if (frameType === 0 && zclData.cmdId === 'report') + this.emit('ind:reported', { ep: remoteEp, cId: msg.clusterid, attrs: zclData.payload }); - this.emit('ZCL:incomingMsg', parsedMsg); - } + if (frameType === 0 && targetEp.onZclFoundation) // foundation + targetEp.onZclFoundation(msg, zclData, remoteEp) + else if (frameType === 1 && targetEp.onZclFunctional) // functional + targetEp.onZclFunctional(msg, zclData, remoteEp) } } makeAfParamsExt(srcEp, addrMode, dstAddrOrGrpId, cId, rawPayload, opt) { @@ -867,11 +856,10 @@ class Af extends EventEmitter { } Af.msgHandlers = [ - { evt: 'AF:dataConfirm', hdlr: 'dataConfirm', self: false }, - { evt: 'AF:reflectError', hdlr: 'reflectError', self: false }, - { evt: 'AF:incomingMsg', hdlr: 'incomingMsg', self: false }, - { evt: 'AF:incomingMsgExt', hdlr: 'incomingMsgExt', self: false }, - { evt: 'ZCL:incomingMsg', hdlr: 'zclIncomingMsg', self: true } + { evt: 'AF:dataConfirm', hdlr: 'dataConfirm' }, + { evt: 'AF:reflectError', hdlr: 'reflectError' }, + { evt: 'AF:incomingMsg', hdlr: 'incomingMsg' }, + { evt: 'AF:incomingMsgExt', hdlr: 'incomingMsgExt' } ]; /*************************************************************************************************/