]> git.basschouten.com Git - openhab-addons.git/blob
c4a2495b39799306215bd6e2704986779d926063
[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.onewire.internal.owserver;
14
15 import java.io.DataInputStream;
16 import java.io.IOException;
17 import java.nio.ByteBuffer;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.openhab.binding.onewire.internal.OwException;
21 import org.openhab.binding.onewire.internal.OwPageBuffer;
22
23 /**
24  * The {@link OwserverPacket} class provides a single packet for communication with the owserver
25  *
26  * @author Jan N. Klug - Initial contribution
27  */
28
29 @NonNullByDefault
30 public class OwserverPacket {
31     public static final int PROTOCOL_VERSION = 0;
32
33     // 6x4 bytes
34     public static final int HEADER_SIZE = 24;
35     protected int payloadLength = 0;
36
37     protected final OwserverPacketType packetType;
38
39     protected int protocolVersion = PROTOCOL_VERSION;
40     protected int controlFlags;
41     protected int packetCode = 0;
42     protected int packetSize = 0;
43     protected int payloadOffset = 0;
44
45     protected byte payload[] = new byte[0];
46
47     /**
48      * constructor for new packet
49      *
50      * @param packetType packetType;
51      */
52     public OwserverPacket(OwserverPacketType packetType) {
53         this.packetType = packetType;
54         setControlFlags(OwserverControlFlag.OWNET, OwserverControlFlag.DEVICE_DISPLAY);
55     }
56
57     /**
58      * constructor for reading packet from stream
59      *
60      * @param owInputStream input stream to read from
61      * @throws IOException
62      * @throws OwException in case an error occurs
63      */
64     public OwserverPacket(DataInputStream owInputStream, OwserverPacketType packetType)
65             throws IOException, OwException {
66         this.packetType = packetType;
67
68         // header
69         protocolVersion = owInputStream.readInt();
70         payloadLength = owInputStream.readInt();
71         packetCode = owInputStream.readInt();
72         controlFlags = owInputStream.readInt();
73         packetSize = owInputStream.readInt();
74         payloadOffset = owInputStream.readInt();
75
76         // payload
77         if (payloadLength != -1) {
78             if ((protocolVersion != PROTOCOL_VERSION) || !OwserverControlFlag.OWNET.isSet(controlFlags)) {
79                 throw new OwException("invalid data read");
80             }
81             if (payloadLength > 0) {
82                 payload = new byte[payloadLength];
83                 owInputStream.readFully(payload, 0, payloadLength);
84             }
85         }
86     }
87
88     /**
89      * constructor for a new request message
90      *
91      * @param owMessageType
92      * @param path
93      * @param owControlFlags
94      */
95     public OwserverPacket(OwserverMessageType owMessageType, String path, OwserverControlFlag... owControlFlags) {
96         this(OwserverPacketType.REQUEST);
97         packetCode = owMessageType.getValue();
98         setPayload(path);
99         setTemperatureScale(OwserverTemperatureScale.CENTIGRADE);
100         setControlFlags(owControlFlags);
101         if (owMessageType == OwserverMessageType.WRITE) {
102             packetSize = 0x00000000;
103         } else {
104             packetSize = 0x00010000;
105         }
106     }
107
108     /**
109      * set one or more control flags for this packet
110      *
111      * @param flags one or more flags as OwControlFlag
112      */
113     public void setControlFlags(OwserverControlFlag... flags) {
114         for (int i = 0; i < flags.length; i++) {
115             controlFlags |= flags[i].getValue();
116         }
117     }
118
119     /**
120      * check if a certain flag is set in this packet
121      *
122      * @param flag flag to be tested
123      * @return true if flag is set
124      */
125     public boolean hasControlFlag(OwserverControlFlag flag) {
126         return flag.isSet(controlFlags);
127     }
128
129     /**
130      * set this packet's pressure scale
131      *
132      * @param pressureScale
133      */
134     public void setPressureScale(OwserverPressureScale pressureScale) {
135         controlFlags = pressureScale.setFlag(controlFlags);
136     }
137
138     /**
139      * get this packets pressure scale
140      *
141      * @return
142      */
143     public OwserverPressureScale getPressureScale() {
144         return OwserverPressureScale.getFlag(controlFlags);
145     }
146
147     /**
148      * set this packet's temperature scale
149      *
150      * @param temperatureScale
151      */
152     public void setTemperatureScale(OwserverTemperatureScale temperatureScale) {
153         controlFlags = temperatureScale.setFlag(controlFlags);
154     }
155
156     /**
157      * get this packets temperature scale
158      *
159      * @return
160      */
161     public OwserverTemperatureScale getTemperatureScale() {
162         return OwserverTemperatureScale.getFlag(controlFlags);
163     }
164
165     /**
166      * set (or replace) this packet's payload from a string
167      *
168      * @param payload string representation of the payload
169      */
170     public void setPayload(String payload) {
171         byte[] bytes = payload.getBytes();
172         payloadLength = bytes.length + 1;
173         this.payload = new byte[payloadLength];
174         System.arraycopy(bytes, 0, this.payload, 0, bytes.length);
175     }
176
177     /**
178      * append to this packet's payload from a string
179      *
180      * @param payload string representation of the payload to append
181      */
182     public void appendPayload(String payload) {
183         byte[] appendBytes = payload.getBytes();
184
185         byte[] fullPayload = new byte[this.payload.length + appendBytes.length];
186         System.arraycopy(this.payload, 0, fullPayload, 0, this.payload.length);
187         System.arraycopy(appendBytes, 0, fullPayload, this.payload.length, appendBytes.length);
188
189         this.packetSize += appendBytes.length;
190         this.payloadLength = fullPayload.length;
191         this.payload = fullPayload;
192     }
193
194     /**
195      * set this packet payload from a OwPageBuffer
196      *
197      * @param payload string representation of the payload
198      */
199     public void setPayload(OwPageBuffer payload) {
200         byte[] bytes = payload.getBytes();
201         payloadLength = bytes.length + 1;
202         this.payload = new byte[payloadLength];
203         System.arraycopy(bytes, 0, this.payload, 0, bytes.length);
204     }
205
206     /**
207      * get the payload of this packet
208      *
209      * @return string representation of this packet's payload
210      */
211     public String getPayloadString() {
212         if (payloadLength > 0) {
213             // already null terminated strings skip the termination character
214             if (payload[payloadLength - 1] == 0) {
215                 return new String(payload, 0, payloadLength - 1);
216             } else {
217                 return new String(payload, 0, payloadLength);
218             }
219         } else {
220             return "";
221         }
222     }
223
224     /**
225      * set this packet's return code (0 is ok)
226      *
227      * @param returnCode an integer
228      */
229     public void setReturnCode(int returnCode) {
230         if (packetType == OwserverPacketType.RETURN) {
231             this.packetCode = returnCode;
232         } else {
233             throw new IllegalStateException("setting return code not allowed in REQUEST packets");
234         }
235     }
236
237     /**
238      * get this packet's return code (0 is ok)
239      *
240      * @return
241      */
242     public int getReturnCode() {
243         if (packetType == OwserverPacketType.RETURN) {
244             return packetCode;
245         } else {
246             throw new IllegalStateException("getting return code not allowed in REQUEST packets");
247         }
248     }
249
250     /**
251      * set this packet's message type
252      *
253      * @param messageType
254      */
255     public void setMessageType(OwserverMessageType messageType) {
256         if (packetType == OwserverPacketType.REQUEST) {
257             packetCode = messageType.getValue();
258         } else {
259             throw new IllegalStateException("setting message type not allowed in RETURN packets");
260         }
261     }
262
263     /**
264      * get this packets message type
265      *
266      * @return
267      */
268     public OwserverMessageType getMessageType() {
269         if (packetType == OwserverPacketType.REQUEST) {
270             return OwserverMessageType.fromInt(packetCode);
271         } else {
272             throw new IllegalStateException("getting message type not allowed in RETURN packets");
273         }
274     }
275
276     /**
277      * check if packed is valid return packet
278      *
279      * @return true if valid
280      */
281     public boolean isValidReturnPacket() {
282         return (packetCode == 0 && packetType == OwserverPacketType.RETURN);
283     }
284
285     /**
286      * check if packed is valid return packet
287      *
288      * @return true if valid
289      */
290     public boolean isPingPacket() {
291         return (payloadLength == -1 && packetType == OwserverPacketType.RETURN);
292     }
293
294     /**
295      * get the payload of this packet
296      *
297      * @return OwPageBuffer with this packet's payload
298      */
299     public OwPageBuffer getPayload() {
300         return new OwPageBuffer(payload);
301     }
302
303     /**
304      * check if this packet has a payload
305      *
306      * @return true if payload present
307      */
308     public boolean hasPayload() {
309         return (payloadLength > 0);
310     }
311
312     /**
313      * convert this packet to an array of bytes
314      *
315      * @return array of bytes
316      */
317     public byte[] toBytes() {
318         ByteBuffer byteBuffer = ByteBuffer.allocate(HEADER_SIZE + payloadLength);
319         byteBuffer.putInt(protocolVersion);
320         byteBuffer.putInt(payloadLength);
321         byteBuffer.putInt(packetCode);
322         byteBuffer.putInt(controlFlags);
323         byteBuffer.putInt(packetSize);
324         byteBuffer.putInt(payloadOffset);
325         if (payloadLength > 0) {
326             byteBuffer.put(payload);
327         }
328
329         return byteBuffer.array();
330     }
331
332     @Override
333     public String toString() {
334         String prefix;
335
336         if (packetType == OwserverPacketType.RETURN) {
337             prefix = String.format("return code %d", packetCode);
338         } else {
339             prefix = String.format("messageType %s", OwserverMessageType.fromInt(packetCode));
340         }
341
342         return String.format("%s, size %d, controlFlags 0x%08x, payload '%s'", prefix, HEADER_SIZE + payloadLength,
343                 controlFlags, getPayloadString().replaceAll("\\p{C}", "?"));
344     }
345 }