From 1a50e2e47f0b7364d32fdcb3f49531f481f95c55 Mon Sep 17 00:00:00 2001 From: Ivan Belokobylskiy Date: Fri, 30 Aug 2024 21:06:19 +0300 Subject: [PATCH] fix: Zigate: parse all values as big endian (#1170) --- src/adapter/zigate/driver/buffaloZiGate.ts | 66 +++++++++++++--------- src/adapter/zigate/driver/commandType.ts | 30 +++++----- src/adapter/zigate/driver/messageType.ts | 36 ++++++------ src/adapter/zigate/driver/parameterType.ts | 4 +- src/adapter/zigate/driver/zigate.ts | 4 +- 5 files changed, 74 insertions(+), 66 deletions(-) diff --git a/src/adapter/zigate/driver/buffaloZiGate.ts b/src/adapter/zigate/driver/buffaloZiGate.ts index eaa0916e25..8e7e724218 100644 --- a/src/adapter/zigate/driver/buffaloZiGate.ts +++ b/src/adapter/zigate/driver/buffaloZiGate.ts @@ -1,6 +1,7 @@ /* istanbul ignore file */ import {Buffalo} from '../../../buffalo'; +import {EUI64} from '../../../zspec/tstypes'; import {BuffaloZclOptions} from '../../../zspec/zcl/definition/tstype'; import {LOG_LEVEL} from './constants'; import ParameterType from './parameterType'; @@ -17,13 +18,13 @@ class BuffaloZiGate extends Buffalo { return this.writeUInt8(value); } case ParameterType.UINT16: { - return this.writeUInt16(value); + return this.writeUInt16BE(value); } case ParameterType.UINT32: { - return this.writeUInt32(value); + return this.writeUInt32BE(value); } case ParameterType.IEEEADDR: { - return this.writeIeeeAddr(value); + return this.writeIeeeAddrBE(value); } case ParameterType.BUFFER: { return this.writeBuffer(value, value.length); @@ -50,24 +51,18 @@ class BuffaloZiGate extends Buffalo { return this.writeListUInt8(value); } case ParameterType.LIST_UINT16: { - return this.writeListUInt16(value); + return this.writeListUInt16BE(value); } case ParameterType.INT8: { return this.writeInt8(value); } case ParameterType.ADDRESS_WITH_TYPE_DEPENDENCY: { const addressMode = this.buffer.readUInt8(this.position - 1); - return addressMode == 3 ? this.writeIeeeAddr(value) : this.writeUInt16BE(value); + return addressMode == 3 ? this.writeIeeeAddrBE(value) : this.writeUInt16BE(value); } case ParameterType.RAW: { return this.writeRaw(value); } - case ParameterType.UINT16BE: { - return this.writeUInt16BE(value); - } - case ParameterType.UINT32BE: { - return this.writeUInt32BE(value); - } } throw new Error(`Write for '${type}' not available`); @@ -79,13 +74,13 @@ class BuffaloZiGate extends Buffalo { return this.readUInt8(); } case ParameterType.UINT16: { - return this.readUInt16(); + return this.readUInt16BE(); } case ParameterType.UINT32: { - return this.readUInt32(); + return this.readUInt32BE(); } case ParameterType.IEEEADDR: { - return this.readIeeeAddr(); + return this.readIeeeAddrBE(); } case ParameterType.BUFFER: { // if length option not specified, read the whole buffer @@ -113,7 +108,7 @@ class BuffaloZiGate extends Buffalo { return this.readListUInt8(options.length ?? 0); // XXX: should always be valid? } case ParameterType.LIST_UINT16: { - return this.readListUInt16(options.length ?? 0); // XXX: should always be valid? + return this.readListUInt16BE(options.length ?? 0); // XXX: should always be valid? } case ParameterType.INT8: { return this.readInt8(); @@ -141,13 +136,7 @@ class BuffaloZiGate extends Buffalo { } case ParameterType.ADDRESS_WITH_TYPE_DEPENDENCY: { const addressMode = this.buffer.readUInt8(this.position - 1); - return addressMode == 3 ? this.readIeeeAddr() : this.readUInt16BE(); - } - case ParameterType.UINT16BE: { - return this.readUInt16BE(); - } - case ParameterType.UINT32BE: { - return this.readUInt32BE(); + return addressMode == 3 ? this.readIeeeAddrBE() : this.readUInt16BE(); } case ParameterType.BUFFER_RAW: { const buffer = this.buffer.subarray(this.position); @@ -180,22 +169,43 @@ class BuffaloZiGate extends Buffalo { this.position += 2; return value; } + public writeUInt16BE(value: number): void { + this.buffer.writeUInt16BE(value, this.position); + this.position += 2; + } public readUInt32BE(): number { const value = this.buffer.readUInt32BE(this.position); this.position += 4; return value; } - - public writeUInt16BE(value: number): void { - this.buffer.writeUInt16BE(value, this.position); - this.position += 2; - } - public writeUInt32BE(value: number): void { this.buffer.writeUInt32BE(value, this.position); this.position += 4; } + + public readListUInt16BE(length: number): number[] { + const value: number[] = []; + for (let i = 0; i < length; i++) { + value.push(this.readUInt16BE()); + } + + return value; + } + public writeListUInt16BE(values: number[]): void { + for (const value of values) { + this.writeUInt16BE(value); + } + } + + public readIeeeAddrBE(): EUI64 { + const octets = Array.from(this.readBuffer(8)); + return `0x${octets.map((octet) => octet.toString(16).padStart(2, '0')).join('')}`; + } + public writeIeeeAddrBE(value: string /*TODO: EUI64*/): void { + this.writeUInt32BE(parseInt(value.slice(2, 10), 16)); + this.writeUInt32BE(parseInt(value.slice(10), 16)); + } } export default BuffaloZiGate; diff --git a/src/adapter/zigate/driver/commandType.ts b/src/adapter/zigate/driver/commandType.ts index 5cd05c129a..92c61fdf39 100644 --- a/src/adapter/zigate/driver/commandType.ts +++ b/src/adapter/zigate/driver/commandType.ts @@ -118,7 +118,7 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { [ZiGateCommandCode.ManagementLQI]: { // 0x004E request: [ - {name: 'targetAddress', parameterType: ParameterType.UINT16BE}, // Status + {name: 'targetAddress', parameterType: ParameterType.UINT16}, // Status {name: 'startIndex', parameterType: ParameterType.UINT8}, // ], response: [ @@ -162,13 +162,13 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { }, [ZiGateCommandCode.SetChannelMask]: { request: [ - {name: 'channelMask', parameterType: ParameterType.UINT32BE}, // + {name: 'channelMask', parameterType: ParameterType.UINT32}, // ], }, [ZiGateCommandCode.ManagementLeaveRequest]: { request: [ - {name: 'shortAddress', parameterType: ParameterType.UINT16BE}, + {name: 'shortAddress', parameterType: ParameterType.UINT16}, {name: 'extendedAddress', parameterType: ParameterType.IEEEADDR}, // {name: 'rejoin', parameterType: ParameterType.UINT8}, {name: 'removeChildren', parameterType: ParameterType.UINT8}, // @@ -223,7 +223,7 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { }, [ZiGateCommandCode.PermitJoin]: { request: [ - {name: 'targetShortAddress', parameterType: ParameterType.UINT16BE}, // - + {name: 'targetShortAddress', parameterType: ParameterType.UINT16}, // - // broadcast 0xfffc {name: 'interval', parameterType: ParameterType.UINT8}, // // 0 = Disable Joining @@ -236,7 +236,7 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { }, [ZiGateCommandCode.PermitJoinStatus]: { request: [ - {name: 'targetShortAddress', parameterType: ParameterType.UINT16BE}, // - + {name: 'targetShortAddress', parameterType: ParameterType.UINT16}, // - // broadcast 0xfffc {name: 'interval', parameterType: ParameterType.UINT8}, // // 0 = Disable Joining @@ -251,11 +251,11 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { [ZiGateCommandCode.RawAPSDataRequest]: { request: [ {name: 'addressMode', parameterType: ParameterType.UINT8}, //
- {name: 'targetShortAddress', parameterType: ParameterType.UINT16BE}, // + {name: 'targetShortAddress', parameterType: ParameterType.UINT16}, // {name: 'sourceEndpoint', parameterType: ParameterType.UINT8}, // {name: 'destinationEndpoint', parameterType: ParameterType.UINT8}, // - {name: 'clusterID', parameterType: ParameterType.UINT16BE}, // - {name: 'profileID', parameterType: ParameterType.UINT16BE}, // + {name: 'clusterID', parameterType: ParameterType.UINT16}, // + {name: 'profileID', parameterType: ParameterType.UINT16}, // {name: 'securityMode', parameterType: ParameterType.UINT8}, // {name: 'radius', parameterType: ParameterType.UINT8}, // {name: 'dataLength', parameterType: ParameterType.UINT8}, // @@ -264,7 +264,7 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { }, [ZiGateCommandCode.NodeDescriptor]: { request: [ - {name: 'targetShortAddress', parameterType: ParameterType.UINT16BE}, // + {name: 'targetShortAddress', parameterType: ParameterType.UINT16}, // ], response: [ [ @@ -288,7 +288,7 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { }, [ZiGateCommandCode.ActiveEndpoint]: { request: [ - {name: 'targetShortAddress', parameterType: ParameterType.UINT16BE}, // + {name: 'targetShortAddress', parameterType: ParameterType.UINT16}, // ], response: [ [ @@ -312,7 +312,7 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { }, [ZiGateCommandCode.SimpleDescriptor]: { request: [ - {name: 'targetShortAddress', parameterType: ParameterType.UINT16BE}, // + {name: 'targetShortAddress', parameterType: ParameterType.UINT16}, // {name: 'endpoint', parameterType: ParameterType.UINT8}, // ], response: [ @@ -335,7 +335,7 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { request: [ {name: 'targetExtendedAddress', parameterType: ParameterType.IEEEADDR}, // {name: 'targetEndpoint', parameterType: ParameterType.UINT8}, // - {name: 'clusterID', parameterType: ParameterType.UINT16BE}, // + {name: 'clusterID', parameterType: ParameterType.UINT16}, // {name: 'destinationAddressMode', parameterType: ParameterType.UINT8}, // { name: 'destinationAddress', @@ -373,7 +373,7 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { request: [ {name: 'targetExtendedAddress', parameterType: ParameterType.IEEEADDR}, // {name: 'targetEndpoint', parameterType: ParameterType.UINT8}, // - {name: 'clusterID', parameterType: ParameterType.UINT16BE}, // + {name: 'clusterID', parameterType: ParameterType.UINT16}, // {name: 'destinationAddressMode', parameterType: ParameterType.UINT8}, // { name: 'destinationAddress', @@ -410,10 +410,10 @@ export const ZiGateCommand: {[key: string]: ZiGateCommandType} = { [ZiGateCommandCode.AddGroup]: { request: [ {name: 'addressMode', parameterType: ParameterType.UINT8}, // - {name: 'shortAddress', parameterType: ParameterType.UINT16BE}, + {name: 'shortAddress', parameterType: ParameterType.UINT16}, {name: 'sourceEndpoint', parameterType: ParameterType.UINT8}, {name: 'destinationEndpoint', parameterType: ParameterType.UINT8}, - {name: 'groupAddress', parameterType: ParameterType.UINT16BE}, + {name: 'groupAddress', parameterType: ParameterType.UINT16}, ], }, }; diff --git a/src/adapter/zigate/driver/messageType.ts b/src/adapter/zigate/driver/messageType.ts index 3f4f65a2af..511e3e7cf7 100644 --- a/src/adapter/zigate/driver/messageType.ts +++ b/src/adapter/zigate/driver/messageType.ts @@ -20,7 +20,7 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { }, [ZiGateMessageCode.DeviceAnnounce]: { response: [ - {name: 'shortAddress', parameterType: ParameterType.UINT16BE}, + {name: 'shortAddress', parameterType: ParameterType.UINT16}, {name: 'ieee', parameterType: ParameterType.IEEEADDR}, {name: 'MACcapability', parameterType: ParameterType.MACCAPABILITY}, // MAC capability @@ -46,7 +46,7 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { // 128 – 244 = Failed (ZigBee event codes) // Packet Type: The value of the initiating command request. {name: 'sequence', parameterType: ParameterType.UINT8}, // - {name: 'packetType', parameterType: ParameterType.UINT16BE}, // + {name: 'packetType', parameterType: ParameterType.UINT16}, // // from 3.1d // {name: 'requestSent', parameterType: ParameterType.MAYBE_UINT8},// - 1 if a request been sent to @@ -71,8 +71,8 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { [ZiGateMessageCode.DataIndication]: { response: [ {name: 'status', parameterType: ParameterType.UINT8}, // - {name: 'profileID', parameterType: ParameterType.UINT16BE}, // - {name: 'clusterID', parameterType: ParameterType.UINT16BE}, // + {name: 'profileID', parameterType: ParameterType.UINT16}, // + {name: 'clusterID', parameterType: ParameterType.UINT16}, // {name: 'sourceEndpoint', parameterType: ParameterType.UINT8}, // {name: 'destinationEndpoint', parameterType: ParameterType.UINT8}, // {name: 'sourceAddressMode', parameterType: ParameterType.UINT8}, // @@ -119,9 +119,9 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { // {name: 'sourceEndpoint', parameterType: ParameterType.UINT8}, // // {name: 'destinationAddressMode', parameterType: ParameterType.UINT8}, // // - {name: 'destinationAddress', parameterType: ParameterType.UINT16BE}, + {name: 'destinationAddress', parameterType: ParameterType.UINT16}, {name: 'destinationEndpoint', parameterType: ParameterType.UINT8}, // - {name: 'clusterID', parameterType: ParameterType.UINT16BE}, + {name: 'clusterID', parameterType: ParameterType.UINT16}, // // {name: 'seqNumber', parameterType: ParameterType.UINT8}, // ], @@ -158,9 +158,9 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { }, [ZiGateMessageCode.NetworkState]: { response: [ - {name: 'shortAddress', parameterType: ParameterType.UINT16BE}, // + {name: 'shortAddress', parameterType: ParameterType.UINT16}, // {name: 'extendedAddress', parameterType: ParameterType.IEEEADDR}, // - {name: 'PANID', parameterType: ParameterType.UINT16BE}, // + {name: 'PANID', parameterType: ParameterType.UINT16}, // {name: 'ExtPANID', parameterType: ParameterType.IEEEADDR}, // {name: 'Channel', parameterType: ParameterType.UINT8}, // ], @@ -179,7 +179,7 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { // 0 = Joined existing network // 1 = Formed new network // 128 – 244 = Failed (ZigBee event codes) - {name: 'shortAddress', parameterType: ParameterType.UINT16BE}, // + {name: 'shortAddress', parameterType: ParameterType.UINT16}, // // {name: 'extendedAddress', parameterType: ParameterType.IEEEADDR}, // // {name: 'channel', parameterType: ParameterType.UINT8}, // ], @@ -200,15 +200,15 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { response: [ {name: 'status', parameterType: ParameterType.UINT8}, // // {name: 'nwkStatus', parameterType: ParameterType.UINT8}, // - // {name: 'dstAddress', parameterType: ParameterType.UINT16BE}, // + // {name: 'dstAddress', parameterType: ParameterType.UINT16}, // ], }, [ZiGateMessageCode.SimpleDescriptorResponse]: { response: [ {name: 'sourceEndpoint', parameterType: ParameterType.UINT8}, // - {name: 'profile ID', parameterType: ParameterType.UINT16BE}, // - {name: 'clusterID', parameterType: ParameterType.UINT16BE}, // - {name: 'attributeList', parameterType: ParameterType.LIST_UINT16BE}, // + {name: 'profile ID', parameterType: ParameterType.UINT16}, // + {name: 'clusterID', parameterType: ParameterType.UINT16}, // + {name: 'attributeList', parameterType: ParameterType.LIST_UINT16}, // ], }, [ZiGateMessageCode.ManagementLQIResponse]: { @@ -222,7 +222,7 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { // @TODO list TYPE // // Note: If Neighbour Table list count is 0, there are no elements in the list. - {name: 'NWKAddress', parameterType: ParameterType.UINT16BE}, // NWK Address : uint16_t + {name: 'NWKAddress', parameterType: ParameterType.UINT16}, // NWK Address : uint16_t {name: 'Extended PAN ID', parameterType: ParameterType.IEEEADDR}, // Extended PAN ID : uint64_t {name: 'IEEE Address', parameterType: ParameterType.IEEEADDR}, // IEEE Address : uint64_t {name: 'Depth', parameterType: ParameterType.UINT8}, // Depth : uint_t @@ -236,13 +236,13 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { // (0-Parent 1-Child 2-Sibling) // bit 6-7 Rx On When Idle status // (1-On 0-Off) - {name: 'srcAddress', parameterType: ParameterType.UINT16BE}, // ( only from v3.1a) + {name: 'srcAddress', parameterType: ParameterType.UINT16}, // ( only from v3.1a) ], }, [ZiGateMessageCode.PDMEvent]: { response: [ {name: 'eventStatus', parameterType: ParameterType.UINT8}, // - {name: 'recordID', parameterType: ParameterType.UINT32BE}, // + {name: 'recordID', parameterType: ParameterType.UINT32}, // ], }, [ZiGateMessageCode.PDMLoaded]: { @@ -281,8 +281,8 @@ export const ZiGateMessage: {[k: number]: ZiGateMessageType} = { }, [ZiGateMessageCode.AddGroupResponse]: { response: [ - {name: 'status', parameterType: ParameterType.UINT16BE}, - {name: 'groupAddress', parameterType: ParameterType.UINT16BE}, + {name: 'status', parameterType: ParameterType.UINT16}, + {name: 'groupAddress', parameterType: ParameterType.UINT16}, ], }, }; diff --git a/src/adapter/zigate/driver/parameterType.ts b/src/adapter/zigate/driver/parameterType.ts index 6f99276e3e..adafe1d10a 100644 --- a/src/adapter/zigate/driver/parameterType.ts +++ b/src/adapter/zigate/driver/parameterType.ts @@ -1,3 +1,4 @@ +// All multi-byte values are big-endian enum ParameterType { UINT8 = 0, UINT16 = 1, @@ -23,9 +24,6 @@ enum ParameterType { // /!\ TODO missing but used in code, IDs assigned for proper compiling, NOT based on spec, needs updating // /!\ some also don't have proper read/write in BuffaloZiGate BUFFER_RAW = 247, - UINT16BE = 248, - UINT32BE = 249, - LIST_UINT16BE = 251, MAYBE_UINT8 = 252, LOG_LEVEL = 253, STRING = 254, diff --git a/src/adapter/zigate/driver/zigate.ts b/src/adapter/zigate/driver/zigate.ts index 9b258fd270..cf10cc605e 100644 --- a/src/adapter/zigate/driver/zigate.ts +++ b/src/adapter/zigate/driver/zigate.ts @@ -263,7 +263,7 @@ export default class ZiGate extends EventEmitter { private onSerialData(buffer: Buffer): void { try { - // logger.debug(`--- parseNext `, buffer, NS); + // logger.debug(`--- parseNext ${JSON.stringify(buffer)}`, NS); const frame = new ZiGateFrame(buffer); if (!(frame instanceof ZiGateFrame)) return; // @Todo fix @@ -314,7 +314,7 @@ export default class ZiGate extends EventEmitter { } private waitressTimeoutFormatter(matcher: WaitressMatcher, timeout: number): string { - return `${matcher} after ${timeout}ms`; + return `${JSON.stringify(matcher)} after ${timeout}ms`; } private waitressValidator(ziGateObject: ZiGateObject, matcher: WaitressMatcher): boolean {