]> git.basschouten.com Git - openhab-addons.git/blob
0e3f9cece2ef455d55b06879772cc24e64c3c135
[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.paradoxalarm.internal.communication;
14
15 import java.util.Arrays;
16
17 import org.openhab.binding.paradoxalarm.internal.communication.crypto.EncryptionHandler;
18 import org.openhab.binding.paradoxalarm.internal.util.ParadoxUtil;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 /**
23  * The {@link Response}. The response which is returned after receiving data from socket.
24  *
25  * @author Konstantin Polihronov - Initial contribution
26  */
27 public class Response implements IResponse {
28
29     private final Logger logger = LoggerFactory.getLogger(Response.class);
30
31     private IRequest request;
32     private byte[] packetBytes;
33     private byte[] header;
34     private byte[] payload;
35
36     public Response(IRequest request, byte[] content, boolean useEncryption) {
37         this.request = request;
38         this.packetBytes = content;
39         ParadoxUtil.printPacket("Rx packet", packetBytes);
40
41         if (useEncryption) {
42             decrypt();
43         }
44         parsePacket();
45     }
46
47     @Override
48     public RequestType getType() {
49         return request.getType();
50     }
51
52     @Override
53     public byte[] getPacketBytes() {
54         return packetBytes;
55     }
56
57     @Override
58     public byte[] getPayload() {
59         return payload;
60     }
61
62     @Override
63     public byte[] getHeader() {
64         return header;
65     }
66
67     @Override
68     public IRequest getRequest() {
69         return request;
70     }
71
72     public void updatePayload(byte[] payload) {
73         this.packetBytes = payload;
74     }
75
76     private void decrypt() {
77         byte[] payloadBytes = Arrays.copyOfRange(packetBytes, 16, packetBytes.length);
78         logger.trace("DECRYPTING. Full packet length={}", packetBytes.length);
79         EncryptionHandler handler = EncryptionHandler.getInstance();
80         byte[] decrypted = handler.decrypt(payloadBytes);
81
82         header = Arrays.copyOfRange(packetBytes, 0, 16);
83         payload = Arrays.copyOfRange(decrypted, 0, header[1]);
84         packetBytes = ParadoxUtil.mergeByteArrays(header, payload);
85         ParadoxUtil.printByteArray("Decrypted package=", packetBytes, packetBytes.length);
86     }
87
88     /**
89      * This method parses data from the IP150 module.
90      * A panel command, e.g. 0x5
91      * A logon sequence part is starting with 0x0, 0x1 or 0x7
92      * We ignore invalid packets which do not match our pattern.
93      *
94      */
95     private void parsePacket() {
96         // Message too short
97         if (packetBytes.length < 17) {
98             logger.debug("Message length is too short. Length={}", packetBytes.length);
99             return;
100         }
101
102         byte receivedCommand = packetBytes[16];
103         byte highNibble = ParadoxUtil.getHighNibble(receivedCommand);
104         RequestType requestType = request.getType();
105
106         switch (requestType) {
107             // For EPROM and RAM messages received command must be 0x5x
108             case EPROM:
109             case RAM:
110                 if (highNibble == 0x5) {
111                     header = Arrays.copyOfRange(packetBytes, 0, 22);
112                     payload = Arrays.copyOfRange(packetBytes, 22, packetBytes.length - 1);
113                     return;
114                 }
115                 break;
116
117             // For logon sequence packets there are various commands but their high nibbles should be either 0x0, 0x1 or
118             // 0x7
119             case LOGON_SEQUENCE:
120                 switch (highNibble) {
121                     case 0x0:
122                     case 0x1:
123                     case 0x7:
124                         header = Arrays.copyOfRange(packetBytes, 0, 16);
125                         payload = Arrays.copyOfRange(packetBytes, 16, packetBytes.length);
126                         return;
127                 }
128                 break;
129
130             case PARTITION_COMMAND:
131                 if (highNibble == 0x4) {
132                     header = Arrays.copyOfRange(packetBytes, 0, 16);
133                     payload = Arrays.copyOfRange(packetBytes, 16, 16 + packetBytes[1]);
134                     logger.debug("Received a valid response for partition command");
135                     return;
136                 }
137                 break;
138
139             case ZONE_COMMAND:
140                 if (highNibble == 0xD) {
141                     header = Arrays.copyOfRange(packetBytes, 0, 16);
142                     payload = Arrays.copyOfRange(packetBytes, 16, 16 + packetBytes[1]);
143                     logger.debug("Received a valid response for zone command");
144                     return;
145                 }
146                 break;
147         }
148
149         // All other cases are considered wrong results for the parser and are probably live events which cannot be
150         // parsed currently
151         logger.debug("Message command not expected. Received command={}", String.format("0x%08X", receivedCommand));
152         header = null;
153         payload = null;
154     }
155
156     @Override
157     public String toString() {
158         return "Response [request=" + request + ", packetBytes=" + ParadoxUtil.byteArrayToString(packetBytes) + "]";
159     }
160 }