]> git.basschouten.com Git - openhab-addons.git/blob
3014b6de65743ace174a1b6157b9e8690518c24f
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.dmx.internal.dmxoverethernet;
14
15 import java.nio.ByteBuffer;
16 import java.nio.charset.StandardCharsets;
17 import java.util.UUID;
18
19 import org.openhab.binding.dmx.internal.Util;
20 import org.openhab.binding.dmx.internal.multiverse.Universe;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 /**
25  * The {@link SacnPacket} is responsible for handling commands, which are
26  * sent to the bridge.
27  *
28  * @author Jan N. Klug - Initial contribution
29  */
30 public class SacnPacket extends DmxOverEthernetPacket {
31     public static final int SACN_MAX_PACKET_LEN = 638;
32     public static final int SACN_MAX_PAYLOAD_SIZE = 512;
33
34     private final Logger logger = LoggerFactory.getLogger(SacnPacket.class);
35
36     /**
37      * default constructor, creates a packet
38      *
39      * @param uuid UUID is mandatory
40      */
41
42     public SacnPacket(UUID uuid) {
43         payloadSize = SACN_MAX_PAYLOAD_SIZE;
44         rawPacket = new byte[SACN_MAX_PACKET_LEN];
45
46         /* init E1.31 root layer, total length 38 bytes */
47         rawPacket[0] = 0x00; // preamble size, 2 bytes
48         rawPacket[1] = 0x10;
49         rawPacket[2] = 0x00; // postamble size, 2 bytes
50         rawPacket[3] = 0x00;
51         rawPacket[4] = 0x41; // packet identifier, 12 bytes
52         rawPacket[5] = 0x53;
53         rawPacket[6] = 0x43;
54         rawPacket[7] = 0x2d;
55         rawPacket[8] = 0x45;
56         rawPacket[9] = 0x31;
57         rawPacket[10] = 0x2e;
58         rawPacket[11] = 0x31;
59         rawPacket[12] = 0x37;
60         rawPacket[13] = 0x00;
61         rawPacket[14] = 0x00;
62         rawPacket[15] = 0x00;
63         rawPacket[16] = 0x72; // flags & length, 2 bytes
64         rawPacket[17] = 0x6e;
65         rawPacket[18] = 0x00; // vector, 4 bytes;
66         rawPacket[19] = 0x00;
67         rawPacket[20] = 0x00;
68         rawPacket[21] = 0x04;
69
70         // UUID 16 bytes
71         ByteBuffer uuidBytes = ByteBuffer.wrap(new byte[16]);
72         uuidBytes.putLong(uuid.getMostSignificantBits());
73         uuidBytes.putLong(uuid.getLeastSignificantBits());
74         System.arraycopy(uuidBytes.array(), 0, rawPacket, 22, 16);
75
76         /* init sACN/E1.31 framing layer, total length 77 bytes */
77         rawPacket[38] = 0x72; // flags & length, 2 bytes
78         rawPacket[39] = 0x58;
79         rawPacket[40] = 0x00; // vector, 4 bytes;
80         rawPacket[41] = 0x00;
81         rawPacket[42] = 0x00;
82         rawPacket[43] = 0x02;
83         for (int i = 44; i < 108; i++) { // senderName, 64 bytes
84             rawPacket[i] = 0x00;
85         }
86         rawPacket[108] = 0x64; // priority (default 100), 1 byte
87         rawPacket[109] = 0x00; // reserved, 2 bytes
88         rawPacket[110] = 0x00;
89         rawPacket[111] = 0x00; // sequence number, 1 byte
90         rawPacket[112] = 0x00; // options, 1 byte
91         rawPacket[113] = 0x00; // universe, 2 bytes
92         rawPacket[114] = 0x00;
93
94         /* sACN/E1.31 DMP layer, total length 11 + channel count */
95         rawPacket[115] = 0x72; // flags & length, 2 bytes
96         rawPacket[116] = 0x0b;
97         rawPacket[117] = 0x02; // vector, 1 byte
98         rawPacket[118] = (byte) 0xa1; // address type, 1 byte
99         rawPacket[119] = 0x00; // start address, 2 bytes
100         rawPacket[120] = 0x00;
101         rawPacket[121] = 0x00; // address increment, 2 bytes
102         rawPacket[122] = 0x01;
103         rawPacket[123] = 0x02; // payload size, 2 bytes (including start code)
104         rawPacket[123] = 0x01;
105         rawPacket[125] = 0x00; // DMX start code, 1 byte
106     }
107
108     @Override
109     public void setPayloadSize(int payloadSize) throws IllegalArgumentException {
110         if (payloadSize < Universe.MIN_UNIVERSE_SIZE) {
111             throw new IllegalArgumentException(
112                     String.format("payload minimum size is %d slots (>%d)", Universe.MIN_UNIVERSE_SIZE, payloadSize));
113         } else if (payloadSize > Universe.MAX_UNIVERSE_SIZE) {
114             throw new IllegalArgumentException(
115                     String.format("payload maximum size is %d slots (<%d)", Universe.MAX_UNIVERSE_SIZE, payloadSize));
116         }
117
118         /* root Layer */
119         rawPacket[16] = (byte) ((28672 + 110 + payloadSize) / 256);
120         rawPacket[17] = (byte) ((28672 + 110 + payloadSize) % 256);
121
122         /* framing layer */
123         rawPacket[38] = (byte) ((28672 + 88 + payloadSize) / 256);
124         rawPacket[39] = (byte) ((28672 + 88 + payloadSize) % 256);
125
126         /* DMP layer */
127         rawPacket[115] = (byte) ((28672 + 11 + payloadSize) / 256);
128         rawPacket[116] = (byte) ((28672 + 11 + payloadSize) % 256);
129         rawPacket[123] = (byte) ((payloadSize + 1) / 256);
130         rawPacket[124] = (byte) ((payloadSize + 1) % 256);
131
132         this.payloadSize = payloadSize;
133     }
134
135     @Override
136     public void setUniverse(int universeId) {
137         this.universeId = universeId;
138
139         /* set universe in packet */
140         rawPacket[113] = (byte) (this.universeId / 256);
141         rawPacket[114] = (byte) (this.universeId % 256);
142
143         /* set sender name in packet */
144         String senderName = new String("openHAB DMX binding (sACN) <" + String.format("%05d", this.universeId) + ">");
145         byte[] senderNameBytes = senderName.getBytes(StandardCharsets.UTF_8);
146         System.arraycopy(senderNameBytes, 0, rawPacket, 44, senderName.length());
147
148         logger.trace("set packet universe to {}", this.universeId);
149     }
150
151     @Override
152     public void setSequence(int sequenceNo) {
153         rawPacket[111] = (byte) (sequenceNo % 256);
154     }
155
156     /**
157      * set priority
158      *
159      * @param priority data priority (for multiple senders), allowed values are 0-200, default 100
160      */
161     public void setPriority(int priority) {
162         /* observe limits (coerce to range) */
163         rawPacket[108] = (byte) Util.coerceToRange(priority, 0, 200, logger, "packet priority");
164         logger.debug("set packet priority to {}", priority);
165     }
166
167     @Override
168     public void setPayload(byte[] payload) {
169         System.arraycopy(payload, 0, rawPacket, 126, payloadSize);
170     }
171
172     @Override
173     public void setPayload(byte[] payload, int payloadSize) {
174         if (payloadSize != this.payloadSize) {
175             setPayloadSize(payloadSize);
176         }
177         setPayload(payload);
178     }
179
180     @Override
181     public int getPacketLength() {
182         return (126 + this.payloadSize);
183     }
184 }