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.enocean.internal.messages;
15 import static org.openhab.binding.enocean.internal.EnOceanBindingConstants.ZERO;
17 import java.security.InvalidParameterException;
18 import java.util.Arrays;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.openhab.binding.enocean.internal.EnOceanException;
22 import org.openhab.binding.enocean.internal.messages.BasePacket.ESPPacketType;
23 import org.openhab.binding.enocean.internal.messages.ERP1Message.RORG;
27 * @author Daniel Weber - Initial contribution
30 public class ESP2Packet {
32 public static final byte ENOCEAN_ESP2_FIRSTSYNC_BYTE = (byte) 0xA5;
33 public static final byte ENOCEAN_ESP2_SECONDSYNC_BYTE = 0x5A;
35 private static final int ESP2_SYNC_BYTE_LENGTH = 2;
36 private static final int ESP2_HEADER_LENGTH = 1;
37 private static final int ESP2_DATA_LENGTH = 4;
38 private static final int ESP2_SENDERID_LENGTH = 4;
39 private static final int ESP2_STATUS_LENGTH = 1;
40 private static final int ESP2_CHECKSUM_LENGTH = 1;
42 public static final int ESP2_ORG_LENGTH = 1;
44 public static final int ESP_PACKET_LENGTH = ESP2_ORG_LENGTH + ESP2_DATA_LENGTH + ESP2_SENDERID_LENGTH
45 + ESP2_STATUS_LENGTH + ESP2_CHECKSUM_LENGTH;
55 private ORG(byte value) {
59 public static ORG getORG(byte org) {
60 for (ORG o : ORG.values()) {
70 public enum ESP2Response {
75 INF_IDBase((byte) 0x98),
76 INF_RX_SENSITIVITY((byte) 0x88),
77 INF_MODEM_STATUS((byte) 0xA8),
78 INF_SW_VERSION((byte) 0x8C),
79 ERR_MODEM_NOTWANTEDACK((byte) 0x28),
80 ERR_MODEM_NOTACK((byte) 0x29),
81 ERR_MODEM_DUP_ID((byte) 0x0C),
82 ERR_SYNTAX_HSEQ((byte) 0x08),
83 ERR_SYNTAX_LENGTH((byte) 0x09),
84 ERR_SYNTAX_CHECKSUM((byte) 0x0A),
85 ERR_SYNTAX_ORG((byte) 0x0B),
86 ERR_TX_IDRANGE((byte) 0x22),
87 ERR_IDRANGE((byte) 0x1A);
91 private ESP2Response(byte value) {
95 public static ESP2Response getResponse(byte response) {
96 for (ESP2Response p : ESP2Response.values()) {
97 if (p.value == response) {
106 public enum ESP2PacketType {
107 Receive_Radio_Telegram((byte) 0x00),
108 Transmit_Radio_Telegram((byte) 0x03),
109 Receive_Message_Telegram((byte) 0x04),
110 Transmit_Command_Telegram((byte) 0x05);
114 private ESP2PacketType(byte value) {
118 public static ESP2PacketType getPacketType(byte packetType) {
119 for (ESP2PacketType p : ESP2PacketType.values()) {
120 if (p.value == packetType) {
125 throw new InvalidParameterException("Unknown ESP2 PacketType value");
129 protected BasePacket basePacket;
131 public ESP2Packet(BasePacket basePacket) {
132 this.basePacket = basePacket;
135 private ESP2PacketType convertToESP2PacketType(ESPPacketType espPacketType) {
136 switch (espPacketType) {
138 return ESP2PacketType.Transmit_Command_Telegram;
141 return ESP2PacketType.Transmit_Radio_Telegram;
142 case RESPONSE: // Response is not intended for outbound data (at least for ESP2)
144 throw new IllegalArgumentException("ESPPacketType not supported");
148 private byte convertToESP2ORG(RORG esp3RORG) {
151 return ORG._RPS.value;
153 return ORG._1BS.value;
155 return ORG._4BS.value;
157 throw new InvalidParameterException("RORG is not supported by ESP2");
161 private byte[] getOrgAndDataBytes(BasePacket basePacket) {
162 byte[] data = new byte[ESP2_ORG_LENGTH + ESP2_DATA_LENGTH];
163 Arrays.fill(data, ZERO);
165 if (basePacket.getPacketType() == ESPPacketType.RADIO_ERP1) {
166 ERP1Message message = (ERP1Message) basePacket;
167 data[0] = convertToESP2ORG(message.getRORG());
168 System.arraycopy(message.getPayload(ESP2_ORG_LENGTH, message.getRORG().getDataLength()), 0, data,
169 ESP2_ORG_LENGTH, message.getRORG().getDataLength());
170 } else if (basePacket.getPacketType() == ESPPacketType.COMMON_COMMAND) {
171 CCMessage message = (CCMessage) basePacket;
172 switch (message.getCCMessageType()) {
181 System.arraycopy(message.getPayload(ESP2_ORG_LENGTH, 4), 0, data, ESP2_ORG_LENGTH, 4);
184 throw new InvalidParameterException("CCMessage is not supported by ESP2");
191 private byte[] getSenderId(BasePacket basePacket) {
192 byte[] data = new byte[4];
193 Arrays.fill(data, ZERO);
195 if (basePacket.getPacketType() == ESPPacketType.RADIO_ERP1) {
196 ERP1Message message = (ERP1Message) basePacket;
197 data = message.getSenderId();
203 private byte getStatus(BasePacket basePacket) {
204 if (basePacket.getPacketType() == ESPPacketType.RADIO_ERP1) {
205 ERP1Message message = (ERP1Message) basePacket;
206 return message.getPayload(ESP2_ORG_LENGTH + message.getRORG().getDataLength() + ESP2_SENDERID_LENGTH,
207 ESP2_STATUS_LENGTH)[0];
213 private byte calcCheckSum(byte data[], int offset, int length) {
215 for (int i = 0; i < length; i++) {
216 checkSum += (data[offset + i] & 0xff);
219 return (byte) (checkSum & 0xff);
222 public byte[] serialize() throws EnOceanException {
224 byte[] result = new byte[ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH
225 + ESP2_SENDERID_LENGTH + ESP2_STATUS_LENGTH + ESP2_CHECKSUM_LENGTH];
226 Arrays.fill(result, ZERO);
228 result[0] = ENOCEAN_ESP2_FIRSTSYNC_BYTE;
229 result[1] = ENOCEAN_ESP2_SECONDSYNC_BYTE;
230 result[2] = (byte) (((convertToESP2PacketType(basePacket.getPacketType()).value << 5) + (ESP_PACKET_LENGTH))
233 System.arraycopy(getOrgAndDataBytes(basePacket), 0, result, ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH,
234 ESP2_ORG_LENGTH + ESP2_DATA_LENGTH);
236 System.arraycopy(getSenderId(basePacket), 0, result,
237 ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH,
238 ESP2_SENDERID_LENGTH);
240 result[ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH
241 + ESP2_SENDERID_LENGTH] = getStatus(basePacket);
243 result[ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH
244 + ESP2_SENDERID_LENGTH + ESP2_STATUS_LENGTH] = calcCheckSum(result, ESP2_SYNC_BYTE_LENGTH,
245 ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH + ESP2_SENDERID_LENGTH
246 + ESP2_STATUS_LENGTH);
249 } catch (Exception e) {
250 throw new EnOceanException(e.getMessage());
254 public static boolean validateCheckSum(byte data[], int length, byte checkSum) {
256 for (int i = 0; i < length; i++) {
257 sum += (data[i] & 0xff);
260 return (sum & 0xff) == (checkSum & 0xff);