]> git.basschouten.com Git - openhab-addons.git/blob
3f0e277b415b6b9ba4b480747d905ba1f5ec6946
[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.enocean.internal.messages;
14
15 import static org.openhab.binding.enocean.internal.EnOceanBindingConstants.ZERO;
16
17 import java.security.InvalidParameterException;
18 import java.util.Arrays;
19
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;
24
25 /**
26  *
27  * @author Daniel Weber - Initial contribution
28  */
29 @NonNullByDefault
30 public class ESP2Packet {
31
32     public static final byte ENOCEAN_ESP2_FIRSTSYNC_BYTE = (byte) 0xA5;
33     public static final byte ENOCEAN_ESP2_SECONDSYNC_BYTE = 0x5A;
34
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;
41
42     public static final int ESP2_ORG_LENGTH = 1;
43
44     public static final int ESP_PACKET_LENGTH = ESP2_ORG_LENGTH + ESP2_DATA_LENGTH + ESP2_SENDERID_LENGTH
45             + ESP2_STATUS_LENGTH + ESP2_CHECKSUM_LENGTH;
46
47     public enum ORG {
48         UNKOWN((byte) 0x00),
49         _RPS((byte) 0x05),
50         _1BS((byte) 0x06),
51         _4BS((byte) 0x07);
52
53         private byte value;
54
55         private ORG(byte value) {
56             this.value = value;
57         }
58
59         public static ORG getORG(byte org) {
60             for (ORG o : ORG.values()) {
61                 if (o.value == org) {
62                     return o;
63                 }
64             }
65
66             return UNKOWN;
67         }
68     }
69
70     public enum ESP2Response {
71
72         UNKOWN((byte) 0),
73         OK((byte) 0x58),
74         ERR((byte) 0x19),
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);
88
89         private byte value;
90
91         private ESP2Response(byte value) {
92             this.value = value;
93         }
94
95         public static ESP2Response getResponse(byte response) {
96             for (ESP2Response p : ESP2Response.values()) {
97                 if (p.value == response) {
98                     return p;
99                 }
100             }
101
102             return UNKOWN;
103         }
104     }
105
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);
111
112         private byte value;
113
114         private ESP2PacketType(byte value) {
115             this.value = value;
116         }
117
118         public static ESP2PacketType getPacketType(byte packetType) {
119             for (ESP2PacketType p : ESP2PacketType.values()) {
120                 if (p.value == packetType) {
121                     return p;
122                 }
123             }
124
125             throw new InvalidParameterException("Unknown ESP2 PacketType value");
126         }
127     }
128
129     protected BasePacket basePacket;
130
131     public ESP2Packet(BasePacket basePacket) {
132         this.basePacket = basePacket;
133     }
134
135     private ESP2PacketType convertToESP2PacketType(ESPPacketType espPacketType) {
136         switch (espPacketType) {
137             case COMMON_COMMAND:
138                 return ESP2PacketType.Transmit_Command_Telegram;
139             case RADIO_ERP1:
140             case RADIO_ERP2:
141                 return ESP2PacketType.Transmit_Radio_Telegram;
142             case RESPONSE: // Response is not intended for outbound data (at least for ESP2)
143             default:
144                 throw new IllegalArgumentException("ESPPacketType not supported");
145         }
146     }
147
148     private byte convertToESP2ORG(RORG esp3RORG) {
149         switch (esp3RORG) {
150             case RPS:
151                 return ORG._RPS.value;
152             case _1BS:
153                 return ORG._1BS.value;
154             case _4BS:
155                 return ORG._4BS.value;
156             default:
157                 throw new InvalidParameterException("RORG is not supported by ESP2");
158         }
159     }
160
161     private byte[] getOrgAndDataBytes(BasePacket basePacket) {
162         byte[] data = new byte[ESP2_ORG_LENGTH + ESP2_DATA_LENGTH];
163         Arrays.fill(data, ZERO);
164
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()) {
173                 case CO_RD_IDBASE:
174                     data[0] = 0x58;
175                     break;
176                 case CO_RD_VERSION:
177                     data[0] = 0x4B;
178                     break;
179                 case CO_WR_IDBASE:
180                     data[0] = 0x18;
181                     System.arraycopy(message.getPayload(ESP2_ORG_LENGTH, 4), 0, data, ESP2_ORG_LENGTH, 4);
182                     break;
183                 default:
184                     throw new InvalidParameterException("CCMessage is not supported by ESP2");
185             }
186         }
187
188         return data;
189     }
190
191     private byte[] getSenderId(BasePacket basePacket) {
192         byte[] data = new byte[4];
193         Arrays.fill(data, ZERO);
194
195         if (basePacket.getPacketType() == ESPPacketType.RADIO_ERP1) {
196             ERP1Message message = (ERP1Message) basePacket;
197             data = message.getSenderId();
198         }
199
200         return data;
201     }
202
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];
208         }
209
210         return ZERO;
211     }
212
213     private byte calcCheckSum(byte data[], int offset, int length) {
214         int checkSum = 0;
215         for (int i = 0; i < length; i++) {
216             checkSum += (data[offset + i] & 0xff);
217         }
218
219         return (byte) (checkSum & 0xff);
220     }
221
222     public byte[] serialize() throws EnOceanException {
223         try {
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);
227
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))
231                     & 0xff);
232
233             System.arraycopy(getOrgAndDataBytes(basePacket), 0, result, ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH,
234                     ESP2_ORG_LENGTH + ESP2_DATA_LENGTH);
235
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);
239
240             result[ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH
241                     + ESP2_SENDERID_LENGTH] = getStatus(basePacket);
242
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);
247
248             return result;
249         } catch (Exception e) {
250             throw new EnOceanException(e.getMessage());
251         }
252     }
253
254     public static boolean validateCheckSum(byte data[], int length, byte checkSum) {
255         int sum = 0;
256         for (int i = 0; i < length; i++) {
257             sum += (data[i] & 0xff);
258         }
259
260         return (sum & 0xff) == (checkSum & 0xff);
261     }
262 }