2 * Copyright (c) 2010-2022 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.plugwise.internal.protocol;
15 import java.io.UnsupportedEncodingException;
17 import org.openhab.binding.plugwise.internal.protocol.field.MACAddress;
18 import org.openhab.binding.plugwise.internal.protocol.field.MessageType;
21 * Base class to represent Plugwise protocol data units.
23 * In general a message consists of a hex string containing the following parts:
25 * <li>a type indicator - many types are yet to be reverse engineered
26 * <li>a sequence number - messages are numbered so that we can keep track of them in an application
27 * <li>a MAC address - the destination of the message
29 * <li>a CRC checksum that is calculated using the previously mentioned segments of the message
32 * Before sending off a message in the Plugwise network they are prepended with a protocol header and trailer is
35 * @author Wouter Born, Karel Goderis - Initial contribution
37 public abstract class Message {
39 public static String getCRC(String string) {
41 int polynomial = 0x1021; // 0001 0000 0010 0001 (0, 5, 12)
43 byte[] bytes = new byte[0];
45 bytes = string.getBytes("ASCII");
46 } catch (UnsupportedEncodingException e) {
50 for (byte b : bytes) {
51 for (int i = 0; i < 8; i++) {
52 boolean bit = ((b >> (7 - i) & 1) == 1);
53 boolean c15 = ((crc >> 15 & 1) == 1);
63 return (String.format("%04X", crc));
66 protected MessageType type;
67 protected Integer sequenceNumber;
68 protected MACAddress macAddress;
70 protected String payload;
72 public Message(MessageType messageType) {
73 this(messageType, null, null, null);
76 public Message(MessageType messageType, Integer sequenceNumber, MACAddress macAddress, String payload) {
77 this.type = messageType;
78 this.sequenceNumber = sequenceNumber;
79 this.macAddress = macAddress;
80 this.payload = payload;
82 if (payload != null) {
87 public Message(MessageType messageType, Integer sequenceNumber, String payload) {
88 this(messageType, sequenceNumber, null, payload);
91 public Message(MessageType messageType, MACAddress macAddress) {
92 this(messageType, null, macAddress, null);
95 public Message(MessageType messageType, MACAddress macAddress, String payload) {
96 this(messageType, null, macAddress, payload);
99 public Message(MessageType messageType, String payload) {
100 this(messageType, null, null, payload);
103 public MACAddress getMACAddress() {
107 public String getPayload() {
111 public int getSequenceNumber() {
112 return sequenceNumber;
115 public MessageType getType() {
119 // Method that implementation classes have to override, and that is responsible for parsing the payload into
121 protected void parsePayload() {
124 protected String payloadToHexString() {
125 return payload != null ? payload : "";
128 private String sequenceNumberToHexString() {
129 return String.format("%04X", sequenceNumber);
132 public void setSequenceNumber(Integer sequenceNumber) {
133 this.sequenceNumber = sequenceNumber;
136 public String toHexString() {
137 StringBuilder sb = new StringBuilder();
138 sb.append(typeToHexString());
139 if (sequenceNumber != null) {
140 sb.append(sequenceNumberToHexString());
142 if (macAddress != null) {
143 sb.append(macAddress);
145 sb.append(payloadToHexString());
147 String string = sb.toString();
148 String crc = getCRC(string);
154 public String toString() {
155 return "Message [type=" + (type != null ? type.name() : null) + ", macAddress=" + macAddress
156 + ", sequenceNumber=" + sequenceNumber + ", payload=" + payload + "]";
159 private String typeToHexString() {
160 return String.format("%04X", type.toInt());