]> git.basschouten.com Git - openhab-addons.git/blob
f1807024083eebf5ea4b11043a8bdd0af834e7ea
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.bluetooth.daikinmadoka.internal;
14
15 import java.io.ByteArrayOutputStream;
16 import java.util.Comparator;
17 import java.util.concurrent.ConcurrentSkipListSet;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.openhab.binding.bluetooth.daikinmadoka.internal.model.commands.ResponseListener;
21
22 /**
23  * As the protocol emutes an UART communication over BLE (characteristics write/notify), this class takes care of BLE
24  * transport.
25  *
26  * @author Benjamin Lafois - Initial contribution
27  */
28 @NonNullByDefault
29 public class BRC1HUartProcessor {
30
31     /**
32      * Maximum number of bytes per message chunk, including headers
33      */
34     public static final int MAX_CHUNK_SIZE = 20;
35
36     /**
37      * In the unlikely event of messages arrive in wrong order, this comparator will sort the queue
38      */
39     private Comparator<byte[]> chunkSorter = (byte[] m1, byte[] m2) -> m1[0] - m2[0];
40
41     private ConcurrentSkipListSet<byte[]> uartMessages = new ConcurrentSkipListSet<>(chunkSorter);
42
43     private ResponseListener responseListener;
44
45     public BRC1HUartProcessor(ResponseListener responseListener) {
46         this.responseListener = responseListener;
47     }
48
49     private boolean isMessageComplete() {
50         int messagesInQueue = this.uartMessages.size();
51
52         if (messagesInQueue <= 0) {
53             return false;
54         }
55
56         byte[] firstMessageInQueue = uartMessages.first();
57         if (firstMessageInQueue.length < 2) {
58             return false;
59         }
60
61         int expectedChunks = (int) Math.ceil(firstMessageInQueue[1] / (MAX_CHUNK_SIZE - 1.0));
62         if (expectedChunks != messagesInQueue) {
63             return false;
64         }
65
66         // Check that we have every single ID
67         int expected = 0;
68         for (byte[] m : this.uartMessages) {
69             if (m.length < 2) {
70                 return false;
71             }
72
73             if (m[0] != expected++) {
74                 return false;
75             }
76         }
77         return true;
78     }
79
80     public void chunkReceived(byte[] byteValue) {
81         this.uartMessages.add(byteValue);
82         if (isMessageComplete()) {
83
84             // Beyond this point, full message received
85             ByteArrayOutputStream bos = new ByteArrayOutputStream();
86
87             for (byte[] msg : uartMessages) {
88                 if (msg.length > 1) {
89                     bos.write(msg, 1, msg.length - 1);
90                 }
91             }
92
93             this.uartMessages.clear();
94
95             this.responseListener.receivedResponse(bos.toByteArray());
96         }
97     }
98
99     public void abandon() {
100         this.uartMessages.clear();
101     }
102 }