UNPKG

3.78 kBPlain TextView Raw
1/**
2 * this is the low-level implementation of the E1.31 (sACN) protocol
3 */
4
5import * as assert from 'assert';
6
7/* eslint-disable lines-between-class-members, no-bitwise, no-control-regex */
8
9const ACN_PID = Buffer.from([
10 0x41,
11 0x53,
12 0x43,
13 0x2d,
14 0x45,
15 0x31,
16 0x2e,
17 0x31,
18 0x37,
19 0x00,
20 0x00,
21 0x00,
22]);
23
24enum RootVector {
25 DATA = 4,
26 EXTENDED = 8,
27}
28enum FrameVector {
29 DATA = 2,
30}
31enum DmpVector {
32 DATA = 2,
33}
34
35/* eslint-disable camelcase */
36
37// enum ExtendedFrameVector { SYNC = 1, DISCOVERY = 2 }
38
39export class Packet {
40 /* root layer */
41 private readonly root_vector: RootVector;
42 private readonly root_fl: number;
43 private readonly preambleSize: number;
44 private readonly postambleSize: number;
45 private readonly acnPid: Buffer;
46 readonly cid: Buffer; // unique id of the sender
47
48 /* framing layer */
49 private readonly frame_vector: FrameVector;
50 private readonly frame_fl: number;
51 readonly options: number;
52 readonly sequence: number;
53 readonly sourceName: string;
54 readonly priority: number; // 0 to 200; default 100
55 readonly syncUniverse: number; // universe used for annoucing timesync
56 readonly universe: number;
57
58 /* DMP layer */
59 private readonly dmp_vector: DmpVector;
60 private readonly dmp_fl: number;
61 private readonly type: number;
62 private readonly firstAddress: number;
63 private readonly addressIncrement: number;
64 readonly propertyValueCount: number;
65 private readonly startCode: number;
66 readonly slotsData: Buffer;
67
68 public constructor(
69 private readonly buffer: Buffer,
70 public readonly sourceAddress?: string,
71 ) {
72 /* root layer */
73 this.root_vector = this.buffer.readUInt32BE(18);
74 this.root_fl = this.buffer.readUInt16BE(16);
75 this.acnPid = this.buffer.slice(4, 16);
76 this.preambleSize = this.buffer.readUInt16BE(0);
77 this.postambleSize = this.buffer.readUInt16BE(2);
78 this.cid = this.buffer.slice(22, 38);
79
80 /* frame layer */
81 this.frame_vector = this.buffer.readUInt32BE(40);
82 this.frame_fl = this.buffer.readUInt16BE(38);
83 this.options = this.buffer.readUInt8(112);
84 this.sequence = this.buffer.readUInt8(111);
85 this.sourceName = this.buffer
86 .toString('ascii', 44, 107)
87 .replace(/\x00/g, '');
88 this.priority = this.buffer.readUInt8(108);
89 this.syncUniverse = this.buffer.readUInt16BE(109);
90 this.universe = this.buffer.readUInt16BE(113);
91
92 /* DMP layer */
93 this.dmp_vector = this.buffer.readUInt8(117);
94 this.dmp_fl = this.buffer.readUInt16BE(115);
95 this.type = this.buffer.readUInt8(118);
96 this.firstAddress = this.buffer.readUInt16BE(119);
97 this.addressIncrement = this.buffer.readUInt16BE(121);
98 this.propertyValueCount = this.buffer.readUInt16BE(123);
99 this.startCode = this.buffer.readUInt8(125);
100 this.slotsData = this.buffer.slice(126);
101
102 this.validate();
103 }
104
105 private validate(): void | never {
106 // ascertains that this packet implements ACN
107 assert.deepStrictEqual(this.acnPid, ACN_PID);
108
109 // ascertains that this packet is a DATA packet
110 assert.strictEqual(this.root_vector, RootVector.DATA);
111 assert.strictEqual(this.frame_vector, FrameVector.DATA);
112 assert.strictEqual(this.dmp_vector, DmpVector.DATA);
113
114 // constants within the UDP overhead
115 assert.strictEqual(this.type, 0xa1); // = 61
116 assert.strictEqual(this.firstAddress, 0);
117 assert.strictEqual(this.addressIncrement, 1);
118 assert.strictEqual(this.startCode, 0);
119 assert.strictEqual(this.preambleSize, 0x0010); // = 16
120 assert.strictEqual(this.postambleSize, 0);
121 }
122
123 // TODO: For octet 112 (options): Bit 7 = Preview_Data / Bit 6 = Stream_Terminated / Bit 5 = Force_Synchronization
124 // public getOption(option: number): boolean {
125 // return !!(this.options & (1 << (option % 8)));
126 // }
127}