diff --git a/README.md b/README.md index 4ad7a8b..1bd8312 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # acn-js not sure how far I will take this but messing around with E1.17 ACN protocol -## areas +## packet decoding - rlp - sdt - vectors @@ -23,4 +23,16 @@ not sure how far I will take this but messing around with E1.17 ACN protocol - [x] DISCONNECT - [x] DISCONNECTING - dmp + - vectors + - [ ] GET_PROPERTY + - [ ] SET_PROPERTY + - [ ] GET_PROPERTY_REPLY + - [ ] EVENT + - [ ] SUBSCRIBE + - [ ] UNSUBSCRIBE + - [ ] GET_PROPERTY_FAIL + - [ ] SET_PROPERTY_FAIL + - [ ] SUBSCRIBE_ACCEPT + - [ ] SUBSCRIBE_REJECT + - [ ] SYNC_EVENT - ddl diff --git a/packages/acn/src/enums.ts b/packages/acn/src/enums.ts index 584f966..c99a138 100644 --- a/packages/acn/src/enums.ts +++ b/packages/acn/src/enums.ts @@ -1,5 +1,6 @@ export enum Protocol { SDT = 1, + DMP, } export enum SDTVector { @@ -22,6 +23,26 @@ export enum SDTVector { SESSIONS, } +export enum DMPVector { + GET_PROPERTY = 1, + SET_PROPERTY, + GET_PROPERTY_REPLY, + EVENT, + RESERVED_1, + RESERVED_2, + SUBSCRIBE, + UNSUBSCRIBE, + GET_PROPERTY_FAIL, + SET_PROPERTY_FAIL, + RESERVED_3, + SUBSCRIBE_ACCEPT, + SUBSCRIBE_REJECT, + RESERVED_4, + RESERVED_5, + RESERVED_6, + SYNC_EVENT, +} + export enum TransportLayerAddressType { SDT_ADDR_NULL = 0, SDT_ADDR_IPV4, diff --git a/packages/acn/src/pdu/dmp.ts b/packages/acn/src/pdu/dmp.ts new file mode 100644 index 0000000..992c79f --- /dev/null +++ b/packages/acn/src/pdu/dmp.ts @@ -0,0 +1,77 @@ +import { DMPVector } from '../enums'; +import { DeviceManagementProtocolPDU, DMPAddressDataType, DMPGetPropertyData } from '../types'; + +export function decode(bytes: Uint8Array): DeviceManagementProtocolPDU { + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + const flags = view.getUint8(0) >> 4; + const lengthFlag = ((flags >> 3) & 0x1) === 1; + const vectorFlag = ((flags >> 2) & 0x1) === 1; + const headerFlag = ((flags >> 1) & 0x1) === 1; + + if (!vectorFlag) { + throw new Error('SDT PDU must have a vector'); + } + + const dataFlag = (flags & 0x1) === 1; + + if (!dataFlag) { + // TODO(jwetzell): idk if this is true + throw new Error('SDT PDU must have data'); + } + + const lengthH = view.getUint8(0) & 0x0f; + let lengthOffset = 1; + const lengthL = view.getUint8(lengthOffset); + + let length = (lengthH << 8) + lengthL; + if (lengthFlag) { + lengthOffset += 1; + const lengthX = view.getUint8(lengthOffset); + length = (lengthH << 16) + (lengthL << 8) + lengthX; + } + let vectorOffset = lengthOffset + 1; + + if (lengthFlag) { + vectorOffset += 1; + } + + const vector = view.getUint8(vectorOffset); + + let headerOffset = (vectorOffset += 1); + + const addressAndDataTypes = view.getUint8(headerOffset); + const addressType = (addressAndDataTypes >> 6) & 0x1; + const dataType = (addressAndDataTypes >> 4) & 0x3; + const elementSize = addressAndDataTypes & 0x11; + + const addressAndDataType = { + addressType, + dataType, + elementSize + } + + const dataOffset = headerOffset + 1; + // NOTE(jwetzell): flags/lengthH + lengthL + lengthX + vector + header + const dataLength = length - (1 + 1 + (lengthFlag ? 1 : 0) + 1 + 1); + const data = decodeData(vector, bytes.subarray(dataOffset, dataOffset + dataLength), addressAndDataType); + console.log('decoded Data', data) + return { + vector, + data + }; +} + +function decodeData(vector: number, bytes: Uint8Array, addressAndDataType: DMPAddressDataType): DMPGetPropertyData | Uint8Array { + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + console.log('pdu bytes', bytes) + console.log('pdu address data type', addressAndDataType) + switch (vector) { + default: + console.error(`unhandled DMP vector: ${vector}`); + return bytes; + } +} + +export default { + decode, +}; diff --git a/packages/acn/src/pdu/index.ts b/packages/acn/src/pdu/index.ts index 07a880b..fa3bfe0 100644 --- a/packages/acn/src/pdu/index.ts +++ b/packages/acn/src/pdu/index.ts @@ -1,6 +1,8 @@ import rlp from './rlp'; import sdt from './sdt'; +import dmp from './dmp'; export default { rlp, sdt, + dmp, }; diff --git a/packages/acn/src/pdu/sdt.ts b/packages/acn/src/pdu/sdt.ts index e87cf7e..17e4a1a 100644 --- a/packages/acn/src/pdu/sdt.ts +++ b/packages/acn/src/pdu/sdt.ts @@ -1,5 +1,7 @@ +import pdu from '.'; import { Protocol, SDTVector } from '../enums'; import { + DeviceManagementProtocolPDU, SDTAckData, SDTConnectAcceptData, SDTConnectData, @@ -113,10 +115,12 @@ function decodeClientBlock(bytes: Uint8Array) { const dataOffset = headerOffset + 6; // NOTE(jwetzell): flags/lengthH + lengthL + lengthX + vector + header const dataLength = length - (1 + 1 + (lengthFlag ? 1 : 0) + 2 + 6); - let data: SessionDataTransportPDU | Uint8Array = bytes.subarray(dataOffset, dataOffset + dataLength); + let data: SessionDataTransportPDU | DeviceManagementProtocolPDU | Uint8Array = bytes.subarray(dataOffset, dataOffset + dataLength); if (clientProtocol === Protocol.SDT) { data = decode(data); + } else if (clientProtocol === Protocol.DMP) { + data = pdu.dmp.decode(data) } else { console.error(`SDT client block contains unknown protocol: ${clientProtocol}`); } diff --git a/packages/acn/src/types.ts b/packages/acn/src/types.ts index 5398bac..c5c81a1 100644 --- a/packages/acn/src/types.ts +++ b/packages/acn/src/types.ts @@ -1,4 +1,4 @@ -import { TransportLayerAddressType, SDTVector, SDTReasonCode } from './enums'; +import { TransportLayerAddressType, SDTVector, SDTReasonCode, DMPVector } from './enums'; export type UDPPreamble = { preambleSize: number; @@ -133,9 +133,26 @@ export type SessionDataTransportPDU = { | Uint8Array; }; +export type DMPAddressDataType = { + addressType: number; + dataType: number; + elementSize: number; +}; + +export type DMPGetPropertyData = { + address: number +} + +export type DMPSubscribePropertyData = DMPGetPropertyData + +export type DeviceManagementProtocolPDU = { + vector: DMPVector; + data: DMPGetPropertyData | DMPSubscribePropertyData | Uint8Array; +}; + export type SDTClientBlock = { memberID: number; clientProtocol: number; association: number; - data: SessionDataTransportPDU | Uint8Array; + data: SessionDataTransportPDU | DeviceManagementProtocolPDU | Uint8Array; };