2 * Copyright (c) 2010-2022 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.bluetooth.daikinmadoka.internal;
15 import java.io.ByteArrayOutputStream;
16 import java.util.Comparator;
17 import java.util.concurrent.ConcurrentSkipListSet;
18 import java.util.concurrent.locks.Lock;
19 import java.util.concurrent.locks.ReentrantLock;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.openhab.binding.bluetooth.daikinmadoka.internal.model.commands.ResponseListener;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * As the protocol emutes an UART communication over BLE (characteristics write/notify), this class takes care of BLE
30 * @author Benjamin Lafois - Initial contribution
33 public class BRC1HUartProcessor {
35 private final Logger logger = LoggerFactory.getLogger(BRC1HUartProcessor.class);
38 * Maximum number of bytes per message chunk, including headers
40 public static final int MAX_CHUNK_SIZE = 20;
43 * In the unlikely event of messages arrive in wrong order, this comparator will sort the queue
45 private Comparator<byte[]> chunkSorter = (byte[] m1, byte[] m2) -> m1[0] - m2[0];
47 private ConcurrentSkipListSet<byte[]> uartMessages = new ConcurrentSkipListSet<>(chunkSorter);
49 private ResponseListener responseListener;
51 private final Lock stateLock = new ReentrantLock();
53 public BRC1HUartProcessor(ResponseListener responseListener) {
54 this.responseListener = responseListener;
57 private boolean isMessageComplete() {
58 int messagesInQueue = this.uartMessages.size();
60 if (messagesInQueue <= 0) {
64 byte[] firstMessageInQueue = uartMessages.first();
65 if (firstMessageInQueue.length < 2) {
69 int expectedChunks = (int) Math.ceil(firstMessageInQueue[1] / (MAX_CHUNK_SIZE - 1.0));
70 if (expectedChunks != messagesInQueue) {
74 // Check that we have every single ID
76 for (byte[] m : this.uartMessages) {
81 if (m[0] != expected++) {
88 public void chunkReceived(byte[] byteValue) {
89 byte[] fullReceivedMessage = null;
92 this.uartMessages.add(byteValue);
93 if (isMessageComplete()) {
94 logger.debug("Complete message received!");
96 // Beyond this point, full message received
97 ByteArrayOutputStream bos = new ByteArrayOutputStream();
99 for (byte[] msg : uartMessages) {
100 if (msg.length > 1) {
101 bos.write(msg, 1, msg.length - 1);
105 this.uartMessages.clear();
106 fullReceivedMessage = bos.toByteArray();
112 if (fullReceivedMessage != null) {
113 this.responseListener.receivedResponse(fullReceivedMessage);
117 public void abandon() {
118 this.uartMessages.clear();