2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.onewire.internal.owserver;
15 import java.io.DataInputStream;
16 import java.io.IOException;
17 import java.nio.ByteBuffer;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.openhab.binding.onewire.internal.OwException;
21 import org.openhab.binding.onewire.internal.OwPageBuffer;
24 * The {@link OwserverPacket} class provides a single packet for communication with the owserver
26 * @author Jan N. Klug - Initial contribution
30 public class OwserverPacket {
31 public static final int PROTOCOL_VERSION = 0;
34 public static final int HEADER_SIZE = 24;
35 protected int payloadLength = 0;
37 protected final OwserverPacketType packetType;
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;
45 protected byte payload[] = new byte[0];
48 * constructor for new packet
50 * @param packetType packetType;
52 public OwserverPacket(OwserverPacketType packetType) {
53 this.packetType = packetType;
54 setControlFlags(OwserverControlFlag.OWNET, OwserverControlFlag.DEVICE_DISPLAY);
58 * constructor for reading packet from stream
60 * @param owInputStream input stream to read from
62 * @throws OwException in case an error occurs
64 public OwserverPacket(DataInputStream owInputStream, OwserverPacketType packetType)
65 throws IOException, OwException {
66 this.packetType = packetType;
69 protocolVersion = owInputStream.readInt();
70 payloadLength = owInputStream.readInt();
71 packetCode = owInputStream.readInt();
72 controlFlags = owInputStream.readInt();
73 packetSize = owInputStream.readInt();
74 payloadOffset = owInputStream.readInt();
77 if (payloadLength != -1) {
78 if ((protocolVersion != PROTOCOL_VERSION) || !OwserverControlFlag.OWNET.isSet(controlFlags)) {
79 throw new OwException("invalid data read");
81 if (payloadLength > 0) {
82 payload = new byte[payloadLength];
83 owInputStream.readFully(payload, 0, payloadLength);
89 * constructor for a new request message
91 * @param owMessageType
93 * @param owControlFlags
95 public OwserverPacket(OwserverMessageType owMessageType, String path, OwserverControlFlag... owControlFlags) {
96 this(OwserverPacketType.REQUEST);
97 packetCode = owMessageType.getValue();
99 setTemperatureScale(OwserverTemperatureScale.CENTIGRADE);
100 setControlFlags(owControlFlags);
101 if (owMessageType == OwserverMessageType.WRITE) {
102 packetSize = 0x00000000;
104 packetSize = 0x00010000;
109 * set one or more control flags for this packet
111 * @param flags one or more flags as OwControlFlag
113 public void setControlFlags(OwserverControlFlag... flags) {
114 for (int i = 0; i < flags.length; i++) {
115 controlFlags |= flags[i].getValue();
120 * check if a certain flag is set in this packet
122 * @param flag flag to be tested
123 * @return true if flag is set
125 public boolean hasControlFlag(OwserverControlFlag flag) {
126 return flag.isSet(controlFlags);
130 * set this packet's pressure scale
132 * @param pressureScale
134 public void setPressureScale(OwserverPressureScale pressureScale) {
135 controlFlags = pressureScale.setFlag(controlFlags);
139 * get this packets pressure scale
143 public OwserverPressureScale getPressureScale() {
144 return OwserverPressureScale.getFlag(controlFlags);
148 * set this packet's temperature scale
150 * @param temperatureScale
152 public void setTemperatureScale(OwserverTemperatureScale temperatureScale) {
153 controlFlags = temperatureScale.setFlag(controlFlags);
157 * get this packets temperature scale
161 public OwserverTemperatureScale getTemperatureScale() {
162 return OwserverTemperatureScale.getFlag(controlFlags);
166 * set (or replace) this packet's payload from a string
168 * @param payload string representation of the payload
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);
178 * append to this packet's payload from a string
180 * @param payload string representation of the payload to append
182 public void appendPayload(String payload) {
183 byte[] appendBytes = payload.getBytes();
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);
189 this.packetSize += appendBytes.length;
190 this.payloadLength = fullPayload.length;
191 this.payload = fullPayload;
195 * set this packet payload from a OwPageBuffer
197 * @param payload string representation of the payload
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);
207 * get the payload of this packet
209 * @return string representation of this packet's payload
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);
217 return new String(payload, 0, payloadLength);
225 * set this packet's return code (0 is ok)
227 * @param returnCode an integer
229 public void setReturnCode(int returnCode) {
230 if (packetType == OwserverPacketType.RETURN) {
231 this.packetCode = returnCode;
233 throw new IllegalStateException("setting return code not allowed in REQUEST packets");
238 * get this packet's return code (0 is ok)
242 public int getReturnCode() {
243 if (packetType == OwserverPacketType.RETURN) {
246 throw new IllegalStateException("getting return code not allowed in REQUEST packets");
251 * set this packet's message type
255 public void setMessageType(OwserverMessageType messageType) {
256 if (packetType == OwserverPacketType.REQUEST) {
257 packetCode = messageType.getValue();
259 throw new IllegalStateException("setting message type not allowed in RETURN packets");
264 * get this packets message type
268 public OwserverMessageType getMessageType() {
269 if (packetType == OwserverPacketType.REQUEST) {
270 return OwserverMessageType.fromInt(packetCode);
272 throw new IllegalStateException("getting message type not allowed in RETURN packets");
277 * check if packed is valid return packet
279 * @return true if valid
281 public boolean isValidReturnPacket() {
282 return (packetCode == 0 && packetType == OwserverPacketType.RETURN);
286 * check if packed is valid return packet
288 * @return true if valid
290 public boolean isPingPacket() {
291 return (payloadLength == -1 && packetType == OwserverPacketType.RETURN);
295 * get the payload of this packet
297 * @return OwPageBuffer with this packet's payload
299 public OwPageBuffer getPayload() {
300 return new OwPageBuffer(payload);
304 * check if this packet has a payload
306 * @return true if payload present
308 public boolean hasPayload() {
309 return (payloadLength > 0);
313 * convert this packet to an array of bytes
315 * @return array of bytes
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);
329 return byteBuffer.array();
333 public String toString() {
336 if (packetType == OwserverPacketType.RETURN) {
337 prefix = String.format("return code %d", packetCode);
339 prefix = String.format("messageType %s", OwserverMessageType.fromInt(packetCode));
342 return String.format("%s, size %d, controlFlags 0x%08x, payload '%s'", prefix, HEADER_SIZE + payloadLength,
343 controlFlags, getPayloadString().replaceAll("\\p{C}", "?"));