]> git.basschouten.com Git - openhab-addons.git/blob
7d68fd8c10b9ee132694b7cbb4bbbb4aa741dfd6
[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         // For EPROM and RAM messages received command must be 0x5x
107         if (requestType == RequestType.EPROM || requestType == RequestType.RAM) {
108             if (highNibble == 0x5) {
109                 header = Arrays.copyOfRange(packetBytes, 0, 22);
110                 payload = Arrays.copyOfRange(packetBytes, 22, packetBytes.length - 1);
111                 return;
112             }
113             // For logon sequence packets there are various commands but their high nibbles should be either 0x0, 0x1 or
114             // 0x7
115         } else if (requestType == RequestType.LOGON_SEQUENCE) {
116             switch (highNibble) {
117                 case 0x0:
118                 case 0x1:
119                 case 0x7:
120                     header = Arrays.copyOfRange(packetBytes, 0, 16);
121                     payload = Arrays.copyOfRange(packetBytes, 16, packetBytes.length);
122                     return;
123             }
124         } else if (requestType == RequestType.PARTITION_COMMAND) {
125             if (highNibble == 0x4) {
126                 header = Arrays.copyOfRange(packetBytes, 0, 16);
127                 payload = Arrays.copyOfRange(packetBytes, 16, 16 + packetBytes[1]);
128                 logger.debug("Received valid response for partition command");
129                 return;
130             }
131         }
132
133         // All other cases are considered wrong results for the parser and are probably live events which cannot be
134         // parsed currently
135         logger.debug("Message command not expected. Received command={}", receivedCommand);
136         header = null;
137         payload = null;
138     }
139
140     @Override
141     public String toString() {
142         return "Response [request=" + request + ", packetBytes=" + ParadoxUtil.byteArrayToString(packetBytes) + "]";
143     }
144 }