]> git.basschouten.com Git - openhab-addons.git/blob
ad8dedab8073d641479a6099369a588cc517fcf4
[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.openhab.binding.enocean.internal.EnOceanException;
21 import org.openhab.binding.enocean.internal.messages.BasePacket.ESPPacketType;
22 import org.openhab.binding.enocean.internal.messages.ERP1Message.RORG;
23
24 /**
25  *
26  * @author Daniel Weber - Initial contribution
27  */
28 public class ESP2Packet {
29
30     public static final byte ENOCEAN_ESP2_FIRSTSYNC_BYTE = (byte) 0xA5;
31     public static final byte ENOCEAN_ESP2_SECONDSYNC_BYTE = 0x5A;
32
33     private static final int ESP2_SYNC_BYTE_LENGTH = 2;
34     private static final int ESP2_HEADER_LENGTH = 1;
35     private static final int ESP2_DATA_LENGTH = 4;
36     private static final int ESP2_SENDERID_LENGTH = 4;
37     private static final int ESP2_STATUS_LENGTH = 1;
38     private static final int ESP2_CHECKSUM_LENGTH = 1;
39
40     public static final int ESP2_ORG_LENGTH = 1;
41
42     public static final int ESP_PACKET_LENGTH = ESP2_ORG_LENGTH + ESP2_DATA_LENGTH + ESP2_SENDERID_LENGTH
43             + ESP2_STATUS_LENGTH + ESP2_CHECKSUM_LENGTH;
44
45     public enum ORG {
46         UNKOWN((byte) 0x00),
47         _RPS((byte) 0x05),
48         _1BS((byte) 0x06),
49         _4BS((byte) 0x07);
50
51         private byte value;
52
53         private ORG(byte value) {
54             this.value = value;
55         }
56
57         public static ORG getORG(byte org) {
58             for (ORG o : ORG.values()) {
59                 if (o.value == org) {
60                     return o;
61                 }
62             }
63
64             return UNKOWN;
65         }
66     }
67
68     public enum ESP2Response {
69
70         UNKOWN((byte) 0),
71         OK((byte) 0x58),
72         ERR((byte) 0x19),
73         INF_IDBase((byte) 0x98),
74         INF_RX_SENSITIVITY((byte) 0x88),
75         INF_MODEM_STATUS((byte) 0xA8),
76         INF_SW_VERSION((byte) 0x8C),
77         ERR_MODEM_NOTWANTEDACK((byte) 0x28),
78         ERR_MODEM_NOTACK((byte) 0x29),
79         ERR_MODEM_DUP_ID((byte) 0x0C),
80         ERR_SYNTAX_HSEQ((byte) 0x08),
81         ERR_SYNTAX_LENGTH((byte) 0x09),
82         ERR_SYNTAX_CHECKSUM((byte) 0x0A),
83         ERR_SYNTAX_ORG((byte) 0x0B),
84         ERR_TX_IDRANGE((byte) 0x22),
85         ERR_IDRANGE((byte) 0x1A);
86
87         private byte value;
88
89         private ESP2Response(byte value) {
90             this.value = value;
91         }
92
93         public static ESP2Response getResponse(byte response) {
94             for (ESP2Response p : ESP2Response.values()) {
95                 if (p.value == response) {
96                     return p;
97                 }
98             }
99
100             return UNKOWN;
101         }
102     }
103
104     public enum ESP2PacketType {
105         Receive_Radio_Telegram((byte) 0x00),
106         Transmit_Radio_Telegram((byte) 0x03),
107         Receive_Message_Telegram((byte) 0x04),
108         Transmit_Command_Telegram((byte) 0x05);
109
110         private byte value;
111
112         private ESP2PacketType(byte value) {
113             this.value = value;
114         }
115
116         public static ESP2PacketType getPacketType(byte packetType) {
117             for (ESP2PacketType p : ESP2PacketType.values()) {
118                 if (p.value == packetType) {
119                     return p;
120                 }
121             }
122
123             throw new InvalidParameterException("Unknown ESP2 PacketType value");
124         }
125     }
126
127     protected BasePacket basePacket;
128
129     public ESP2Packet(BasePacket basePacket) {
130         this.basePacket = basePacket;
131     }
132
133     private ESP2PacketType convertToESP2PacketType(ESPPacketType espPacketType) {
134         switch (espPacketType) {
135             case COMMON_COMMAND:
136                 return ESP2PacketType.Transmit_Command_Telegram;
137             case RADIO_ERP1:
138             case RADIO_ERP2:
139                 return ESP2PacketType.Transmit_Radio_Telegram;
140             case RESPONSE: // Response is not intended for outbound data (at least for ESP2)
141             default:
142                 throw new IllegalArgumentException("ESPPacketType not supported");
143         }
144     }
145
146     private byte convertToESP2ORG(RORG esp3RORG) {
147         switch (esp3RORG) {
148             case RPS:
149                 return ORG._RPS.value;
150             case _1BS:
151                 return ORG._1BS.value;
152             case _4BS:
153                 return ORG._4BS.value;
154             default:
155                 throw new InvalidParameterException("RORG is not supported by ESP2");
156         }
157     }
158
159     private byte[] getOrgAndDataBytes(BasePacket basePacket) {
160         byte[] data = new byte[ESP2_ORG_LENGTH + ESP2_DATA_LENGTH];
161         Arrays.fill(data, ZERO);
162
163         if (basePacket.getPacketType() == ESPPacketType.RADIO_ERP1) {
164             ERP1Message message = (ERP1Message) basePacket;
165             data[0] = convertToESP2ORG(message.getRORG());
166             System.arraycopy(message.getPayload(ESP2_ORG_LENGTH, message.getRORG().getDataLength()), 0, data,
167                     ESP2_ORG_LENGTH, message.getRORG().getDataLength());
168         } else if (basePacket.getPacketType() == ESPPacketType.COMMON_COMMAND) {
169             CCMessage message = (CCMessage) basePacket;
170             switch (message.getCCMessageType()) {
171                 case CO_RD_IDBASE:
172                     data[0] = 0x58;
173                     break;
174                 case CO_RD_VERSION:
175                     data[0] = 0x4B;
176                     break;
177                 case CO_WR_IDBASE:
178                     data[0] = 0x18;
179                     System.arraycopy(message.getPayload(ESP2_ORG_LENGTH, 4), 0, data, ESP2_ORG_LENGTH, 4);
180                     break;
181                 default:
182                     throw new InvalidParameterException("CCMessage is not supported by ESP2");
183             }
184         }
185
186         return data;
187     }
188
189     private byte[] getSenderId(BasePacket basePacket) {
190         byte[] data = new byte[4];
191         Arrays.fill(data, ZERO);
192
193         if (basePacket.getPacketType() == ESPPacketType.RADIO_ERP1) {
194             ERP1Message message = (ERP1Message) basePacket;
195             data = message.getSenderId();
196         }
197
198         return data;
199     }
200
201     private byte getStatus(BasePacket basePacket) {
202         if (basePacket.getPacketType() == ESPPacketType.RADIO_ERP1) {
203             ERP1Message message = (ERP1Message) basePacket;
204             return message.getPayload(ESP2_ORG_LENGTH + message.getRORG().getDataLength() + ESP2_SENDERID_LENGTH,
205                     ESP2_STATUS_LENGTH)[0];
206         }
207
208         return ZERO;
209     }
210
211     private byte calcCheckSum(byte data[], int offset, int length) {
212         int checkSum = 0;
213         for (int i = 0; i < length; i++) {
214             checkSum += (data[offset + i] & 0xff);
215         }
216
217         return (byte) (checkSum & 0xff);
218     }
219
220     public byte[] serialize() throws EnOceanException {
221         try {
222             byte[] result = new byte[ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH
223                     + ESP2_SENDERID_LENGTH + ESP2_STATUS_LENGTH + ESP2_CHECKSUM_LENGTH];
224             Arrays.fill(result, ZERO);
225
226             result[0] = ENOCEAN_ESP2_FIRSTSYNC_BYTE;
227             result[1] = ENOCEAN_ESP2_SECONDSYNC_BYTE;
228             result[2] = (byte) (((convertToESP2PacketType(basePacket.getPacketType()).value << 5) + (ESP_PACKET_LENGTH))
229                     & 0xff);
230
231             System.arraycopy(getOrgAndDataBytes(basePacket), 0, result, ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH,
232                     ESP2_ORG_LENGTH + ESP2_DATA_LENGTH);
233
234             System.arraycopy(getSenderId(basePacket), 0, result,
235                     ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH,
236                     ESP2_SENDERID_LENGTH);
237
238             result[ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH
239                     + ESP2_SENDERID_LENGTH] = getStatus(basePacket);
240
241             result[ESP2_SYNC_BYTE_LENGTH + ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH
242                     + ESP2_SENDERID_LENGTH + ESP2_STATUS_LENGTH] = calcCheckSum(result, ESP2_SYNC_BYTE_LENGTH,
243                             ESP2_HEADER_LENGTH + ESP2_ORG_LENGTH + ESP2_DATA_LENGTH + ESP2_SENDERID_LENGTH
244                                     + ESP2_STATUS_LENGTH);
245
246             return result;
247         } catch (Exception e) {
248             throw new EnOceanException(e.getMessage());
249         }
250     }
251
252     public static boolean validateCheckSum(byte data[], int length, byte checkSum) {
253         int sum = 0;
254         for (int i = 0; i < length; i++) {
255             sum += (data[i] & 0xff);
256         }
257
258         return (sum & 0xff) == (checkSum & 0xff);
259     }
260 }