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