1

I'm trying to send "continuous" notifications from a Nordic nRF52840 (peripheral) to a Samsung S8 (central) running Android 9. I request an MTU of 247 and a Phy of 2MBPS. The characteristics being sent are 244 bytes in size and include a sequence number. Right now, I have a test loop in the peripheral that sends 1 notification every 15ms (I'd like to get it to one every 7.5ms eventually). But first, I'd like to get the notifications transmitted/received correctly! (By the way, things work well if I only send notifications every 30 ms, so this appears to be notification transmission rate dependent.)

I set up a BLEManager as a service, and the connection from the peripheral to the central is made, the notification is subscribed, and a command is sent from the central to the peripheral to start sending sensor data. I'm using the "stock" Android BLE library in the central.

The stream of characteristics starts, with sequence numbers 0, 1, 2, and 3, but then it appears that packet 6 arrives 3 times. (in place of 4, 5, and 6). The next characteristic reported is 0x000a, so sequence numbers 7, 8, and 9 appear to have been lost.

Originally, when a characteristic was received, I passed it to the MainActivity via "broadcastUpdate", but I thought perhaps there was too much overhead doing this, so I moved the test code that reports the notifications directly into the "OnCharacteristicChanged" callback:

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
        Timber.d("onCharacteristicChanged: ");
        Timber.d("  characteristic UUID: %s", characteristic.getUuid().toString());


        //broadcastUpdate(ACTION_GATT_DATA_READY, characteristic);

        final byte[] data = characteristic.getValue();
        ByteBuffer buf = ByteBuffer.wrap(data);
        buf.order(ByteOrder.LITTLE_ENDIAN);

        if (characteristic.getUuid().toString().equals(MIC_DATA_UUID)) {
            Timber.d("Data received from Microphone: %d", data.length);

            buf.asShortBuffer().get(micData, micWriteIndex, MIC_SAMPLES_PER_PACKET);

            // Service the rotating buffer write pointer
            micWriteIndex = micWriteIndex + MIC_SAMPLES_PER_PACKET;
            if (micWriteIndex >= MIC_BUFFER_SIZE) micWriteIndex = 0;
            // Read the sequence number...
            // buf pointer is still at the beginning, so
            // index of NNN skips over data we just read.
            micSeqNum = buf.getShort(MIC_SAMPLES_PER_PACKET * MIC_SAMPLE_SIZE_IN_BYTES);
            micChkSum = buf.getShort();
            Timber.d("    Mic seq: %04x  Mic chk: %04x", micSeqNum, micChkSum);

        }
    }

Here is a portion of the log that is produced:

> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 0000  Mic chk: 0000
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 0001  Mic chk: 0078
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 0002  Mic chk: 00f0
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 0003  Mic chk: 0168
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 0006  Mic chk: 02d0
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 0006  Mic chk: 02d0
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 0006  Mic chk: 02d0
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 000a  Mic chk: 04b0
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 000b  Mic chk: 0528
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 000b  Mic chk: 0528
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 000b  Mic chk: 0528
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 000e  Mic chk: 0690
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 000e  Mic chk: 0690
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 000e  Mic chk: 0690
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 000e  Mic chk: 0690
> D/BLEManager: onCharacteristicChanged:  D/BLEManager:   characteristic
> UUID: f000af03-0807-0605-0403-020100000000 D/BLEManager: Data received
> from Microphone: 244 D/BLEManager:     Mic seq: 0012  Mic chk: 0870

When notifications arrive "quickly" is there some special consideration that needs to be taken to insure "notification 1" is processed before "notification 2" is handled? Is there a "synchronized" construct that can be used to ensure that characteristics don't overwrite one another? Is there a way to tell the BLE manager to queue the incoming notifications?

Thanks!

1 Answers1

0

Since the BLE library internally uses aidl and "Binder", it's guaranteed that only one callback is run at a time for every BluetoothGatt object. Even if you insert a sleep inside onCharacteristicChanged you will not get another callback until the previous one has returned. If you call getValue on the characteristic before returning, you do it the correct way.

Your code looks ok. Make sure the code is correct on the peripheral side. To be 100% sure on which side the issue lies, use a BLE air sniffer or simply look at the hci log in Android.

Emil
  • 16,784
  • 2
  • 41
  • 52
  • Thanks for the response. I don't currently have access to an air sniffer, but do have the debug log from the nRF52840 device (peripheral) and the hci log from the Android app (central). The debug log shows all of the notifications (packets) being sent to the appropriate nRF BLE function, in order, with no error being reported. The hci log, as viewed in WireShark, shows the packet duplication/dropping (as it is later reported in the log above). I'll see if I can get access to an air sniffer... Of course, the Android library makes use of the Samsung BLE implementation... – ckt-designer Jul 08 '20 at 14:41
  • If the hci log shows duplicated / dropped packets then you must have a bug in your peripheral code. Maybe you look at the wrong place in your peripheral code. – Emil Jul 08 '20 at 16:57