0

Hi I am running RxAndroidBle in a service. I set it to auto-connect because the device wakeup in every 5 minutes and try to send data to paired device. I also set notification to get the data. It works but on every disconnect I get Notifications error and Write error.

03-07 12:37:03.600 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: close()
03-07 12:37:03.600 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: unregisterApp() - mClientIf=6
03-07 12:37:03.604 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: connect() - device: B4:99:4C:67:5E:67, auto: true
03-07 12:37:03.604 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: registerApp()
03-07 12:37:03.604 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: registerApp() - UUID=1a9155ae-aa9c-465e-aacd-3c535c3d32a8
03-07 12:37:03.607 31014-31026/com.lady.viktoria.lightdrip D/BluetoothGatt: onClientRegistered() - status=0 clientIf=6
03-07 12:37:03.610 31014-31027/com.lady.viktoria.lightdrip D/BluetoothGatt: setCharacteristicNotification() - uuid: 0000ffe1-0000-1000-8000-00805f9b34fb enable: false
03-07 12:37:03.610 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Notifications error: BleGattException{macAddress=B4:99:4C:67:5E:67, status=8 (0x08 -> https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h), bleGattOperationType=BleGattOperation{description='CONNECTION_STATE'}}
03-07 12:37:03.612 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Write error: BleGattException{macAddress=B4:99:4C:67:5E:67, status=8 (0x08 -> https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h), bleGattOperationType=BleGattOperation{description='CONNECTION_STATE'}}
03-07 12:41:41.296 31014-7238/com.lady.viktoria.lightdrip D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=B4:99:4C:67:5E:67
03-07 12:41:41.304 31014-31093/com.lady.viktoria.lightdrip V/CgmBleService: Hey, connection has been established!
03-07 12:41:41.314 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: discoverServices() - device: B4:99:4C:67:5E:67
03-07 12:41:41.889 31014-7239/com.lady.viktoria.lightdrip D/BluetoothGatt: onSearchComplete() = Device=B4:99:4C:67:5E:67 Status=0
03-07 12:41:41.900 31014-31093/com.lady.viktoria.lightdrip D/BluetoothGatt: setCharacteristicNotification() - uuid: 0000ffe1-0000-1000-8000-00805f9b34fb enable: true
03-07 12:41:41.941 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Notifications has been set up
03-07 12:41:46.748 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Change: 1500300000002E000000D63CC12B680000000000
03-07 12:41:46.753 31014-31014/com.lady.viktoria.lightdrip I/CgmBleService: Received Data packet
03-07 12:41:46.763 31014-31014/com.lady.viktoria.lightdrip D/GlucoseRecord: create: No calibration yet
03-07 12:41:46.772 31014-31014/com.lady.viktoria.lightdrip I/GlucoseRecord: calculateAgeAdjustedRawValue: RAW VALUE ADJUSTMENT FROM:0.048 TO: 0.06792021355263159
03-07 12:41:46.781 31014-31014/com.lady.viktoria.lightdrip V/GlucoseRecord: glucoseRecord json: {"id":128,"a":0.0,"ageAdjustedRawValue":0.06792021355263159,"b":0.0,"c":0.0,"calculatedValue":0.0,"calculatedValueSlope":0.0,"calibrationFlag":false,"calibration_id":0,"filteredData":0.046,"ra":0.0,"rawData":0.048,"rb":0.0,"rc":0.0,"sensor_id":2,"synced":false,"timeSinceSensorStarted":1.2766377E7,"timestamp":1.488886906748E12}
03-07 12:41:46.782 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Change: 01
03-07 12:41:46.782 31014-31014/com.lady.viktoria.lightdrip D/CgmBleService: Sending Acknowledge Packet, to put wixel to sleep
03-07 12:41:46.791 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Write success
03-07 12:42:01.144 31014-31027/com.lady.viktoria.lightdrip D/BluetoothGatt: onClientConnectionState() - status=8 clientIf=6 device=B4:99:4C:67:5E:67
03-07 12:42:01.147 31014-31027/com.lady.viktoria.lightdrip V/CgmBleService: Connection Failure
03-07 12:42:01.148 31014-31014/com.lady.viktoria.lightdrip D/BluetoothManager: getConnectionState()
03-07 12:42:01.148 31014-31014/com.lady.viktoria.lightdrip D/BluetoothManager: getConnectedDevices
03-07 12:42:01.153 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: close()
03-07 12:42:01.153 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: unregisterApp() - mClientIf=6
03-07 12:42:01.161 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: connect() - device: B4:99:4C:67:5E:67, auto: true
public class CgmBleService extends Service {
private final static String TAG = CgmBleService.class.getSimpleName();

public final static UUID UUID_BG_MEASUREMENT = UUID.fromString(GattAttributes.HM_RX_TX);
public final static String ACTION_BLE_CONNECTED = "ACTION_BLE_CONNECTED";
public final static String ACTION_BLE_DISCONNECTED = "ACTION_BLE_DISCONNECTED";
public final static String ACTION_BLE_DATA_AVAILABLE = "ACTION_BLE_DATA_AVAILABLE";
public final static String EXTRA_BLE_DATA = "EXTRA_BLE_DATA";
public final static String BEACON_SNACKBAR = "BEACON_SNACKBAR";

private RxBleClient rxBleClient;
private RxBleDevice bleDevice;
private AppPreferences mTrayPreferences;
private PublishSubject<Void> disconnectTriggerSubject = PublishSubject.create();
private Observable<RxBleConnection> connectionObservable;
Handler handler;

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    handler = new Handler();
    startJobScheduler();

    // get mac address from selected wixelbridge
    mTrayPreferences = new AppPreferences(this);
    final String BTDeviceAddress = mTrayPreferences.getString("BT_MAC_Address", "00:00:00:00:00:00");

    //init rxBleClient
    rxBleClient = RxBleClient.create(this);
    bleDevice = rxBleClient.getBleDevice(BTDeviceAddress);
    // logging for RxBleClient
    RxBleClient.setLogLevel(RxBleLog.INFO);
    connectionObservable = prepareConnectionObservable();
    connect();

    return START_STICKY;
}

private Observable<RxBleConnection> prepareConnectionObservable() {
    return bleDevice
            .establishConnection(true)
            .takeUntil(disconnectTriggerSubject)
            //.compose(bindUntilEvent(PAUSE)
            .doOnUnsubscribe(this::clearSubscription)
            .compose(new ConnectionSharingAdapter());
}

public void connect() {
    if (isConnected()) {
        triggerDisconnect();
        broadcastUpdate(ACTION_BLE_CONNECTED);
    } else {
        connectionObservable.subscribe(this::onConnectionReceived, this::onConnectionFailure);
        broadcastUpdate(ACTION_BLE_DISCONNECTED);
    }
}

public void writeCharacteristic(final ByteBuffer byteBuffer) {
    byte[] bytearray = byteBuffer.array();
    if (isConnected()) {
        connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection
                        .writeCharacteristic(UUID_BG_MEASUREMENT, bytearray))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(bytes -> onWriteSuccess(), this::onWriteFailure);
    }
}

public void writeNotificationCharacteristic() {
    if (isConnected()) {
        connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection.setupNotification(UUID_BG_MEASUREMENT))
                .doOnNext(notificationObservable -> runOnUiThread(this::notificationHasBeenSetUp))
                .flatMap(notificationObservable -> notificationObservable)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::onNotificationReceived, this::onNotificationSetupFailure);
    }
}

private void runOnUiThread(Runnable runnable) {
    handler.post(runnable);
}

private boolean isConnected() {
    return bleDevice.getConnectionState() == RxBleConnection.RxBleConnectionState.CONNECTED;
}

private void clearSubscription() {
    updateUI();
}

private void triggerDisconnect() {
    disconnectTriggerSubject.onNext(null);
}

private void updateUI() {
    //   connectButton.setText(isConnected() ? getString(R.string.disconnect) : getString(R.string.connect));
    //  readButton.setEnabled(isConnected());
    //  writeButton.setEnabled(isConnected());
    // notifyButton.setEnabled(isConnected());
}



private void onConnectionFailure(Throwable throwable) {
    //noinspection ConstantConditions
    Log.v(TAG, "Connection Failure");
    connect();
}

private void onConnectionReceived(RxBleConnection connection) {
    //noinspection ConstantConditions
    Log.v(TAG, "Hey, connection has been established!");
        writeNotificationCharacteristic();
}

private void onWriteSuccess() {
    //noinspection ConstantConditions
    Log.v(TAG, "Write success");
}

private void onWriteFailure(Throwable throwable) {
    //noinspection ConstantConditions
    Log.v(TAG, "Write error: " + throwable);
}

private void onNotificationReceived(byte[] bytes) {
    //noinspection ConstantConditions
    Log.v(TAG, "Change: "  + ConvertHexString.bytesToHex(bytes));
    long timestamp = new Date().getTime();
    int packatlength = bytes[0];
    if (packatlength >= 2) {
        if (CheckTransmitterID(bytes, bytes.length)) {
            TransmitterRecord.create(bytes, bytes.length, timestamp);
        } else {
            broadcastUpdate(BEACON_SNACKBAR);
        }
    } else if (packatlength <= 1) {
        writeAcknowledgePacket();
    }
}

private void onNotificationSetupFailure(Throwable throwable) {
    //noinspection ConstantConditions
    Log.v(TAG, "Notifications error: " + throwable);
}

private void notificationHasBeenSetUp() {
    //noinspection ConstantConditions
    Log.v(TAG, "Notifications has been set up");
}

public boolean CheckTransmitterID(byte[] packet, int len) {
    int DexSrc;
    int TransmitterID;
    ByteBuffer tmpBuffer;
    final String TxId = mTrayPreferences.getString("Transmitter_Id", "00000");
    TransmitterID = ConvertTxID.convertSrc(TxId);

    tmpBuffer = ByteBuffer.allocate(len);
    tmpBuffer.order(ByteOrder.LITTLE_ENDIAN);
    tmpBuffer.put(packet, 0, len);

    if (packet[0] == 7) {
        Log.i(TAG, "Received Beacon packet.");
        broadcastUpdate(BEACON_SNACKBAR);
        writeTxIdPacket(TransmitterID);
        return false;
    } else if (packet[0] >= 21 && packet[1] == 0) {
        Log.i(TAG, "Received Data packet");
        DexSrc = tmpBuffer.getInt(12);
        TransmitterID = ConvertTxID.convertSrc(TxId);
        if (Integer.compare(DexSrc, TransmitterID) != 0) {
            writeTxIdPacket(TransmitterID);
            return false;
        } else {
            return true;
        }
    }
    return false;
}

private void writeTxIdPacket(int TransmitterID) {
    Log.v(TAG, "try to set transmitter ID");
    ByteBuffer txidMessage = ByteBuffer.allocate(6);
    txidMessage.order(ByteOrder.LITTLE_ENDIAN);
    txidMessage.put(0, (byte) 0x06);
    txidMessage.put(1, (byte) 0x01);
    txidMessage.putInt(2, TransmitterID);
    writeCharacteristic(txidMessage);
}

private void writeAcknowledgePacket() {
    Log.d(TAG, "Sending Acknowledge Packet, to put wixel to sleep");
    ByteBuffer ackMessage = ByteBuffer.allocate(2);
    ackMessage.put(0, (byte) 0x02);
    ackMessage.put(1, (byte) 0xF0);
    writeCharacteristic(ackMessage);
}

private void broadcastUpdate(final String action) {
    final Intent intent = new Intent(action);
    sendBroadcast(intent);
}

public void startJobScheduler() {
    final long REFRESH_INTERVAL = 15 * 60 * 1000;
    ComponentName serviceComponent = new ComponentName(this, SchedulerJobService.class);
    JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
    builder.setRequiresDeviceIdle(false);
    builder.setRequiresCharging(false);
    builder.setPeriodic(REFRESH_INTERVAL);
    //builder.setPersisted(true);
    JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    int result = jobScheduler.schedule(builder.build());
    if (result == JobScheduler.RESULT_SUCCESS) Log.d(TAG, "Job scheduled successfully!");
}

public void stopJobScheduler() {
    JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    jobScheduler.cancel(0);
}

@Override
public void onDestroy() {
    super.onDestroy();
    Intent broadcastIntent = new Intent("com.lady.viktoria.lightdrip.services.RestartCgmBleService");
    sendBroadcast(broadcastIntent);
    stopJobScheduler();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}}
madhan kumar
  • 1,560
  • 2
  • 26
  • 36

2 Answers2

0

It is possible that users are still subscribed to some observables related to RxBleConnection object when an independent disconnect event happens. As the library is often used without a single subscribe flow — exactly as in your case — it needs to route the information about the disconnection to all subscribers. That is why you get the same error two times.

Dariusz Seweryn
  • 3,212
  • 2
  • 14
  • 21
  • no its not the same error. there are 2 different errors. one one the setnotification characteristic and the on write characteristic. – LadyViktoria Mar 07 '17 at 13:50
  • It looks like you get exactly the same error on every subscriber that observed something — in your situation writing and notification — on the same connection. When the connection disconnected — both got that information. Could you explain your question or rephrase it? – Dariusz Seweryn Mar 07 '17 at 15:39
  • question is if this is normal and not an issue of my code. what i understand is that i subscribe to two events (success and fail). after connection is closed the fail event is started. – LadyViktoria Mar 07 '17 at 15:46
  • This behaviour is according to the design. You are subscribing to three flows: 1 - establishing the connection; 2 - writing a data packet (potentially multiple times); 3 - receiving notifications. If you unsubscribe from the 1st the connection will be closed and other subscribers (2nd and 3rd) will get notified that the connection is no longer valid (they will receive an error). – Dariusz Seweryn Mar 07 '17 at 16:56
0

thanks to @s_noopy so i have to do some thing like this:

Subscription writeNotificationSubscription;
Subscription writeCharacteristicSubscription;

public void writeCharacteristic(final ByteBuffer byteBuffer) {
        byte[] bytearray = byteBuffer.array();
        if (isConnected()) {
            writeCharacteristicSubscription = connectionObservable
                    .flatMap(rxBleConnection -> rxBleConnection
                            .writeCharacteristic(UUID_BG_MEASUREMENT, bytearray))
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(bytes -> onWriteSuccess(), this::onWriteFailure);
        }
    }

 private void onConnectionFailure(Throwable throwable) {
        //noinspection ConstantConditions
        Log.v(TAG, "Connection Failure");
        writeCharacteristicSubscription.unsubscribe();
        writeNotificationSubscription.unsubscribe();
        connect();
    }