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.EOFException;
17 import java.io.IOException;
18 import java.nio.ByteBuffer;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.openhab.binding.onewire.internal.OwException;
22 import org.openhab.binding.onewire.internal.OwPageBuffer;
25 * The {@link OwserverPacket} class provides a single packet for communication with the owserver
27 * @author Jan N. Klug - Initial contribution
31 public class OwserverPacket {
32 public static final int PROTOCOL_VERSION = 0;
35 public static final int HEADER_SIZE = 24;
36 protected int payloadLength = 0;
38 protected final OwserverPacketType packetType;
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;
46 protected byte payload[] = new byte[0];
49 * constructor for new packet
51 * @param packetType packetType;
53 public OwserverPacket(OwserverPacketType packetType) {
54 this.packetType = packetType;
55 setControlFlags(OwserverControlFlag.OWNET, OwserverControlFlag.DEVICE_DISPLAY);
59 * constructor for reading packet from stream
61 * @param owInputStream input stream to read from
65 public OwserverPacket(DataInputStream owInputStream, OwserverPacketType packetType)
66 throws IOException, OwException, EOFException {
67 this.packetType = packetType;
70 protocolVersion = owInputStream.readInt();
71 payloadLength = owInputStream.readInt();
72 packetCode = owInputStream.readInt();
73 controlFlags = owInputStream.readInt();
74 packetSize = owInputStream.readInt();
75 payloadOffset = owInputStream.readInt();
78 if (payloadLength != -1) {
79 if ((protocolVersion != PROTOCOL_VERSION) || !OwserverControlFlag.OWNET.isSet(controlFlags)) {
80 throw new OwException("invalid data read");
82 if (payloadLength > 0) {
83 payload = new byte[payloadLength];
84 owInputStream.readFully(payload, 0, payloadLength);
90 * constructor for a new request message
92 * @param owMessageType
94 * @param owControlFlags
96 public OwserverPacket(OwserverMessageType owMessageType, String path, OwserverControlFlag... owControlFlags) {
97 this(OwserverPacketType.REQUEST);
98 packetCode = owMessageType.getValue();
100 setTemperatureScale(OwserverTemperatureScale.CENTIGRADE);
101 setControlFlags(owControlFlags);
102 if (owMessageType == OwserverMessageType.WRITE) {
103 packetSize = 0x00000000;
105 packetSize = 0x00010000;
110 * set one or more control flags for this packet
112 * @param flags one or more flags as OwControlFlag
114 public void setControlFlags(OwserverControlFlag... flags) {
115 for (int i = 0; i < flags.length; i++) {
116 controlFlags |= flags[i].getValue();
121 * check if a certain flag is set in this packet
123 * @param flag flag to be tested
124 * @return true if flag is set
126 public boolean hasControlFlag(OwserverControlFlag flag) {
127 return flag.isSet(controlFlags);
131 * set this packet's pressure scale
133 * @param pressureScale
135 public void setPressureScale(OwserverPressureScale pressureScale) {
136 controlFlags = pressureScale.setFlag(controlFlags);
140 * get this packets pressure scale
144 public OwserverPressureScale getPressureScale() {
145 return OwserverPressureScale.getFlag(controlFlags);
149 * set this packet's temperature scale
151 * @param pressureScale
153 public void setTemperatureScale(OwserverTemperatureScale temperatureScale) {
154 controlFlags = temperatureScale.setFlag(controlFlags);
158 * get this packets temperature scale
162 public OwserverTemperatureScale getTemperatureScale() {
163 return OwserverTemperatureScale.getFlag(controlFlags);
167 * set (or replace) this packet's payload from a string
169 * @param payload string representation of the payload
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);
179 * append to this packet's payload from a string
181 * @param payload string representation of the payload to append
183 public void appendPayload(String payload) {
184 byte appendBytes[] = payload.getBytes();
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);
190 this.packetSize += appendBytes.length;
191 this.payloadLength = fullPayload.length;
192 this.payload = fullPayload;
196 * set this packet payload from a OwPageBuffer
198 * @param payload string representation of the payload
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);
208 * get the payload of this packet
210 * @return string representation of this packet's payload
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);
218 return new String(payload, 0, payloadLength);
226 * set this packet's return code (0 is ok)
228 * @param returnCode an integer
230 public void setReturnCode(int returnCode) {
231 if (packetType == OwserverPacketType.RETURN) {
232 this.packetCode = returnCode;
234 throw new IllegalStateException("setting return code not allowed in REQUEST packets");
239 * get this packet's return code (0 is ok)
243 public int getReturnCode() {
244 if (packetType == OwserverPacketType.RETURN) {
247 throw new IllegalStateException("getting return code not allowed in REQUEST packets");
252 * set this packet's message type
256 public void setMessageType(OwserverMessageType messageType) {
257 if (packetType == OwserverPacketType.REQUEST) {
258 packetCode = messageType.getValue();
260 throw new IllegalStateException("setting message type not allowed in RETURN packets");
265 * get this packets message type
269 public OwserverMessageType getMessageType() {
270 if (packetType == OwserverPacketType.REQUEST) {
271 return OwserverMessageType.fromInt(packetCode);
273 throw new IllegalStateException("getting message type not allowed in RETURN packets");
278 * check if packed is valid return packet
280 * @return true if valid
282 public boolean isValidReturnPacket() {
283 return (packetCode == 0 && packetType == OwserverPacketType.RETURN);
287 * check if packed is valid return packet
289 * @return true if valid
291 public boolean isPingPacket() {
292 return (payloadLength == -1 && packetType == OwserverPacketType.RETURN);
296 * get the payload of this packet
298 * @return OwPageBuffer with this packet's payload
300 public OwPageBuffer getPayload() {
301 OwPageBuffer byteBuffer = new OwPageBuffer(payload);
306 * check if this packet has a payload
308 * @return true if payload present
310 public boolean hasPayload() {
311 return (payloadLength > 0);
315 * convert this packet to an array of bytes
317 * @return array of bytes
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);
331 return byteBuffer.array();
335 public String toString() {
338 if (packetType == OwserverPacketType.RETURN) {
339 prefix = String.format("return code %d", packetCode);
341 prefix = String.format("messageType %s", OwserverMessageType.fromInt(packetCode));
344 return String.format("%s, size %d, controlFlags 0x%08x, payload '%s'", prefix, HEADER_SIZE + payloadLength,
345 controlFlags, getPayloadString().replaceAll("\\p{C}", "?"));