douglasjunior / AndroidBluetoothLibrary

A Library for easy implementation of Serial Bluetooth Classic and Low Energy on Android. 💙
MIT License
224 stars 68 forks source link

Currupt data in onDataRead(byte[] buffer, int length), BLE. #5

Closed medvednic closed 7 years ago

medvednic commented 7 years ago

I'm using the latest version of your library (0.3.3 BLE version) for communication with an Arduino board, its repeatedly sends a string of data via Bluetooth LE, - {imei: 861311006131360,name: 'Bluetooth nmea',ver: 8}

Before stating the issue I want to assure you that the problem is not with my Arduino board, since I've used it with google's official android Bluetooth LE API and it worked flawlessly.

The issue I've noticed that the data passed to onDataRead event callback sometimes has missing/misplaced characters in comparison to the raw data which is logged inside onCharacteristicChanged of BluetoothLeService. I suspect that the reason is readData(byte[] data) which is called in onCharacteristicChanged.

For brevity I use StringBuilder in onDataRead callback to append and log the data from the buffer.

public void onDataRead(byte[] buffer, int length) {
                String s = new String(buffer, 0, length);
                sb.append(s);
                Log.d(TAG, sb.toString());
            }

In the attached log you can see that the displayed data differs from the raw data of the characteristic, for example: Line 25 - the IMEI value has a missing character - 86131100631360. Line 29 - IMEI is 86311006131360. Line 34 - iei instead of imei. However onCharacteristicChanged always have the proper value, received in three parts:

{imei: 8613110061313
60, name: 'Bluetooth
nmea', ver: 8}

I guess that reaData(byte[] data) does something weird. Solution - fix reaData or just return the raw characteristic from onCharacteristicChanged.

Here is the BluetoothConfiguration:

BluetoothConfiguration config = new BluetoothConfiguration();
        config.context = getApplicationContext();
        config.bluetoothServiceClass = BluetoothLeService.class;
        config.bufferSize = 23;
        config.characterDelimiter = '\n';
        config.deviceName = "Your App Name";
        config.callListenersInMainThread = false;

        config.uuidService = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
        config.uuidCharacteristic = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            config.transport = BluetoothDevice.TRANSPORT_LE;
        }
        BluetoothService.init(config);
        service = BluetoothService.getDefaultInstance();

I've tried changing the configuration: buffer size, delimiter and running of main thread but the result is always the same - missing characters in the string created from buffer of onDataRead.

douglasjunior commented 7 years ago

Is Arduino sending a line break \n at the end of the String?

If is not, the library will store the received data until it completes the Buffer size, after completing the Buffer content is dispatched by onDataRead.

In your case, I suggest Arduino sends a delimiter character at the end of the String, to indicate its end. For example, a line break {imei: 861311006131360,name: 'Bluetooth nmea',ver: 8}\n.

This way, whenever the library finds \n the content {imei: 861311006131360,name: 'Bluetooth nmea',ver: 8} will be dispatched to onDataRead.

If you choose another character instead of \n do not forget to set the library to:

config.characterDelimiter = 'your-char';
medvednic commented 7 years ago

Well, that actually solves the issue, here is a log, the received data is now consistent.

Anyway, if one doesn't specify a delimiter there is some weird unexplained behavior which results in corrupt data being sent to onDataRead?

douglasjunior commented 7 years ago

The data is not corrupted, to understand the purpose of Buffer first you need to understand how bluetooth communication works.

When you send a String (or any bytes) over bluetooth, it may not received complete on the other side, that is, it is received from pieces to pieces.

The library store these pieces and fires the onDataRead when finds the delimiter, or when complete the Buffer size.

medvednic commented 7 years ago

I understand this, but before your answer I used a small buffer size (23) and a improper delimiter (the buffer was filled because no delimiter was ever found). Once the buffer was full I got the data in onDataRead but some of the characters were in the wrong order - this behavior is problematic. As far as I understand one should receive the proper data even if the buffer is filled before the delimiter is found.

douglasjunior commented 7 years ago

Sorry, looking at the log again I think now I understand the problem.

I'll check.

douglasjunior commented 7 years ago

You could try again in this version:

dependencies {
    compile 'com.github.douglasjunior.AndroidBluetoothLibrary:BluetoothLowEnergyLibrary:issue-5-SNAPSHOT'
}
medvednic commented 7 years ago

Will check it out in the following days.

douglasjunior commented 7 years ago

@medvednic can I close this issue?