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.paradoxalarm.internal.communication;
15 import java.util.Arrays;
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;
23 * The {@link Response}. The response which is returned after receiving data from socket.
25 * @author Konstantin Polihronov - Initial contribution
27 public class Response implements IResponse {
29 private final Logger logger = LoggerFactory.getLogger(Response.class);
31 private IRequest request;
32 private byte[] packetBytes;
33 private byte[] header;
34 private byte[] payload;
36 public Response(IRequest request, byte[] content, boolean useEncryption) {
37 this.request = request;
38 this.packetBytes = content;
39 ParadoxUtil.printPacket("Rx packet", packetBytes);
48 public RequestType getType() {
49 return request.getType();
53 public byte[] getPacketBytes() {
58 public byte[] getPayload() {
63 public byte[] getHeader() {
68 public IRequest getRequest() {
72 public void updatePayload(byte[] payload) {
73 this.packetBytes = payload;
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);
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);
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.
95 private void parsePacket() {
97 if (packetBytes.length < 17) {
98 logger.debug("Message length is too short. Length={}", packetBytes.length);
102 byte receivedCommand = packetBytes[16];
103 byte highNibble = ParadoxUtil.getHighNibble(receivedCommand);
104 RequestType requestType = request.getType();
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);
113 // For logon sequence packets there are various commands but their high nibbles should be either 0x0, 0x1 or
115 } else if (requestType == RequestType.LOGON_SEQUENCE) {
116 switch (highNibble) {
120 header = Arrays.copyOfRange(packetBytes, 0, 16);
121 payload = Arrays.copyOfRange(packetBytes, 16, packetBytes.length);
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");
133 // All other cases are considered wrong results for the parser and are probably live events which cannot be
135 logger.debug("Message command not expected. Received command={}", receivedCommand);
141 public String toString() {
142 return "Response [request=" + request + ", packetBytes=" + ParadoxUtil.byteArrayToString(packetBytes) + "]";