ongebear
ongebear

Reputation: 35

BLE Reading Constant Data Stream after Enabling Notifications

Update Below

I am trying to receive a constant stream of serial data from an HM-10 bluetooth device connected to an arduino setup. I am using the BLE Scanner on the google play store to find the MAC address and UUIDs. There is a single characteristic which can read, write and notify. Enabling notifications on the app allows for the display of the constant stream of data, while reading displays the address. I can't figure out how enabling notifications allow access to the data stream. I have written code that enables me to continuously read (displaying the address, just like the app) and I'm wondering how I could access the notify data. Sorry if I have the terminology wrong, I don't really understand BLE notifications. Here is my Connect, Runnable, and Callback code:

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void Connect(View view) throws InterruptedException {

    Device = Adapter.getRemoteDevice("3C:A3:08:94:C3:11");

    Gatt = Device.connectGatt(this, true, GattCallback);


}

private final BluetoothGattCallback GattCallback = new BluetoothGattCallback() {
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

        if (newState == BluetoothProfile.STATE_CONNECTED) {
            Gatt.discoverServices();


        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            Service = Gatt.getService(UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB"));
            Characteristic = Service.getCharacteristic(UUID.fromString("0000FFE1-0000-1000-8000-00805F9B34FB"));
            Gatt.setCharacteristicNotification(Characteristic, true);
            thread.start();


        } else {
        }

    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        final byte[] data = characteristic.getValue();
        if (data != null && data.length > 0) {
            final StringBuilder stringBuilder = new StringBuilder(data.length);
            for (byte byteChar : data) {
                stringBuilder.append(String.format("%02X ", byteChar));
            }


            final String strReceived = stringBuilder.toString();

            ErrorID.setText(strReceived);

        }


    }

};

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void run() {
        UUID uuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
        BluetoothGattDescriptor descriptor = Characteristic.getDescriptor(uuid);
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        Gatt.writeDescriptor(descriptor);
        while (true) {
            Gatt.readCharacteristic(Characteristic);

        }
    }

Sorry if the code is not very "clean",

Thanks!

Upvotes: 1

Views: 2206

Answers (3)

LED-Guy1618
LED-Guy1618

Reputation: 1

You can increase the max. character limit for a data package using the following line of code in the OnServicesDiscovered Callback method:

mBluetoothGatt.requestMtu(80); 

In place of the '80' you enter the max number of bytes you plan on receiving.

Then in the BluetoothGattCallback you want to include the following case with a system log print to confirm you have successfully updated the character limit:

public void onMtuChanged(BluetoothGatt bluetoothGatt, int mtu, int status){

    System.out.println(" +++++++ MTU CHANGE SUCCESSFUL +++++++");
}

As for 'receiving serial data via notifications' I cannot help as I've been struggling to find a simple explanation as to how to do this for weeks.....

Upvotes: 0

ongebear
ongebear

Reputation: 35

UPDATE

So I now have the textView displaying the data from the bluetooth module. The problem now is that the values will not update unless the Connect method is called (I press the connect button). I suspect this is because the 20 byte limit is reached. Is there a way for me to continuously update the values without reconnecting? I'm also trying to save the values in a text file while displaying, but my text file is empty. Here is my updated code:

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void Connect(View view) throws InterruptedException {

    Device = Adapter.getRemoteDevice("3C:A3:08:94:C3:11");

    Gatt = Device.connectGatt(this, true, GattCallback);


}

private final BluetoothGattCallback GattCallback = new BluetoothGattCallback() {
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

        if (newState == BluetoothProfile.STATE_CONNECTED) {
            Gatt.discoverServices();


        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            Service = Gatt.getService(UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB"));
            Characteristic = Service.getCharacteristic(UUID.fromString("0000FFE1-0000-1000-8000-00805F9B34FB"));
            UUID uuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
            descriptor = Characteristic.getDescriptor(uuid);
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            Gatt.setCharacteristicNotification(Characteristic, true);
            Gatt.writeDescriptor(descriptor);


        }

    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {

        final String strReceived = characteristic.getStringValue(0);

        try {
            FileOutputStream fos = new FileOutputStream(myFile);
            OutputStreamWriter osw = new OutputStreamWriter(openFileOutput("Test.txt", MODE_APPEND));
            osw.write(strReceived);
            fos.flush();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        ErrorID.setText(strReceived);

    }


    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        final byte[] data = characteristic.getValue();
        if (data != null && data.length > 0) {
            final StringBuilder stringBuilder = new StringBuilder(data.length);
            for (byte byteChar : data) {
                stringBuilder.append(String.format("%02X ", byteChar));
            }


            final String strReceived = stringBuilder.toString();

            ErrorID.setText(strReceived);

        }


    }

};

Upvotes: 0

Emil
Emil

Reputation: 18517

Remove the while loop that reads the characteristic with 100% cpu usage. The setCharacteristicNotification followed by the descriptor write is all you need to prepare for the notifications.

Just implement the onCharacteristicChanged callback which will then be called upon each notification.

Upvotes: 1

Related Questions