From e11f16f427db8b32bc50b7918b710e669d5e9b40 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Sat, 15 Mar 2025 12:32:13 -0500 Subject: [PATCH] add decoder for RTTrPL --- src/decoders/index.ts | 2 + src/decoders/lighting/rttrpl.ts | 37 +++++++++++++ src/models.ts | 5 ++ tests/decode.test.js | 96 +++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 src/decoders/lighting/rttrpl.ts diff --git a/src/decoders/index.ts b/src/decoders/index.ts index 21f1406..8218e0f 100644 --- a/src/decoders/index.ts +++ b/src/decoders/index.ts @@ -1,5 +1,6 @@ import ChannelBlock from './lighting/channel-block'; import LightingOutput from './lighting/lighting-output'; +import RTTrPL from './lighting/rttrpl'; import Spot from './lighting/spot'; import Universe from './lighting/universe'; import CentroidAccelVelocity from './motion/centroid-accel-velocity'; @@ -17,6 +18,7 @@ import RTTrPHeader from './rttrp-header'; export const Decoders = { RTTrPHeader, RTTrPM, + RTTrPL, Trackable, CentroidPosition, CentroidAccelVelocity, diff --git a/src/decoders/lighting/rttrpl.ts b/src/decoders/lighting/rttrpl.ts new file mode 100644 index 0000000..5ed142b --- /dev/null +++ b/src/decoders/lighting/rttrpl.ts @@ -0,0 +1,37 @@ +import { Decoders } from '..'; +import { LightingOutput, RTTrPL } from '../../models'; + +export default (bytes: Uint8Array): RTTrPL => { + if (bytes.byteLength < 18) { + throw new Error('RTTrPL packet must be at least 18 bytes long'); + } + const header = Decoders.RTTrPHeader(bytes.subarray(0, 18)); + + if (bytes.byteLength !== header.size) { + throw new Error('RTTrPL packet size mismatch'); + } + + const modules: LightingOutput[] = []; + let packetModuleOffset = 18; + + for (let index = 0; index < header.subModuleCount; index++) { + const moduleData = bytes.subarray(packetModuleOffset); + const moduleType = moduleData[0]; + switch (moduleType) { + case 0x07: { + const module = Decoders.LightingOutput(moduleData, header.isLittleEndian); + modules.push(module); + packetModuleOffset += module.size; + break; + } + default: + console.error(`unknown RTTrPL submodule type: ${moduleType}`); + break; + } + } + + return { + header, + modules, + }; +}; diff --git a/src/models.ts b/src/models.ts index 949430b..9dcde49 100644 --- a/src/models.ts +++ b/src/models.ts @@ -15,6 +15,11 @@ export type RTTrPM = { modules: Trackable[]; }; +export type RTTrPL = { + header: RTTrPHeader; + modules: LightingOutput[]; +}; + export type TrackableModule = | CentroidPosition | CentroidAccelVelocity diff --git a/tests/decode.test.js b/tests/decode.test.js index 6104c4d..ee47e54 100644 --- a/tests/decode.test.js +++ b/tests/decode.test.js @@ -251,6 +251,102 @@ const goodTests = [ }, decoder: Decoders.RTTrPM, }, + { + description: 'RTTrPL + Lighting Output + Universe + Spot + Single Channel Block', + bytes: new Uint8Array([ + 65, 84, 0x44, 0x34, 0, 2, 0, 0, 0, 1, 0, 0, 53, 18, 52, 86, 120, 1, 0x07, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x01, 0x09, 0x00, 0x15, 0x12, 0x34, 0x00, 0x01, 0x0a, 0x00, 0x0e, 0x12, 0x34, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x06, 0x40, + ]), + expected: { + header: { + intHeader: 0x4154, + floatHeader: 0x4434, + version: 2, + packetID: 1, + packetFormat: 0, + size: 53, + context: 0x12345678, + subModuleCount: 1, + isLittleEndian: false, + }, + modules: [ + { + type: 0x07, + size: 35, + sequence: 1, + action: 1, + holdTime: 100, + numberOfUniverses: 1, + universes: [ + { + type: 0x09, + size: 21, + id: 0x1234, + numberOfSpots: 1, + spots: [ + { + type: 0x0a, + size: 14, + id: 0x1234, + offset: 1, + numberOfChannelBlocks: 1, + channelBlocks: [ + { + offset: 0x08, + fade: 0x06, + value: 0x40, + }, + ], + }, + ], + }, + ], + }, + ], + }, + decoder: Decoders.RTTrPL, + }, + { + description: 'Lighting Output + Universe + Spot + Single Channel Block', + bytes: new Uint8Array([ + 0x07, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x01, 0x09, 0x00, 0x15, 0x12, 0x34, + 0x00, 0x01, 0x0a, 0x00, 0x0e, 0x12, 0x34, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x06, 0x40, + ]), + expected: { + type: 0x07, + size: 35, + sequence: 1, + action: 1, + holdTime: 100, + numberOfUniverses: 1, + universes: [ + { + type: 0x09, + size: 21, + id: 0x1234, + numberOfSpots: 1, + spots: [ + { + type: 0x0a, + size: 14, + id: 0x1234, + offset: 1, + numberOfChannelBlocks: 1, + channelBlocks: [ + { + offset: 0x08, + fade: 0x06, + value: 0x40, + }, + ], + }, + ], + }, + ], + }, + decoder: Decoders.LightingOutput, + }, { description: 'Universe + Spot + Single Channel Block', bytes: new Uint8Array([