]> git.basschouten.com Git - openhab-addons.git/blob
af7bebcf875a1332d629f8896810b6fce065cabe
[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.velux.internal.bridge.slip.utils;
14
15 import java.nio.ByteBuffer;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 /**
22  * Transport layer supported by the Velux bridge.
23  * <P>
24  * Module semantic: encoding and decoding of frames according to RFC 1055.
25  * <P>
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}.
30  * <P>
31  * Methods available:
32  * <UL>
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>
40  * </UL>
41  *
42  * @author Guenther Schreiner - Initial contribution.
43  */
44 @NonNullByDefault
45 public class SlipEncoding {
46
47     private final Logger logger = LoggerFactory.getLogger(SlipEncoding.class);
48
49     private static final byte PROTOCOL_ID = 0;
50     private boolean encodingValid = false;
51     private byte[] message = new byte[0];
52
53     /**
54      * Builds a message based on command and parameters.
55      *
56      * @param command Message type as short.
57      * @param data Parameters as Array of bytes.
58      */
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;
65         } else {
66             byte checksum = 0;
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);
76             }
77             message[4 + data.length] = checksum;
78             logger.trace("SlipEncoding(constructor) successfully initialized, storing bytes: {}.", this.toString());
79             encodingValid = true;
80         }
81     }
82
83     /**
84      * Validates a message based on transfer syntax as Array-of-bytes.
85      *
86      * @param thisPacket Message as Array of bytes.
87      */
88
89     public SlipEncoding(byte[] thisPacket) {
90         logger.trace("SlipEncoding(constructor) called for decoding a packet with size {}.", thisPacket.length);
91         message = thisPacket;
92         encodingValid = false;
93         do {
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);
97                 break;
98             }
99             if (message[0] != PROTOCOL_ID) {
100                 logger.warn("SlipEncoding(constructor) called: Unexpected PROTOCOL_ID (got {}).",
101                         Packet.shortToString(message[0]));
102                 break;
103             }
104             byte checksum = 0;
105             for (int i = 0; i < message.length - 1; i++) {
106                 checksum = (byte) (checksum ^ message[i]);
107             }
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(":"));
112                 break;
113             }
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;
117         } while (false);
118     }
119
120     /**
121      * Returns the validity of the message content.
122      *
123      * @return <b>encodingValid</b>
124      *         of type boolean as status of the encoding or decoding.
125      */
126     public boolean isValid() {
127         return encodingValid;
128     }
129
130     /**
131      * Extracts the command.
132      *
133      * @return <b>command</b>
134      *         of type short as encoded within the message.
135      */
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));
139         return command;
140     }
141
142     /**
143      * Extracts the data i.e. parameters to the command.
144      *
145      * @return <b>data</b>
146      *         of type Array-of-byte as encoded within the message.
147      */
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());
152         return data;
153     }
154
155     /**
156      * Returns the complete message.
157      *
158      * @return <b>message</b>
159      *         of type Array-of-byte.
160      */
161     public byte[] toMessage() {
162         return message;
163     }
164
165     @Override
166     public String toString() {
167         return new Packet(message).toString();
168     }
169 }