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