com.polidea.rxandroidble2.exceptions.BleDisconnectedException Java Examples

The following examples show how to use com.polidea.rxandroidble2.exceptions.BleDisconnectedException. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: RxBleGattCallback.java    From RxAndroidBle with Apache License 2.0 6 votes vote down vote up
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    LoggerUtil.logCallback("onConnectionStateChange", gatt, status, newState);
    nativeCallbackDispatcher.notifyNativeConnectionStateCallback(gatt, status, newState);
    super.onConnectionStateChange(gatt, status, newState);
    bluetoothGattProvider.updateBluetoothGatt(gatt);

    if (isDisconnectedOrDisconnecting(newState)) {
        disconnectionRouter.onDisconnectedException(new BleDisconnectedException(gatt.getDevice().getAddress(), status));
    } else if (status != BluetoothGatt.GATT_SUCCESS) {
        disconnectionRouter.onGattConnectionStateException(
                new BleGattException(gatt, status, BleGattOperationType.CONNECTION_STATE)
        );
    }

    connectionStatePublishRelay.accept(mapConnectionStateToRxBleConnectionStatus(newState));
}
 
Example #2
Source File: BlueJayService.java    From xDrip-plus with GNU General Public License v3.0 6 votes vote down vote up
boolean sendOtaChunk(final UUID uuid, final byte[] bytes) {
    if (I.connection == null || !I.isConnected) return false;
    I.connection.writeCharacteristic(uuid, bytes)
            .observeOn(Schedulers.io())
            .subscribeOn(Schedulers.io())
            .subscribe(

                    characteristicValue -> {
                        if (D)
                            UserError.Log.d(TAG, "Wrote record request request: " + bytesToHex(characteristicValue));
                        busy = false;
                    }, throwable -> {
                        UserError.Log.e(TAG, "Failed to write record request: " + throwable);
                        if (throwable instanceof BleGattCharacteristicException) {
                            final int status = ((BleGattCharacteristicException) throwable).getStatus();
                            UserError.Log.e(TAG, "Got status message: " + Helper.getStatusName(status));
                        } else {
                            if (throwable instanceof BleDisconnectedException) {
                                changeState(CLOSE);
                            }
                            UserError.Log.d(TAG, "Throwable in Record End write: " + throwable);
                        }
                    });
    return true; // only that we didn't fail in setup
}
 
Example #3
Source File: BlueJayService.java    From xDrip with GNU General Public License v3.0 6 votes vote down vote up
boolean sendOtaChunk(final UUID uuid, final byte[] bytes) {
    if (I.connection == null || !I.isConnected) return false;
    I.connection.writeCharacteristic(uuid, bytes)
            .observeOn(Schedulers.io())
            .subscribeOn(Schedulers.io())
            .subscribe(

                    characteristicValue -> {
                        if (D)
                            UserError.Log.d(TAG, "Wrote record request request: " + bytesToHex(characteristicValue));
                        busy = false;
                    }, throwable -> {
                        UserError.Log.e(TAG, "Failed to write record request: " + throwable);
                        if (throwable instanceof BleGattCharacteristicException) {
                            final int status = ((BleGattCharacteristicException) throwable).getStatus();
                            UserError.Log.e(TAG, "Got status message: " + Helper.getStatusName(status));
                        } else {
                            if (throwable instanceof BleDisconnectedException) {
                                changeState(CLOSE);
                            }
                            UserError.Log.d(TAG, "Throwable in Record End write: " + throwable);
                        }
                    });
    return true; // only that we didn't fail in setup
}
 
Example #4
Source File: InPenService.java    From xDrip with GNU General Public License v3.0 5 votes vote down vote up
private void getAttachTime() {
    // TODO persist attach epoch
    if (currentPenAttachTime == null || ratelimit("inpen-get-time", 180000)) {
        I.connection.readCharacteristic(PEN_ATTACH_TIME).subscribe(
                timeValue -> {
                    UserError.Log.d(TAG, "GetAttachTime result: " + dumpHexString(timeValue));
                    currentPenAttachTime = new TimeRx().fromBytes(timeValue);
                    if (currentPenAttachTime != null) {
                        UserError.Log.d(TAG, "Current pen attach epoch: " + currentPenAttachTime.getPenTime());
                        changeNextState();
                    } else {
                        UserError.Log.e(TAG, "Current pen attach time invalid");
                    }
                }, throwable -> {
                    UserError.Log.e(TAG, "Could not read after get attach time status: " + throwable);
                    if (throwable instanceof BleDisconnectedException) {
                        changeState(CLOSE);
                    } else {
                        changeNextState();
                    }
                });

    } else {
        UserError.Log.d(TAG, "Skipping get attach time, already have epoch");
        changeNextState();
    }
}
 
Example #5
Source File: InPenService.java    From xDrip-plus with GNU General Public License v3.0 5 votes vote down vote up
private void getAttachTime() {
    // TODO persist attach epoch
    if (currentPenAttachTime == null || ratelimit("inpen-get-time", 180000)) {
        I.connection.readCharacteristic(PEN_ATTACH_TIME).subscribe(
                timeValue -> {
                    UserError.Log.d(TAG, "GetAttachTime result: " + dumpHexString(timeValue));
                    currentPenAttachTime = new TimeRx().fromBytes(timeValue);
                    if (currentPenAttachTime != null) {
                        UserError.Log.d(TAG, "Current pen attach epoch: " + currentPenAttachTime.getPenTime());
                        changeNextState();
                    } else {
                        UserError.Log.e(TAG, "Current pen attach time invalid");
                    }
                }, throwable -> {
                    UserError.Log.e(TAG, "Could not read after get attach time status: " + throwable);
                    if (throwable instanceof BleDisconnectedException) {
                        changeState(CLOSE);
                    } else {
                        changeNextState();
                    }
                });

    } else {
        UserError.Log.d(TAG, "Skipping get attach time, already have epoch");
        changeNextState();
    }
}
 
Example #6
Source File: PendiqService.java    From xDrip-plus with GNU General Public License v3.0 5 votes vote down vote up
private void writeQueueItem(final ConcurrentLinkedQueue<QueueItem> queue, final QueueItem item) {
    extendWakeLock(2000);
    connection.writeCharacteristic(OUTGOING_CHAR, item.data)
            .timeout(item.timeoutSeconds, TimeUnit.SECONDS)
            .subscribe(Value -> {
                UserError.Log.d(TAG, "Wrote request: " + item.description + " -> " + JoH.bytesToHex(Value));
                expectReply(queue, item);
                if (item.post_delay > 0) {
                    // always sleep if set as new item might appear in queue
                    final long sleep_time = item.post_delay + (item.description.contains("WAKE UP") ? 2000 : 0);
                    UserError.Log.d(TAG, "sleeping " + sleep_time);
                    JoH.threadSleep(sleep_time);
                }
                writeMultipleFromQueue(queue); // recurse
                throw new OperationSuccess("write complete: " + item.description);
            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    UserError.Log.d(TAG, "Throwable in: " + item.description + " -> " + throwable);
                    item.retries++;
                    if (!(throwable instanceof BleDisconnectedException)) {
                        if (item.retries > MAX_QUEUE_RETRIES) {
                            UserError.Log.d(TAG, item.description + " failed max retries @ " + item.retries + " shutting down queue");
                            queue.clear();
                            changeState(CLOSE);
                        } else {
                            writeQueueItem(queue, item);
                        }
                    } else {
                        UserError.Log.d(TAG, "Disconnected so not attempting retries");
                    }
                } else {
                    // not disconnecting on success
                }
            });
}
 
Example #7
Source File: PendiqService.java    From xDrip with GNU General Public License v3.0 5 votes vote down vote up
private void writeQueueItem(final ConcurrentLinkedQueue<QueueItem> queue, final QueueItem item) {
    extendWakeLock(2000);
    connection.writeCharacteristic(OUTGOING_CHAR, item.data)
            .timeout(item.timeoutSeconds, TimeUnit.SECONDS)
            .subscribe(Value -> {
                UserError.Log.d(TAG, "Wrote request: " + item.description + " -> " + JoH.bytesToHex(Value));
                expectReply(queue, item);
                if (item.post_delay > 0) {
                    // always sleep if set as new item might appear in queue
                    final long sleep_time = item.post_delay + (item.description.contains("WAKE UP") ? 2000 : 0);
                    UserError.Log.d(TAG, "sleeping " + sleep_time);
                    JoH.threadSleep(sleep_time);
                }
                writeMultipleFromQueue(queue); // recurse
                throw new OperationSuccess("write complete: " + item.description);
            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    UserError.Log.d(TAG, "Throwable in: " + item.description + " -> " + throwable);
                    item.retries++;
                    if (!(throwable instanceof BleDisconnectedException)) {
                        if (item.retries > MAX_QUEUE_RETRIES) {
                            UserError.Log.d(TAG, item.description + " failed max retries @ " + item.retries + " shutting down queue");
                            queue.clear();
                            changeState(CLOSE);
                        } else {
                            writeQueueItem(queue, item);
                        }
                    } else {
                        UserError.Log.d(TAG, "Disconnected so not attempting retries");
                    }
                } else {
                    // not disconnecting on success
                }
            });
}
 
Example #8
Source File: Ob1G5StateMachine.java    From xDrip-plus with GNU General Public License v3.0 5 votes vote down vote up
@SuppressLint("CheckResult")
private static void disconnectNow(Ob1G5CollectionService parent, RxBleConnection connection) {
    // tell device to disconnect now
    UserError.Log.d(TAG, "Disconnect NOW: " + JoH.dateTimeText(tsl()));
    speakSlowly();
    connection.writeCharacteristic(Control, nn(new DisconnectTxMessage().byteSequence))
            .timeout(2, TimeUnit.SECONDS)
            //  .observeOn(Schedulers.newThread())
            //  .subscribeOn(Schedulers.newThread())
            .subscribe(disconnectValue -> {
                if (d) UserError.Log.d(TAG, "Wrote disconnect request");
                parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                throw new OperationSuccess("Requested Disconnect");
            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    UserError.Log.d(TAG, "Disconnect NOW failure: " + JoH.dateTimeText(tsl()));
                    if (throwable instanceof BleDisconnectedException) {
                        UserError.Log.d(TAG, "Failed to write DisconnectTxMessage as already disconnected: " + throwable);

                    } else {
                        UserError.Log.e(TAG, "Failed to write DisconnectTxMessage: " + throwable);

                    }
                    parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                }
            });
    UserError.Log.d(TAG, "Disconnect NOW exit: " + JoH.dateTimeText(tsl()));
}
 
Example #9
Source File: Ob1G5StateMachine.java    From xDrip with GNU General Public License v3.0 5 votes vote down vote up
@SuppressLint("CheckResult")
private static void disconnectNow(Ob1G5CollectionService parent, RxBleConnection connection) {
    // tell device to disconnect now
    UserError.Log.d(TAG, "Disconnect NOW: " + JoH.dateTimeText(tsl()));
    speakSlowly();
    connection.writeCharacteristic(Control, nn(new DisconnectTxMessage().byteSequence))
            .timeout(2, TimeUnit.SECONDS)
            //  .observeOn(Schedulers.newThread())
            //  .subscribeOn(Schedulers.newThread())
            .subscribe(disconnectValue -> {
                if (d) UserError.Log.d(TAG, "Wrote disconnect request");
                parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                throw new OperationSuccess("Requested Disconnect");
            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    UserError.Log.d(TAG, "Disconnect NOW failure: " + JoH.dateTimeText(tsl()));
                    if (throwable instanceof BleDisconnectedException) {
                        UserError.Log.d(TAG, "Failed to write DisconnectTxMessage as already disconnected: " + throwable);

                    } else {
                        UserError.Log.e(TAG, "Failed to write DisconnectTxMessage: " + throwable);

                    }
                    parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                }
            });
    UserError.Log.d(TAG, "Disconnect NOW exit: " + JoH.dateTimeText(tsl()));
}
 
Example #10
Source File: Ob1G5StateMachine.java    From xDrip with GNU General Public License v3.0 5 votes vote down vote up
@SuppressLint("CheckResult")
private static void disconnectNow(Ob1G5CollectionService parent, RxBleConnection connection) {
    // tell device to disconnect now
    UserError.Log.d(TAG, "Disconnect NOW: " + JoH.dateTimeText(tsl()));
    speakSlowly();
    connection.writeCharacteristic(Control, nn(new DisconnectTxMessage().byteSequence))
            .timeout(2, TimeUnit.SECONDS)
            //  .observeOn(Schedulers.newThread())
            //  .subscribeOn(Schedulers.newThread())
            .subscribe(disconnectValue -> {
                if (d) UserError.Log.d(TAG, "Wrote disconnect request");
                parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                throw new OperationSuccess("Requested Disconnect");
            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    UserError.Log.d(TAG, "Disconnect NOW failure: " + JoH.dateTimeText(tsl()));
                    if (throwable instanceof BleDisconnectedException) {
                        UserError.Log.d(TAG, "Failed to write DisconnectTxMessage as already disconnected: " + throwable);

                    } else {
                        UserError.Log.e(TAG, "Failed to write DisconnectTxMessage: " + throwable);

                    }
                    parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                }
            });
    UserError.Log.d(TAG, "Disconnect NOW exit: " + JoH.dateTimeText(tsl()));
}
 
Example #11
Source File: Ob1G5StateMachine.java    From xDrip-plus with GNU General Public License v3.0 5 votes vote down vote up
@SuppressLint("CheckResult")
private static void disconnectNow(Ob1G5CollectionService parent, RxBleConnection connection) {
    // tell device to disconnect now
    UserError.Log.d(TAG, "Disconnect NOW: " + JoH.dateTimeText(tsl()));
    speakSlowly();
    connection.writeCharacteristic(Control, nn(new DisconnectTxMessage().byteSequence))
            .timeout(2, TimeUnit.SECONDS)
            //  .observeOn(Schedulers.newThread())
            //  .subscribeOn(Schedulers.newThread())
            .subscribe(disconnectValue -> {
                if (d) UserError.Log.d(TAG, "Wrote disconnect request");
                parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                throw new OperationSuccess("Requested Disconnect");
            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    UserError.Log.d(TAG, "Disconnect NOW failure: " + JoH.dateTimeText(tsl()));
                    if (throwable instanceof BleDisconnectedException) {
                        UserError.Log.d(TAG, "Failed to write DisconnectTxMessage as already disconnected: " + throwable);

                    } else {
                        UserError.Log.e(TAG, "Failed to write DisconnectTxMessage: " + throwable);

                    }
                    parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                }
            });
    UserError.Log.d(TAG, "Disconnect NOW exit: " + JoH.dateTimeText(tsl()));
}
 
Example #12
Source File: JamBaseBluetoothSequencer.java    From xDrip with GNU General Public License v3.0 5 votes vote down vote up
private void onConnectionFailure(Throwable throwable) {
    UserError.Log.d(TAG, "received: onConnectionFailure: " + throwable);
    if (throwable instanceof BleAlreadyConnectedException) {
        UserError.Log.d(TAG, "Already connected - advancing to next stage");
        I.isConnected = true;
        changeNextState();
    } else if (throwable instanceof BleDisconnectedException) {
        if (((BleDisconnectedException) throwable).state == 133) {
            if (I.retry133) {
                if (JoH.ratelimit(TAG + "133recon", 60)) {
                    if (I.state.equals(CONNECT_NOW)) {
                        UserError.Log.d(TAG, "Automatically retrying connection");
                        Inevitable.task(TAG + "133recon", 3000, new Runnable() {
                            @Override
                            public void run() {
                                changeState(CONNECT_NOW);
                            }
                        });
                    }
                }
            }
        } else if (I.autoConnect) {
            UserError.Log.d(TAG, "Auto reconnect persist");
            changeState(CONNECT_NOW);
        }
    }
}
 
Example #13
Source File: JamBaseBluetoothSequencer.java    From xDrip-plus with GNU General Public License v3.0 5 votes vote down vote up
private void onConnectionFailure(Throwable throwable) {
    UserError.Log.d(TAG, "received: onConnectionFailure: " + throwable);
    if (throwable instanceof BleAlreadyConnectedException) {
        UserError.Log.d(TAG, "Already connected - advancing to next stage");
        I.isConnected = true;
        changeNextState();
    } else if (throwable instanceof BleDisconnectedException) {
        if (((BleDisconnectedException) throwable).state == 133) {
            if (I.retry133) {
                if (JoH.ratelimit(TAG + "133recon", 60)) {
                    if (I.state.equals(CONNECT_NOW)) {
                        UserError.Log.d(TAG, "Automatically retrying connection");
                        Inevitable.task(TAG + "133recon", 3000, new Runnable() {
                            @Override
                            public void run() {
                                changeState(CONNECT_NOW);
                            }
                        });
                    }
                }
            }
        } else if (I.autoConnect) {
            UserError.Log.d(TAG, "Auto reconnect persist");
            changeState(CONNECT_NOW);
        }
    }
}
 
Example #14
Source File: MiBandService.java    From xDrip-plus with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
private void installWatchface() {
    //TODO decrease display brightness before uploading watchface to minimize battery consumption
    RxBleConnection connection = I.connection;
    if (d)
        UserError.Log.d(TAG, "Install WatchFace");
    if (I.connection == null) {
        if (d)
            UserError.Log.d(TAG, "Cannot enable as connection is null!");
        return;
    }
    try {
        WatchFaceGenerator wfGen = new WatchFaceGenerator(getBaseContext().getAssets());
        byte[] fwArray = wfGen.genWatchFace();
        if (fwArray == null || fwArray.length == 0) {
            resetFirmwareState(false, "Empty image");
            return;
        }
        firmware = new FirmwareOperations(fwArray);
    } catch (Exception e) {
        resetFirmwareState(false, "FirmwareOperations error " + e.getMessage());
        return;
    }
    if (d)
        UserError.Log.d(TAG, "Begin uploading Watchface, lenght: " + firmware.getSize());
    if (d)
        UserError.Log.d(TAG, "Requesting to enable notifications for installWatchface");
    watchfaceSubscription = new Subscription(
            connection.setupNotification(firmware.getFirmwareCharacteristicUUID())
                    .timeout(400, TimeUnit.SECONDS) // WARN
                    .doOnNext(notificationObservable -> {
                                if (d)
                                    UserError.Log.d(TAG, "Notification for firmware enabled");
                                firmware.nextSequence();
                                processFirmwareCommands(null, true);
                            }
                    )
                    .flatMap(notificationObservable -> notificationObservable)
                    .subscribe(bytes -> {
                        // incoming notifications
                        if (d)
                            UserError.Log.d(TAG, "Received firmware notification bytes: " + bytesToHex(bytes));
                        processFirmwareCommands(bytes, false);
                    }, throwable -> {
                        UserError.Log.d(TAG, "Throwable in firmware Notification: " + throwable);
                        if (throwable instanceof BleCharacteristicNotFoundException) {
                            // maybe legacy - ignore for now but needs better handling
                            UserError.Log.d(TAG, "Characteristic not found for notification");
                        } else if (throwable instanceof BleCannotSetCharacteristicNotificationException) {
                            UserError.Log.e(TAG, "Problems setting notifications - disconnecting");
                        } else if (throwable instanceof BleDisconnectedException) {
                            UserError.Log.d(TAG, "Disconnected while enabling notifications");
                        } else if (throwable instanceof TimeoutException) {
                            UserError.Log.d(TAG, "Timeout");
                        }
                        resetFirmwareState(false);
                    }));
}
 
Example #15
Source File: Ob1G5StateMachine.java    From xDrip-plus with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
public static boolean doCheckAuth(Ob1G5CollectionService parent, RxBleConnection connection) {

    if (connection == null) return false;
    parent.msg("Authorizing");

    if (parent.android_wear) {
        speakSlowly = true;
        UserError.Log.d(TAG, "Setting speak slowly to true"); // WARN should be reactive or on named devices
    }

    final AuthRequestTxMessage authRequest = new AuthRequestTxMessage(getTokenSize(), usingAlt());
    UserError.Log.i(TAG, "AuthRequestTX: " + JoH.bytesToHex(authRequest.byteSequence));

    connection.setupNotification(Authentication)
            // .timeout(10, TimeUnit.SECONDS)
            .timeout(15, TimeUnit.SECONDS) // WARN
            // .observeOn(Schedulers.newThread()) // needed?
            .doOnNext(notificationObservable -> {
                connection.writeCharacteristic(Authentication, nn(authRequest.byteSequence))
                        .subscribe(
                                characteristicValue -> {
                                    // Characteristic value confirmed.
                                    if (d)
                                        UserError.Log.d(TAG, "Wrote authrequest, got: " + JoH.bytesToHex(characteristicValue));
                                    speakSlowly();
                                    connection.readCharacteristic(Authentication).subscribe(
                                            readValue -> {
                                                authenticationProcessor(parent, connection, readValue);
                                            }, throwable -> {
                                                UserError.Log.e(TAG, "Could not read after AuthRequestTX: " + throwable);
                                            });
                                    //parent.background_automata();
                                },
                                throwable -> {
                                    UserError.Log.e(TAG, "Could not write AuthRequestTX: " + throwable);
                                    parent.incrementErrors();
                                }

                        );
            }).flatMap(notificationObservable -> notificationObservable)
            //.timeout(5, TimeUnit.SECONDS)
            //.observeOn(Schedulers.newThread())
            .subscribe(bytes -> {
                // incoming notifications
                UserError.Log.d(TAG, "Received Authentication notification bytes: " + JoH.bytesToHex(bytes));
                authenticationProcessor(parent, connection, bytes);

            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    if (((parent.getState() == Ob1G5CollectionService.STATE.CLOSED)
                            || (parent.getState() == Ob1G5CollectionService.STATE.CLOSE))
                            && (throwable instanceof BleDisconnectedException)) {
                        UserError.Log.d(TAG, "normal authentication notification throwable: (" + parent.getState() + ") " + throwable + " " + JoH.dateTimeText(tsl()));
                        parent.connectionStateChange(CLOSED_OK_TEXT);
                    } else if ((parent.getState() == Ob1G5CollectionService.STATE.BOND) && (throwable instanceof TimeoutException)) {
                        // TODO Trigger on Error count / Android wear metric
                        // UserError.Log.e(TAG,"Attempting to reset/create bond due to: "+throwable);
                        // parent.reset_bond(true);
                        // parent.unBond(); // WARN
                    } else {
                        UserError.Log.e(TAG, "authentication notification  throwable: (" + parent.getState() + ") " + throwable + " " + JoH.dateTimeText(tsl()));
                        parent.incrementErrors();
                        if (throwable instanceof BleCannotSetCharacteristicNotificationException
                                || throwable instanceof BleGattCharacteristicException) {
                            parent.tryGattRefresh();
                            parent.changeState(Ob1G5CollectionService.STATE.SCAN);
                        }
                    }
                    if ((throwable instanceof BleDisconnectedException) || (throwable instanceof TimeoutException)) {
                        if ((parent.getState() == Ob1G5CollectionService.STATE.BOND) || (parent.getState() == Ob1G5CollectionService.STATE.CHECK_AUTH)) {

                            if (parent.getState() == Ob1G5CollectionService.STATE.BOND) {
                                UserError.Log.d(TAG, "SLEEPING BEFORE RECONNECT");
                                threadSleep(15000);
                            }
                            UserError.Log.d(TAG, "REQUESTING RECONNECT");
                            parent.changeState(Ob1G5CollectionService.STATE.SCAN);
                        }
                    }
                }
            });
    return true;
}
 
Example #16
Source File: Ob1G5StateMachine.java    From xDrip-plus with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
private static void processQueueCommand(Ob1G5CollectionService parent, RxBleConnection connection) {
    boolean changed = false;
    synchronized (commandQueue) {
        if (!commandQueue.isEmpty()) {
            final Ob1Work unit = commandQueue.poll();
            if (unit != null) {
                changed = true;
                reprocessTxMessage(unit.msg);
                if (unit.retry < 5 && JoH.msSince(unit.timestamp) < HOUR_IN_MS * 8) {
                    connection.writeCharacteristic(Control, nn(unit.msg.byteSequence))
                            .timeout(2, TimeUnit.SECONDS)
                            .subscribe(value -> {
                                UserError.Log.d(TAG, "Wrote Queue Message: " + unit.text);
                                final long guardTime = unit.msg.guardTime();
                                inevitableDisconnect(parent, connection, guardTime);
                                if (guardTime > 0) {
                                    UserError.Log.d(TAG, "Sleeping post execute: " + unit.text + " " + guardTime + "ms");
                                    JoH.threadSleep(guardTime);
                                }
                                throw new OperationSuccess("Completed: " + unit.text);

                            }, throwable -> {
                                if (!(throwable instanceof OperationSuccess)) {
                                    unit.retry++;
                                    UserError.Log.d(TAG, "Re-adding: " + unit.text);
                                    synchronized (commandQueue) {
                                        commandQueue.push(unit);
                                    }
                                    UserError.Log.d(TAG, "Failure: " + unit.text + " " + JoH.dateTimeText(tsl()));
                                    if (throwable instanceof BleDisconnectedException) {
                                        UserError.Log.d(TAG, "Disconnected: " + unit.text + " " + throwable);
                                        parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                                    } else {
                                        UserError.Log.e(TAG, "Failed to write: " + unit.text + " " + throwable);
                                    }
                                    parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                                } else {
                                    queued(parent, connection); // turtles all the way down
                                }
                            });
                } else {
                    UserError.Log.e(TAG, "Ejected command from queue due to being too old: " + unit.text + " " + JoH.dateTimeText(unit.timestamp));
                    queued(parent, connection); // move on to next command if we just ejected something
                }
            }
            if (commandQueue.isEmpty()) {
                if (d) UserError.Log.d(TAG, "Command Queue Drained");
                if (android_wear) {
                    PersistentStore.setBoolean(PREF_QUEUE_DRAINED, true);
                }
            }
        } else {
            UserError.Log.d(TAG, "Command Queue is Empty");
        }
    }
    if (changed) saveQueue();
}
 
Example #17
Source File: JamBaseBluetoothSequencer.java    From xDrip-plus with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
private void writeQueueItem(final PoorMansConcurrentLinkedDeque<QueueItem> queue, final QueueItem item) {
    extendWakeLock(2000 + item.post_delay);
    if (I.connection == null) {
        UserError.Log.e(TAG, "Cannot write queue item: " + item.description + " as we have no connection!");
        return;
    }

    if (item.queueWriteCharacterstic == null) {
        UserError.Log.e(TAG, "Write characteristic not set in queue write");
        return;
    }
    UserError.Log.d(TAG, "Writing to characteristic: " + item.queueWriteCharacterstic + " " + item.description);
    I.connection.writeCharacteristic(item.queueWriteCharacterstic, item.getData())
            .timeout(item.timeoutSeconds, TimeUnit.SECONDS)
            .subscribe(Value -> {
                UserError.Log.d(TAG, "Wrote request: " + item.description + " -> " + JoH.bytesToHex(Value));
                if (item.expectReply) expectReply(queue, item);
                if (item.post_delay > 0) {
                    // always sleep if set as new item might appear in queue
                    final long sleep_time = item.post_delay + (item.description.contains("WAKE UP") ? 2000 : 0);
                    if (sleep_time != 100) UserError.Log.d(TAG, "sleeping " + sleep_time);
                    JoH.threadSleep(sleep_time);
                }
                if (item.runnable != null) {
                    item.runnable.run(); // TODO should this be handled by expect reply in that case?
                }
                if (!item.expectReply) {
                    if (item.replyProcessor != null) {
                        item.replyProcessor.process(Value);
                    }
                    writeMultipleFromQueue(queue); // start next item immediately
                }
                throw new OperationSuccess("write complete: " + item.description);
            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    UserError.Log.d(TAG, "Throwable in: " + item.description + " -> " + throwable);
                    item.retries++;
                    if (!(throwable instanceof BleDisconnectedException)) {
                        if (item.retries > MAX_QUEUE_RETRIES) {
                            UserError.Log.d(TAG, item.description + " failed max retries @ " + item.retries + " shutting down queue");
                            queue.clear(); /// clear too?
                            //changeState(CLOSE); // TODO put on switch
                        } else {
                            writeQueueItem(queue, item);
                        }
                    } else {
                        UserError.Log.d(TAG, "Disconnected so not attempting retries");
                        I.isConnected = false;
                    }
                } else {
                    // not disconnecting on success
                }
            });
}
 
Example #18
Source File: MiBandService.java    From xDrip-plus with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
private void authPhase() {
    extendWakeLock(30000);
    RxBleConnection connection = I.connection;
    if (d)
        UserError.Log.d(TAG, "Authorizing");
    if (I.connection == null) {
        if (d)
            UserError.Log.d(TAG, "Cannot enable as connection is null!");
        return;
    }

    String authKey = MiBand.getPersistentAuthKey();
    if (MiBand.getMibandType() == MI_BAND4) {
        if (authKey.isEmpty()) {
            authKey = MiBand.getAuthKey();
            if (authKey.isEmpty()) {
                authKey = AuthMessages.getAuthCodeFromFilesSystem(MiBand.getMac());
            }
            if (!AuthMessages.isValidAuthKey(authKey)) {
                JoH.static_toast_long("Wrong miband authorization key, please recheck a key and try to reconnect again");
                changeState(AUTHORIZE_FAILED);
                return;
            } else {
                MiBand.setAuthKey(authKey);
            }
        }
    }
    if (!AuthMessages.isValidAuthKey(authKey)) {
        authKey = "";
    }
    if (d)
        UserError.Log.d(TAG, "authKey: " + authKey);

    authorisation = new AuthMessages(MiBand.getMibandType(), authKey);
    if (d)
        UserError.Log.d(TAG, "localKey: " + JoH.bytesToHex(authorisation.getLocalKey()));
    authSubscription = new Subscription(
            connection.setupNotification(authorisation.getCharacteristicUUID())
                    .timeout(20, TimeUnit.SECONDS) // WARN
                    // .observeOn(Schedulers.newThread()) // needed?
                    .doOnNext(notificationObservable -> {
                                if (d)
                                    UserError.Log.d(TAG, "Notification for auth enabled");
                                if (MiBand.isAuthenticated()) {
                                    connection.writeCharacteristic(authorisation.getCharacteristicUUID(), authorisation.getAuthKeyRequest()) //get random key from band
                                            .subscribe(val -> {
                                                if (d)
                                                    UserError.Log.d(TAG, "Wrote getAuthKeyRequest: " + JoH.bytesToHex(val));
                                            }, throwable -> {
                                                UserError.Log.e(TAG, "Could not getAuthKeyRequest: " + throwable);
                                            });
                                } else {
                                    connection.writeCharacteristic(authorisation.getCharacteristicUUID(), authorisation.getAuthCommand())
                                            .subscribe(characteristicValue -> {
                                                        UserError.Log.d(TAG, "Wrote getAuthCommand, got: " + JoH.bytesToHex(characteristicValue));
                                                    },
                                                    throwable -> {
                                                        UserError.Log.e(TAG, "Could not write getAuthCommand: " + throwable);
                                                    }
                                            );
                                }

                            }
                    )
                    .flatMap(notificationObservable -> notificationObservable)
                    .subscribe(bytes -> {
                        // incoming notifications
                        if (d)
                            UserError.Log.d(TAG, "Received auth notification bytes: " + bytesToHex(bytes));
                        ProcessAuthCommands(connection, bytes);
                        // changeNextState();
                    }, throwable -> {
                        UserError.Log.d(TAG, "Throwable in Record Notification: " + throwable);
                        if (throwable instanceof BleCharacteristicNotFoundException) {
                            // maybe legacy - ignore for now but needs better handling
                            UserError.Log.d(TAG, "Characteristic not found for notification");
                        } else if (throwable instanceof BleCannotSetCharacteristicNotificationException) {
                            UserError.Log.e(TAG, "Problems setting notifications - disconnecting");
                        } else if (throwable instanceof BleDisconnectedException) {
                            UserError.Log.d(TAG, "Disconnected while enabling notifications");
                        } else if (throwable instanceof TimeoutException) {
                            //check if it is normal timeout
                            if (!MiBand.isAuthenticated()) {
                                String errorText = "MiBand authentication failed due to authentication timeout. When your Mi Band vibrates and blinks, tap it a few times in a row.";
                                UserError.Log.d(TAG, errorText);
                                JoH.static_toast_long(errorText);
                            }
                        }
                        if (authSubscription != null) {
                            authSubscription.unsubscribe();
                        }
                        changeState(CLOSE);
                    }));
}
 
Example #19
Source File: InPenService.java    From xDrip-plus with GNU General Public License v3.0 4 votes vote down vote up
private void getRecords(final int firstIndex, final int lastIndex) {

        final int numberOfRecords = lastIndex - firstIndex;
        if (numberOfRecords > 30) {
            I.connection.writeCharacteristic(KEEPALIVE, new KeepAliveTx().getBytes()).subscribe(
                    value -> {
                        UserError.Log.d(TAG, "Wrote keep alive for " + numberOfRecords);
                    }, throwable -> {
                        UserError.Log.d(TAG, "Got exception in keep alive" + throwable);
                    });
        }

        final RecordTx packet = new RecordTx(firstIndex, lastIndex);
        UserError.Log.d(TAG, "getRecords called, loading: " + firstIndex + " to " + lastIndex);
        I.connection.setupIndication(RECORD_INDICATE).doOnNext(notificationObservable -> {

            I.connection.writeCharacteristic(RECORD_START, packet.startBytes()).subscribe(valueS -> {
                UserError.Log.d(TAG, "Wrote record start: " + bytesToHex(valueS));
                I.connection.writeCharacteristic(RECORD_END, packet.endBytes()).subscribe(valueE -> {
                    UserError.Log.d(TAG, "Wrote record end: " + bytesToHex(valueE));
                    I.connection.writeCharacteristic(RECORD_REQUEST, packet.triggerBytes()).subscribe(
                            characteristicValue -> {

                                if (D)
                                    UserError.Log.d(TAG, "Wrote record request request: " + bytesToHex(characteristicValue));
                            }, throwable -> {
                                UserError.Log.e(TAG, "Failed to write record request: " + throwable);
                                if (throwable instanceof BleGattCharacteristicException) {
                                    final int status = ((BleGattCharacteristicException) throwable).getStatus();
                                    UserError.Log.e(TAG, "Got status message: " + Helper.getStatusName(status));
                                }
                            });
                }, throwable -> {
                    UserError.Log.d(TAG, "Throwable in Record End write: " + throwable);
                });
            }, throwable -> {
                UserError.Log.d(TAG, "Throwable in Record Start write: " + throwable);
                // throws BleGattCharacteristicException status = 128 for "no resources" eg nothing matches
            });
        })
                .flatMap(notificationObservable -> notificationObservable)
                .timeout(120, TimeUnit.SECONDS)
                .observeOn(Schedulers.newThread())
                .subscribe(bytes -> {

                    records.add(bytes);
                    UserError.Log.d(TAG, "INDICATE INDICATE: " + HexDump.dumpHexString(bytes));

                }, throwable -> {
                    if (!(throwable instanceof OperationSuccess)) {
                        if (throwable instanceof BleDisconnectedException) {
                            UserError.Log.d(TAG, "Disconnected when waiting to receive indication: " + throwable);

                        } else {
                            UserError.Log.e(TAG, "Error receiving indication: " + throwable);

                        }
                        Inevitable.task("check-records-queue", 100, this::processRecordsQueue);
                    }
                });

    }
 
Example #20
Source File: BlueJayService.java    From xDrip-plus with GNU General Public License v3.0 4 votes vote down vote up
private void enableNotifications() {
    UserError.Log.d(TAG, "enableNotifications called()");
    if (I.isNotificationEnabled) {
        UserError.Log.d(TAG, "Notifications already enabled");
        changeNextState();
        return;
    }
    if (notificationSubscription != null) {
        notificationSubscription.unsubscribe();
    }
    JoH.threadSleep(500);
    UserError.Log.d(TAG, "Requesting to enable notifications");
    notificationSubscription = new Subscription(
            I.connection.setupNotification(THINJAM_WRITE)
                    // .timeout(15, TimeUnit.SECONDS) // WARN
                    // .observeOn(Schedulers.newThread()) // needed?
                    .doOnNext(notificationObservable -> {

                                UserError.Log.d(TAG, "Notifications enabled");
                                I.connection.writeCharacteristic(THINJAM_BULK, new byte[]{0x55});

                                JoH.threadSleep(500); // Debug sleep to make sure notifications are actually enabled???
                                I.isNotificationEnabled = true;
                                changeNextState();
                            }

                    ).flatMap(notificationObservable -> notificationObservable)
                    //.timeout(5, TimeUnit.SECONDS)
                    .observeOn(Schedulers.newThread())
                    .subscribe(bytes -> {
                        // incoming notifications
                        UserError.Log.d(TAG, "Received notification bytes: " + JoH.bytesToHex(bytes));
                        val pushRx = PushRx.parse(bytes);
                        if (pushRx != null) {
                            UserError.Log.d(TAG, "Received PushRX: " + pushRx.toS());
                            getInfo().processPushRx(pushRx);
                            processPushRxActions(pushRx);
                        } else if (bytes[0] == 0x06) {
                            // TODO move this to parsed response
                            final int replyParam = ((int) bytes[1]) & 0xff;
                            if (replyParam == 0) {
                                UserError.Log.d(TAG, "Bulk up success reply marker received! - removing queue head item");
                                commandQueue.poll(); // removes first item from the queue which should be the one we just processed!
                                UserError.Log.d(TAG, "Scheduling immediate run of queue");
                                Inevitable.kill("tj-next-queue"); // remove timeout retry task
                                Inevitable.task("tj-next-queue", 0, this::processQueue);
                            } else {
                                revisedOffset = replyParam;
                                UserError.Log.d(TAG, "Bulk up failure at: " + revisedOffset); // race condition on display
                            }
                        } else if (bytes[0] == (byte) 0xFE) {
                            audioStreamCallBack(bytes);
                        } else {
                            if (ThinJamActivity.isD()) {
                                notificationString.append(new String(bytes));
                                Inevitable.task("tj update notifi", 250, new Runnable() {
                                    @Override
                                    public void run() {
                                        stringObservableField.set(notificationString.toString());
                                    }
                                });
                            }
                        }
                    }, throwable -> {
                        UserError.Log.d(TAG, "Throwable in Record Notification: " + throwable);
                        I.isNotificationEnabled = false;

                        if (throwable instanceof BleCharacteristicNotFoundException) {
                            // maybe legacy - ignore for now but needs better handling
                            UserError.Log.d(TAG, "Characteristic not found for notification");
                            debug.processTestSuite("logcharerror");
                            tryGattRefresh(getI().connection);
                        }
                        if (throwable instanceof BleCannotSetCharacteristicNotificationException) {
                            UserError.Log.e(TAG, "Problems setting notifications - disconnecting");
                            changeState(CLOSE);
                        }
                        if (throwable instanceof BleDisconnectedException) {
                            UserError.Log.d(TAG, "Disconnected while enabling notifications");
                            changeState(CLOSE);
                        }

                    }));
}
 
Example #21
Source File: Ob1G5StateMachine.java    From xDrip-plus with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
public static boolean doCheckAuth(Ob1G5CollectionService parent, RxBleConnection connection) {

    if (connection == null) return false;
    parent.msg("Authorizing");

    if (parent.android_wear) {
        speakSlowly = true;
        UserError.Log.d(TAG, "Setting speak slowly to true"); // WARN should be reactive or on named devices
    }

    final AuthRequestTxMessage authRequest = new AuthRequestTxMessage(getTokenSize(), usingAlt());
    UserError.Log.i(TAG, "AuthRequestTX: " + JoH.bytesToHex(authRequest.byteSequence));

    connection.setupNotification(Authentication)
            // .timeout(10, TimeUnit.SECONDS)
            .timeout(15, TimeUnit.SECONDS) // WARN
            // .observeOn(Schedulers.newThread()) // needed?
            .doOnNext(notificationObservable -> {
                connection.writeCharacteristic(Authentication, nn(authRequest.byteSequence))
                        .subscribe(
                                characteristicValue -> {
                                    // Characteristic value confirmed.
                                    if (d)
                                        UserError.Log.d(TAG, "Wrote authrequest, got: " + JoH.bytesToHex(characteristicValue));
                                    speakSlowly();
                                    connection.readCharacteristic(Authentication).subscribe(
                                            readValue -> {
                                                authenticationProcessor(parent, connection, readValue);
                                            }, throwable -> {
                                                UserError.Log.e(TAG, "Could not read after AuthRequestTX: " + throwable);
                                            });
                                    //parent.background_automata();
                                },
                                throwable -> {
                                    UserError.Log.e(TAG, "Could not write AuthRequestTX: " + throwable);
                                    parent.incrementErrors();
                                }

                        );
            }).flatMap(notificationObservable -> notificationObservable)
            //.timeout(5, TimeUnit.SECONDS)
            //.observeOn(Schedulers.newThread())
            .subscribe(bytes -> {
                // incoming notifications
                UserError.Log.d(TAG, "Received Authentication notification bytes: " + JoH.bytesToHex(bytes));
                authenticationProcessor(parent, connection, bytes);

            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    if (((parent.getState() == Ob1G5CollectionService.STATE.CLOSED)
                            || (parent.getState() == Ob1G5CollectionService.STATE.CLOSE))
                            && (throwable instanceof BleDisconnectedException)) {
                        UserError.Log.d(TAG, "normal authentication notification throwable: (" + parent.getState() + ") " + throwable + " " + JoH.dateTimeText(tsl()));
                        parent.connectionStateChange(CLOSED_OK_TEXT);
                    } else if ((parent.getState() == Ob1G5CollectionService.STATE.BOND) && (throwable instanceof TimeoutException)) {
                        // TODO Trigger on Error count / Android wear metric
                        // UserError.Log.e(TAG,"Attempting to reset/create bond due to: "+throwable);
                        // parent.reset_bond(true);
                        // parent.unBond(); // WARN
                    } else {
                        UserError.Log.e(TAG, "authentication notification  throwable: (" + parent.getState() + ") " + throwable + " " + JoH.dateTimeText(tsl()));
                        parent.incrementErrors();
                        if (throwable instanceof BleCannotSetCharacteristicNotificationException
                                || throwable instanceof BleGattCharacteristicException) {
                            parent.tryGattRefresh();
                            parent.changeState(Ob1G5CollectionService.STATE.SCAN);
                        }
                    }
                    if ((throwable instanceof BleDisconnectedException) || (throwable instanceof TimeoutException)) {
                        if ((parent.getState() == Ob1G5CollectionService.STATE.BOND) || (parent.getState() == Ob1G5CollectionService.STATE.CHECK_AUTH)) {

                            if (parent.getState() == Ob1G5CollectionService.STATE.BOND) {
                                UserError.Log.d(TAG, "SLEEPING BEFORE RECONNECT");
                                threadSleep(15000);
                            }
                            UserError.Log.d(TAG, "REQUESTING RECONNECT");
                            parent.changeState(Ob1G5CollectionService.STATE.SCAN);
                        }
                    }
                }
            });
    return true;
}
 
Example #22
Source File: Ob1G5StateMachine.java    From xDrip-plus with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
private static void processQueueCommand(Ob1G5CollectionService parent, RxBleConnection connection) {
    boolean changed = false;
    synchronized (commandQueue) {
        if (!commandQueue.isEmpty()) {
            final Ob1Work unit = commandQueue.poll();
            if (unit != null) {
                changed = true;
                reprocessTxMessage(unit.msg);
                if (unit.retry < 5 && JoH.msSince(unit.timestamp) < HOUR_IN_MS * 8) {
                    connection.writeCharacteristic(Control, nn(unit.msg.byteSequence))
                            .timeout(2, TimeUnit.SECONDS)
                            .subscribe(value -> {
                                UserError.Log.d(TAG, "Wrote Queue Message: " + unit.text);
                                final long guardTime = unit.msg.guardTime();
                                inevitableDisconnect(parent, connection, guardTime);
                                if (guardTime > 0) {
                                    UserError.Log.d(TAG, "Sleeping post execute: " + unit.text + " " + guardTime + "ms");
                                    JoH.threadSleep(guardTime);
                                }
                                throw new OperationSuccess("Completed: " + unit.text);

                            }, throwable -> {
                                if (!(throwable instanceof OperationSuccess)) {
                                    unit.retry++;
                                    UserError.Log.d(TAG, "Re-adding: " + unit.text);
                                    synchronized (commandQueue) {
                                        commandQueue.push(unit);
                                    }
                                    UserError.Log.d(TAG, "Failure: " + unit.text + " " + JoH.dateTimeText(tsl()));
                                    if (throwable instanceof BleDisconnectedException) {
                                        UserError.Log.d(TAG, "Disconnected: " + unit.text + " " + throwable);
                                        parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                                    } else {
                                        UserError.Log.e(TAG, "Failed to write: " + unit.text + " " + throwable);
                                    }
                                    parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                                } else {
                                    queued(parent, connection); // turtles all the way down
                                }
                            });
                } else {
                    UserError.Log.e(TAG, "Ejected command from queue due to being too old: " + unit.text + " " + JoH.dateTimeText(unit.timestamp));
                    queued(parent, connection); // move on to next command if we just ejected something
                }
            }
            if (commandQueue.isEmpty()) {
                if (d) UserError.Log.d(TAG, "Command Queue Drained");
                if (android_wear) {
                    PersistentStore.setBoolean(PREF_QUEUE_DRAINED, true);
                }
            }
        } else {
            UserError.Log.d(TAG, "Command Queue is Empty");
        }
    }
    if (changed) saveQueue();
}
 
Example #23
Source File: ConnectionOperationQueueImpl.java    From RxAndroidBle with Apache License 2.0 4 votes vote down vote up
@Override
public void onConnectionUnsubscribed() {
    disconnectionThrowableSubscription.dispose();
    disconnectionThrowableSubscription = null;
    terminate(new BleDisconnectedException(deviceMacAddress, BleDisconnectedException.UNKNOWN_STATUS));
}
 
Example #24
Source File: InPenService.java    From xDrip with GNU General Public License v3.0 4 votes vote down vote up
private void getRecords(final int firstIndex, final int lastIndex) {

        final int numberOfRecords = lastIndex - firstIndex;
        if (numberOfRecords > 30) {
            I.connection.writeCharacteristic(KEEPALIVE, new KeepAliveTx().getBytes()).subscribe(
                    value -> {
                        UserError.Log.d(TAG, "Wrote keep alive for " + numberOfRecords);
                    }, throwable -> {
                        UserError.Log.d(TAG, "Got exception in keep alive" + throwable);
                    });
        }

        final RecordTx packet = new RecordTx(firstIndex, lastIndex);
        UserError.Log.d(TAG, "getRecords called, loading: " + firstIndex + " to " + lastIndex);
        I.connection.setupIndication(RECORD_INDICATE).doOnNext(notificationObservable -> {

            I.connection.writeCharacteristic(RECORD_START, packet.startBytes()).subscribe(valueS -> {
                UserError.Log.d(TAG, "Wrote record start: " + bytesToHex(valueS));
                I.connection.writeCharacteristic(RECORD_END, packet.endBytes()).subscribe(valueE -> {
                    UserError.Log.d(TAG, "Wrote record end: " + bytesToHex(valueE));
                    I.connection.writeCharacteristic(RECORD_REQUEST, packet.triggerBytes()).subscribe(
                            characteristicValue -> {

                                if (D)
                                    UserError.Log.d(TAG, "Wrote record request request: " + bytesToHex(characteristicValue));
                            }, throwable -> {
                                UserError.Log.e(TAG, "Failed to write record request: " + throwable);
                                if (throwable instanceof BleGattCharacteristicException) {
                                    final int status = ((BleGattCharacteristicException) throwable).getStatus();
                                    UserError.Log.e(TAG, "Got status message: " + Helper.getStatusName(status));
                                }
                            });
                }, throwable -> {
                    UserError.Log.d(TAG, "Throwable in Record End write: " + throwable);
                });
            }, throwable -> {
                UserError.Log.d(TAG, "Throwable in Record Start write: " + throwable);
                // throws BleGattCharacteristicException status = 128 for "no resources" eg nothing matches
            });
        })
                .flatMap(notificationObservable -> notificationObservable)
                .timeout(120, TimeUnit.SECONDS)
                .observeOn(Schedulers.newThread())
                .subscribe(bytes -> {

                    records.add(bytes);
                    UserError.Log.d(TAG, "INDICATE INDICATE: " + HexDump.dumpHexString(bytes));

                }, throwable -> {
                    if (!(throwable instanceof OperationSuccess)) {
                        if (throwable instanceof BleDisconnectedException) {
                            UserError.Log.d(TAG, "Disconnected when waiting to receive indication: " + throwable);

                        } else {
                            UserError.Log.e(TAG, "Error receiving indication: " + throwable);

                        }
                        Inevitable.task("check-records-queue", 100, this::processRecordsQueue);
                    }
                });

    }
 
Example #25
Source File: Ob1G5StateMachine.java    From xDrip with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
private static void processQueueCommand(Ob1G5CollectionService parent, RxBleConnection connection) {
    boolean changed = false;
    synchronized (commandQueue) {
        if (!commandQueue.isEmpty()) {
            final Ob1Work unit = commandQueue.poll();
            if (unit != null) {
                changed = true;
                reprocessTxMessage(unit.msg);
                if (unit.retry < 5 && JoH.msSince(unit.timestamp) < HOUR_IN_MS * 8) {
                    connection.writeCharacteristic(Control, nn(unit.msg.byteSequence))
                            .timeout(2, TimeUnit.SECONDS)
                            .subscribe(value -> {
                                UserError.Log.d(TAG, "Wrote Queue Message: " + unit.text);
                                final long guardTime = unit.msg.guardTime();
                                inevitableDisconnect(parent, connection, guardTime);
                                if (guardTime > 0) {
                                    UserError.Log.d(TAG, "Sleeping post execute: " + unit.text + " " + guardTime + "ms");
                                    JoH.threadSleep(guardTime);
                                }
                                throw new OperationSuccess("Completed: " + unit.text);

                            }, throwable -> {
                                if (!(throwable instanceof OperationSuccess)) {
                                    unit.retry++;
                                    UserError.Log.d(TAG, "Re-adding: " + unit.text);
                                    synchronized (commandQueue) {
                                        commandQueue.push(unit);
                                    }
                                    UserError.Log.d(TAG, "Failure: " + unit.text + " " + JoH.dateTimeText(tsl()));
                                    if (throwable instanceof BleDisconnectedException) {
                                        UserError.Log.d(TAG, "Disconnected: " + unit.text + " " + throwable);
                                        parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                                    } else {
                                        UserError.Log.e(TAG, "Failed to write: " + unit.text + " " + throwable);
                                    }
                                    parent.changeState(Ob1G5CollectionService.STATE.CLOSE);
                                } else {
                                    queued(parent, connection); // turtles all the way down
                                }
                            });
                } else {
                    UserError.Log.e(TAG, "Ejected command from queue due to being too old: " + unit.text + " " + JoH.dateTimeText(unit.timestamp));
                    queued(parent, connection); // move on to next command if we just ejected something
                }
            }
            if (commandQueue.isEmpty()) {
                if (d) UserError.Log.d(TAG, "Command Queue Drained");
                if (android_wear) {
                    PersistentStore.setBoolean(PREF_QUEUE_DRAINED, true);
                }
            }
        } else {
            UserError.Log.d(TAG, "Command Queue is Empty");
        }
    }
    if (changed) saveQueue();
}
 
Example #26
Source File: Ob1G5StateMachine.java    From xDrip with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
public static boolean doCheckAuth(Ob1G5CollectionService parent, RxBleConnection connection) {

    if (connection == null) return false;
    parent.msg("Authorizing");

    if (parent.android_wear) {
        speakSlowly = true;
        UserError.Log.d(TAG, "Setting speak slowly to true"); // WARN should be reactive or on named devices
    }

    final AuthRequestTxMessage authRequest = new AuthRequestTxMessage(getTokenSize(), usingAlt());
    UserError.Log.i(TAG, "AuthRequestTX: " + JoH.bytesToHex(authRequest.byteSequence));

    connection.setupNotification(Authentication)
            // .timeout(10, TimeUnit.SECONDS)
            .timeout(15, TimeUnit.SECONDS) // WARN
            // .observeOn(Schedulers.newThread()) // needed?
            .doOnNext(notificationObservable -> {
                connection.writeCharacteristic(Authentication, nn(authRequest.byteSequence))
                        .subscribe(
                                characteristicValue -> {
                                    // Characteristic value confirmed.
                                    if (d)
                                        UserError.Log.d(TAG, "Wrote authrequest, got: " + JoH.bytesToHex(characteristicValue));
                                    speakSlowly();
                                    connection.readCharacteristic(Authentication).subscribe(
                                            readValue -> {
                                                authenticationProcessor(parent, connection, readValue);
                                            }, throwable -> {
                                                UserError.Log.e(TAG, "Could not read after AuthRequestTX: " + throwable);
                                            });
                                    //parent.background_automata();
                                },
                                throwable -> {
                                    UserError.Log.e(TAG, "Could not write AuthRequestTX: " + throwable);
                                    parent.incrementErrors();
                                }

                        );
            }).flatMap(notificationObservable -> notificationObservable)
            //.timeout(5, TimeUnit.SECONDS)
            //.observeOn(Schedulers.newThread())
            .subscribe(bytes -> {
                // incoming notifications
                UserError.Log.d(TAG, "Received Authentication notification bytes: " + JoH.bytesToHex(bytes));
                authenticationProcessor(parent, connection, bytes);

            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    if (((parent.getState() == Ob1G5CollectionService.STATE.CLOSED)
                            || (parent.getState() == Ob1G5CollectionService.STATE.CLOSE))
                            && (throwable instanceof BleDisconnectedException)) {
                        UserError.Log.d(TAG, "normal authentication notification throwable: (" + parent.getState() + ") " + throwable + " " + JoH.dateTimeText(tsl()));
                        parent.connectionStateChange(CLOSED_OK_TEXT);
                    } else if ((parent.getState() == Ob1G5CollectionService.STATE.BOND) && (throwable instanceof TimeoutException)) {
                        // TODO Trigger on Error count / Android wear metric
                        // UserError.Log.e(TAG,"Attempting to reset/create bond due to: "+throwable);
                        // parent.reset_bond(true);
                        // parent.unBond(); // WARN
                    } else {
                        UserError.Log.e(TAG, "authentication notification  throwable: (" + parent.getState() + ") " + throwable + " " + JoH.dateTimeText(tsl()));
                        parent.incrementErrors();
                        if (throwable instanceof BleCannotSetCharacteristicNotificationException
                                || throwable instanceof BleGattCharacteristicException) {
                            parent.tryGattRefresh();
                            parent.changeState(Ob1G5CollectionService.STATE.SCAN);
                        }
                    }
                    if ((throwable instanceof BleDisconnectedException) || (throwable instanceof TimeoutException)) {
                        if ((parent.getState() == Ob1G5CollectionService.STATE.BOND) || (parent.getState() == Ob1G5CollectionService.STATE.CHECK_AUTH)) {

                            if (parent.getState() == Ob1G5CollectionService.STATE.BOND) {
                                UserError.Log.d(TAG, "SLEEPING BEFORE RECONNECT");
                                threadSleep(15000);
                            }
                            UserError.Log.d(TAG, "REQUESTING RECONNECT");
                            parent.changeState(Ob1G5CollectionService.STATE.SCAN);
                        }
                    }
                }
            });
    return true;
}
 
Example #27
Source File: BlueJayService.java    From xDrip with GNU General Public License v3.0 4 votes vote down vote up
private void enableNotifications() {
    UserError.Log.d(TAG, "enableNotifications called()");
    if (I.isNotificationEnabled) {
        UserError.Log.d(TAG, "Notifications already enabled");
        changeNextState();
        return;
    }
    if (notificationSubscription != null) {
        notificationSubscription.unsubscribe();
    }
    JoH.threadSleep(500);
    UserError.Log.d(TAG, "Requesting to enable notifications");
    notificationSubscription = new Subscription(
            I.connection.setupNotification(THINJAM_WRITE)
                    // .timeout(15, TimeUnit.SECONDS) // WARN
                    // .observeOn(Schedulers.newThread()) // needed?
                    .doOnNext(notificationObservable -> {

                                UserError.Log.d(TAG, "Notifications enabled");
                                I.connection.writeCharacteristic(THINJAM_BULK, new byte[]{0x55});

                                JoH.threadSleep(500); // Debug sleep to make sure notifications are actually enabled???
                                I.isNotificationEnabled = true;
                                changeNextState();
                            }

                    ).flatMap(notificationObservable -> notificationObservable)
                    //.timeout(5, TimeUnit.SECONDS)
                    .observeOn(Schedulers.newThread())
                    .subscribe(bytes -> {
                        // incoming notifications
                        UserError.Log.d(TAG, "Received notification bytes: " + JoH.bytesToHex(bytes));
                        val pushRx = PushRx.parse(bytes);
                        if (pushRx != null) {
                            UserError.Log.d(TAG, "Received PushRX: " + pushRx.toS());
                            getInfo().processPushRx(pushRx);
                            processPushRxActions(pushRx);
                        } else if (bytes[0] == 0x06) {
                            // TODO move this to parsed response
                            final int replyParam = ((int) bytes[1]) & 0xff;
                            if (replyParam == 0) {
                                UserError.Log.d(TAG, "Bulk up success reply marker received! - removing queue head item");
                                commandQueue.poll(); // removes first item from the queue which should be the one we just processed!
                                UserError.Log.d(TAG, "Scheduling immediate run of queue");
                                Inevitable.kill("tj-next-queue"); // remove timeout retry task
                                Inevitable.task("tj-next-queue", 0, this::processQueue);
                            } else {
                                revisedOffset = replyParam;
                                UserError.Log.d(TAG, "Bulk up failure at: " + revisedOffset); // race condition on display
                            }
                        } else if (bytes[0] == (byte) 0xFE) {
                            audioStreamCallBack(bytes);
                        } else {
                            if (ThinJamActivity.isD()) {
                                notificationString.append(new String(bytes));
                                Inevitable.task("tj update notifi", 250, new Runnable() {
                                    @Override
                                    public void run() {
                                        stringObservableField.set(notificationString.toString());
                                    }
                                });
                            }
                        }
                    }, throwable -> {
                        UserError.Log.d(TAG, "Throwable in Record Notification: " + throwable);
                        I.isNotificationEnabled = false;

                        if (throwable instanceof BleCharacteristicNotFoundException) {
                            // maybe legacy - ignore for now but needs better handling
                            UserError.Log.d(TAG, "Characteristic not found for notification");
                            debug.processTestSuite("logcharerror");
                            tryGattRefresh(getI().connection);
                        }
                        if (throwable instanceof BleCannotSetCharacteristicNotificationException) {
                            UserError.Log.e(TAG, "Problems setting notifications - disconnecting");
                            changeState(CLOSE);
                        }
                        if (throwable instanceof BleDisconnectedException) {
                            UserError.Log.d(TAG, "Disconnected while enabling notifications");
                            changeState(CLOSE);
                        }

                    }));
}
 
Example #28
Source File: MiBandService.java    From xDrip with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
private void installWatchface() {
    //TODO decrease display brightness before uploading watchface to minimize battery consumption
    RxBleConnection connection = I.connection;
    if (d)
        UserError.Log.d(TAG, "Install WatchFace");
    if (I.connection == null) {
        if (d)
            UserError.Log.d(TAG, "Cannot enable as connection is null!");
        return;
    }
    try {
        WatchFaceGenerator wfGen = new WatchFaceGenerator(getBaseContext().getAssets());
        byte[] fwArray = wfGen.genWatchFace();
        if (fwArray == null || fwArray.length == 0) {
            resetFirmwareState(false, "Empty image");
            return;
        }
        firmware = new FirmwareOperations(fwArray);
    } catch (Exception e) {
        resetFirmwareState(false, "FirmwareOperations error " + e.getMessage());
        return;
    }
    if (d)
        UserError.Log.d(TAG, "Begin uploading Watchface, lenght: " + firmware.getSize());
    if (d)
        UserError.Log.d(TAG, "Requesting to enable notifications for installWatchface");
    watchfaceSubscription = new Subscription(
            connection.setupNotification(firmware.getFirmwareCharacteristicUUID())
                    .timeout(400, TimeUnit.SECONDS) // WARN
                    .doOnNext(notificationObservable -> {
                                if (d)
                                    UserError.Log.d(TAG, "Notification for firmware enabled");
                                firmware.nextSequence();
                                processFirmwareCommands(null, true);
                            }
                    )
                    .flatMap(notificationObservable -> notificationObservable)
                    .subscribe(bytes -> {
                        // incoming notifications
                        if (d)
                            UserError.Log.d(TAG, "Received firmware notification bytes: " + bytesToHex(bytes));
                        processFirmwareCommands(bytes, false);
                    }, throwable -> {
                        UserError.Log.d(TAG, "Throwable in firmware Notification: " + throwable);
                        if (throwable instanceof BleCharacteristicNotFoundException) {
                            // maybe legacy - ignore for now but needs better handling
                            UserError.Log.d(TAG, "Characteristic not found for notification");
                        } else if (throwable instanceof BleCannotSetCharacteristicNotificationException) {
                            UserError.Log.e(TAG, "Problems setting notifications - disconnecting");
                        } else if (throwable instanceof BleDisconnectedException) {
                            UserError.Log.d(TAG, "Disconnected while enabling notifications");
                        } else if (throwable instanceof TimeoutException) {
                            UserError.Log.d(TAG, "Timeout");
                        }
                        resetFirmwareState(false);
                    }));
}
 
Example #29
Source File: MiBandService.java    From xDrip with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
private void authPhase() {
    extendWakeLock(30000);
    RxBleConnection connection = I.connection;
    if (d)
        UserError.Log.d(TAG, "Authorizing");
    if (I.connection == null) {
        if (d)
            UserError.Log.d(TAG, "Cannot enable as connection is null!");
        return;
    }

    String authKey = MiBand.getPersistentAuthKey();
    if (MiBand.getMibandType() == MI_BAND4) {
        if (authKey.isEmpty()) {
            authKey = MiBand.getAuthKey();
            if (authKey.isEmpty()) {
                authKey = AuthMessages.getAuthCodeFromFilesSystem(MiBand.getMac());
            }
            if (!AuthMessages.isValidAuthKey(authKey)) {
                JoH.static_toast_long("Wrong miband authorization key, please recheck a key and try to reconnect again");
                changeState(AUTHORIZE_FAILED);
                return;
            } else {
                MiBand.setAuthKey(authKey);
            }
        }
    }
    if (!AuthMessages.isValidAuthKey(authKey)) {
        authKey = "";
    }
    if (d)
        UserError.Log.d(TAG, "authKey: " + authKey);

    authorisation = new AuthMessages(MiBand.getMibandType(), authKey);
    if (d)
        UserError.Log.d(TAG, "localKey: " + JoH.bytesToHex(authorisation.getLocalKey()));
    authSubscription = new Subscription(
            connection.setupNotification(authorisation.getCharacteristicUUID())
                    .timeout(20, TimeUnit.SECONDS) // WARN
                    // .observeOn(Schedulers.newThread()) // needed?
                    .doOnNext(notificationObservable -> {
                                if (d)
                                    UserError.Log.d(TAG, "Notification for auth enabled");
                                if (MiBand.isAuthenticated()) {
                                    connection.writeCharacteristic(authorisation.getCharacteristicUUID(), authorisation.getAuthKeyRequest()) //get random key from band
                                            .subscribe(val -> {
                                                if (d)
                                                    UserError.Log.d(TAG, "Wrote getAuthKeyRequest: " + JoH.bytesToHex(val));
                                            }, throwable -> {
                                                UserError.Log.e(TAG, "Could not getAuthKeyRequest: " + throwable);
                                            });
                                } else {
                                    connection.writeCharacteristic(authorisation.getCharacteristicUUID(), authorisation.getAuthCommand())
                                            .subscribe(characteristicValue -> {
                                                        UserError.Log.d(TAG, "Wrote getAuthCommand, got: " + JoH.bytesToHex(characteristicValue));
                                                    },
                                                    throwable -> {
                                                        UserError.Log.e(TAG, "Could not write getAuthCommand: " + throwable);
                                                    }
                                            );
                                }

                            }
                    )
                    .flatMap(notificationObservable -> notificationObservable)
                    .subscribe(bytes -> {
                        // incoming notifications
                        if (d)
                            UserError.Log.d(TAG, "Received auth notification bytes: " + bytesToHex(bytes));
                        ProcessAuthCommands(connection, bytes);
                        // changeNextState();
                    }, throwable -> {
                        UserError.Log.d(TAG, "Throwable in Record Notification: " + throwable);
                        if (throwable instanceof BleCharacteristicNotFoundException) {
                            // maybe legacy - ignore for now but needs better handling
                            UserError.Log.d(TAG, "Characteristic not found for notification");
                        } else if (throwable instanceof BleCannotSetCharacteristicNotificationException) {
                            UserError.Log.e(TAG, "Problems setting notifications - disconnecting");
                        } else if (throwable instanceof BleDisconnectedException) {
                            UserError.Log.d(TAG, "Disconnected while enabling notifications");
                        } else if (throwable instanceof TimeoutException) {
                            //check if it is normal timeout
                            if (!MiBand.isAuthenticated()) {
                                String errorText = "MiBand authentication failed due to authentication timeout. When your Mi Band vibrates and blinks, tap it a few times in a row.";
                                UserError.Log.d(TAG, errorText);
                                JoH.static_toast_long(errorText);
                            }
                        }
                        if (authSubscription != null) {
                            authSubscription.unsubscribe();
                        }
                        changeState(CLOSE);
                    }));
}
 
Example #30
Source File: JamBaseBluetoothSequencer.java    From xDrip with GNU General Public License v3.0 4 votes vote down vote up
@SuppressLint("CheckResult")
private void writeQueueItem(final PoorMansConcurrentLinkedDeque<QueueItem> queue, final QueueItem item) {
    extendWakeLock(2000 + item.post_delay);
    if (I.connection == null) {
        UserError.Log.e(TAG, "Cannot write queue item: " + item.description + " as we have no connection!");
        return;
    }

    if (item.queueWriteCharacterstic == null) {
        UserError.Log.e(TAG, "Write characteristic not set in queue write");
        return;
    }
    UserError.Log.d(TAG, "Writing to characteristic: " + item.queueWriteCharacterstic + " " + item.description);
    I.connection.writeCharacteristic(item.queueWriteCharacterstic, item.getData())
            .timeout(item.timeoutSeconds, TimeUnit.SECONDS)
            .subscribe(Value -> {
                UserError.Log.d(TAG, "Wrote request: " + item.description + " -> " + JoH.bytesToHex(Value));
                if (item.expectReply) expectReply(queue, item);
                if (item.post_delay > 0) {
                    // always sleep if set as new item might appear in queue
                    final long sleep_time = item.post_delay + (item.description.contains("WAKE UP") ? 2000 : 0);
                    if (sleep_time != 100) UserError.Log.d(TAG, "sleeping " + sleep_time);
                    JoH.threadSleep(sleep_time);
                }
                if (item.runnable != null) {
                    item.runnable.run(); // TODO should this be handled by expect reply in that case?
                }
                if (!item.expectReply) {
                    if (item.replyProcessor != null) {
                        item.replyProcessor.process(Value);
                    }
                    writeMultipleFromQueue(queue); // start next item immediately
                }
                throw new OperationSuccess("write complete: " + item.description);
            }, throwable -> {
                if (!(throwable instanceof OperationSuccess)) {
                    UserError.Log.d(TAG, "Throwable in: " + item.description + " -> " + throwable);
                    item.retries++;
                    if (!(throwable instanceof BleDisconnectedException)) {
                        if (item.retries > MAX_QUEUE_RETRIES) {
                            UserError.Log.d(TAG, item.description + " failed max retries @ " + item.retries + " shutting down queue");
                            queue.clear(); /// clear too?
                            //changeState(CLOSE); // TODO put on switch
                        } else {
                            writeQueueItem(queue, item);
                        }
                    } else {
                        UserError.Log.d(TAG, "Disconnected so not attempting retries");
                        I.isConnected = false;
                    }
                } else {
                    // not disconnecting on success
                }
            });
}