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.velux.internal.bridge.slip.utils;
15 import java.nio.ByteBuffer;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
22 * Transport layer supported by the Velux bridge.
24 * Module semantic: encoding and decoding of frames according to RFC 1055.
26 * It defines informations how to send query and receive answer through the
27 * {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
28 * as described by the {@link org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol
29 * BridgeCommunicationProtocol}.
33 * <LI>{@link #SlipEncoding(short command, byte[] data) } builds a message based on command and data.</LI>
34 * <LI>{@link #SlipEncoding(byte[] thisPacket) } splits a message into command and data.</LI>
35 * <LI>{@link #isValid} returns the number of bytes contained within this Packet.</LI>
36 * <LI>{@link #getCommand} returns the Command part of the message.</LI>
37 * <LI>{@link #getData} returns the data part of the message.</LI>
38 * <LI>{@link #toMessage} returns the complete message.</LI>
39 * <LI>{@link #toString} returns the message in a human-readable way.</LI>
42 * @author Guenther Schreiner - Initial contribution.
45 public class SlipEncoding {
47 private final Logger logger = LoggerFactory.getLogger(SlipEncoding.class);
49 private static final byte PROTOCOL_ID = 0;
50 private boolean encodingValid = false;
51 private byte[] message = new byte[0];
54 * Builds a message based on command and parameters.
56 * @param command Message type as short.
57 * @param data Parameters as Array of bytes.
59 public SlipEncoding(short command, byte[] data) {
60 logger.trace("SlipEncoding(constructor) for command 0x{} with data size {} called.",
61 Integer.toHexString(Short.valueOf(command).intValue()), data.length);
62 if (data.length > 250) {
63 logger.warn("SlipEncoding(constructor) called with data size {}: too big, aborting.", data.length);
64 encodingValid = false;
67 message = new byte[data.length + 5];
68 message[0] = PROTOCOL_ID;
69 message[1] = (byte) (3 + data.length);
70 message[2] = (byte) (command >>> 8);
71 message[3] = (byte) command;
72 message[4 + data.length] = 0;
73 System.arraycopy(data, 0, message, 4, data.length);
74 for (byte b : message) {
75 checksum = (byte) (checksum ^ b);
77 message[4 + data.length] = checksum;
78 logger.trace("SlipEncoding(constructor) successfully initialized, storing bytes: {}.", this.toString());
84 * Validates a message based on transfer syntax as Array-of-bytes.
86 * @param thisPacket Message as Array of bytes.
89 public SlipEncoding(byte[] thisPacket) {
90 logger.trace("SlipEncoding(constructor) called for decoding a packet with size {}.", thisPacket.length);
92 encodingValid = false;
94 // ProtocolID:Length:Command:Data(0-250):Checksum
95 if (message.length < 5) {
96 logger.warn("SlipEncoding(constructor) called with data size {}: Packet too short.", message.length);
99 if (message[0] != PROTOCOL_ID) {
100 logger.warn("SlipEncoding(constructor) called: Unexpected PROTOCOL_ID (got {}).",
101 Packet.shortToString(message[0]));
105 for (int i = 0; i < message.length - 1; i++) {
106 checksum = (byte) (checksum ^ message[i]);
108 if (message[message.length - 1] != checksum) {
109 logger.warn("SlipEncoding(constructor) Invalid packet checksum (got {} != calculated {}).",
110 Packet.shortToString(message[message.length - 1]), Packet.shortToString(checksum));
111 logger.debug("SlipEncoding(constructor) packet is {}.", new Packet(message).toString(":"));
114 logger.trace("SlipEncoding(constructor) successfully initialized with command 0x{} and data {}.",
115 Packet.shortToString(this.getCommand()), new Packet(this.getData()).toString());
116 encodingValid = true;
121 * Returns the validity of the message content.
123 * @return <b>encodingValid</b>
124 * of type boolean as status of the encoding or decoding.
126 public boolean isValid() {
127 return encodingValid;
131 * Extracts the command.
133 * @return <b>command</b>
134 * of type short as encoded within the message.
136 public short getCommand() {
137 short command = ByteBuffer.wrap(new byte[] { message[2], message[3] }).getShort();
138 logger.trace("getCommand() returns 0x{}.", String.format("%02X ", command));
143 * Extracts the data i.e. parameters to the command.
145 * @return <b>data</b>
146 * of type Array-of-byte as encoded within the message.
148 public byte[] getData() {
149 byte[] data = new byte[message.length - 5];
150 System.arraycopy(message, 4, data, 0, message.length - 5);
151 logger.trace("getData() returns {} bytes: {}.", data.length, new Packet(data).toString());
156 * Returns the complete message.
158 * @return <b>message</b>
159 * of type Array-of-byte.
161 public byte[] toMessage() {
166 public String toString() {
167 return new Packet(message).toString();