import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
private @Nullable ScheduledFuture<?> removeInactiveDevicesTask;
private @Nullable ScheduledFuture<?> discoveryTask;
+ private @Nullable ScheduledFuture<?> initTask;
private @Nullable Future<?> passiveScanIdleTimer;
@Override
public void initialize() {
- logger.info("Initializing BlueGiga");
super.initialize();
- Optional<BlueGigaConfiguration> cfg = Optional.of(getConfigAs(BlueGigaConfiguration.class));
updateStatus(ThingStatus.UNKNOWN);
+ if (initTask == null) {
+ initTask = scheduler.scheduleWithFixedDelay(this::checkInit, 0, 10, TimeUnit.SECONDS);
+ }
+ }
+
+ protected void checkInit() {
+ boolean init = false;
+ try {
+ if (!serialHandler.get().isAlive()) {
+ logger.debug("BLE serial handler seems to be dead, reinitilize");
+ stop();
+ init = true;
+ }
+ } catch (InterruptedException e) {
+ return;
+ } catch (ExecutionException e) {
+ init = true;
+ }
+
+ if (init) {
+ logger.debug("Initialize BlueGiga");
+ start();
+ }
+ }
+
+ private void start() {
+ Optional<BlueGigaConfiguration> cfg = Optional.of(getConfigAs(BlueGigaConfiguration.class));
if (cfg.isPresent()) {
+ initComplete = false;
configuration = cfg.get();
serialPortFuture = RetryFuture.callWithRetry(() -> {
var localFuture = serialPortFuture;
- logger.debug("Initialize BlueGiga");
logger.debug("Using configuration: {}", configuration);
String serialPortName = configuration.port;
@Override
public void dispose() {
- logger.info("Disposing BlueGiga");
+ if (initTask != null) {
+ initTask.cancel(true);
+ initTask = null;
+ }
stop();
- stopScheduledTasks();
super.dispose();
}
private void stop() {
+ logger.info("Stop BlueGiga");
transactionManager.thenAccept(tman -> {
tman.removeEventListener(this);
tman.close();
serialPortFuture.thenAccept(this::closeSerialPort);
serialPortFuture.cancel(false);
+ stopScheduledTasks();
}
private void schedulePassiveScan() {
@Override
public void bluegigaClosed(Exception reason) {
- logger.debug("BlueGiga connection closed, request reinitialization");
+ logger.debug("BlueGiga connection closed, request reinitialization, reason: {}", reason.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason.getMessage());
- initComplete = false;
}
}
parserThread = createBlueGigaBLEHandler(uid);
parserThread.setUncaughtExceptionHandler((t, th) -> {
logger.warn("BluegigaSerialHandler terminating due to unhandled error", th);
+ notifyEventListeners(new BlueGigaException(
+ "BluegigaSerialHandler terminating due to unhandled error, reason " + th.getMessage()));
});
parserThread.setDaemon(true);
parserThread.start();
private void inboundMessageHandlerLoop() {
final int[] framecheckParams = { 0x00, 0x7F, 0xC0, 0xF8, 0xE0 };
- int exceptionCnt = 0;
logger.trace("BlueGiga BLE thread started");
int[] inputBuffer = new int[BLE_MAX_LENGTH];
int inputCount = 0;
}
if (inputCount < 4) {
- // The BGAPI protocol has no packet framing, and no error detection, so we do a few
- // sanity checks on the header to try and allow resyncronisation should there be an
- // error.
+ // The BGAPI protocol has no packet framing and no error detection, so we do a few
+ // sanity checks on the header to try and allow resynchronisation.
// Byte 0: Check technology type is bluetooth and high length is 0
// Byte 1: Check length is less than 64 bytes
// Byte 2: Check class ID is less than 8
} else if (inputCount == 4) {
// Process the header to get the length
inputLength = inputBuffer[1] + (inputBuffer[0] & 0x02 << 8) + 4;
- if (inputLength > 64) {
- logger.debug("BLE length larger than 64 bytes ({})", inputLength);
+ if (inputLength > BLE_MAX_LENGTH) {
+ logger.debug("Received illegal BLE packet, length larger than max {} bytes ({})",
+ BLE_MAX_LENGTH, inputLength);
if (inputStream.markSupported()) {
inputStream.reset();
}
inputCount = 0;
+ inputLength = 0;
continue;
}
- }
- if (inputCount == inputLength) {
+ } else if (inputCount == inputLength) {
+ // End of packet reached - process
if (logger.isTraceEnabled()) {
logger.trace("BLE RX: {}", printHex(inputBuffer, inputLength));
}
- // End of packet reached - process
BlueGigaResponse responsePacket = BlueGigaResponsePackets.getPacket(inputBuffer);
if (logger.isTraceEnabled()) {
}
if (responsePacket != null) {
notifyEventListeners(responsePacket);
+ } else {
+ logger.debug("Unknown packet received: {}", printHex(inputBuffer, inputLength));
}
inputCount = 0;
- exceptionCnt = 0;
- }
-
- } catch (IOException e) {
- logger.debug("BlueGiga BLE IOException: ", e);
-
- if (exceptionCnt++ > 10) {
- logger.error("BlueGiga BLE exception count exceeded, closing handler");
- close = true;
- notifyEventListeners(e);
}
} catch (Exception e) {
- logger.debug("BlueGiga BLE Exception, closing handler", e);
+ logger.trace("BlueGiga BLE Exception: ", e);
close = true;
- notifyEventListeners(e);
+ notifyEventListeners(new BlueGigaException("BlueGiga BLE Exception, reason " + e.getMessage(), e));
}
}
logger.debug("BlueGiga BLE exited.");