Reputation: 4555
Android BLE Data lost on reading characteristic when the device sends data frequently.
Byte Array converts from Big endian
Every 4 bytes Make One
Cell I should convert to decimal
Here is my code:
device.connectGatt(context, true, new BluetoothGattCallback() {
//region onServicesDiscovered
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
Log.d(TAG, "onServicesDiscovered --> Status : " + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService mBluetoothGattService = mBluetoothGatt.getService(convertUuidFromInteger(0x181D));
if (mBluetoothGattService == null) {
Log.e(TAG, "onServicesDiscovered --> Service characteristic not found for UUID : " + SERVICE_UUID);
return;
}
Log.d(TAG, "onServicesDiscovered --> Service characteristic UUID found : " + mBluetoothGattService.getUuid().toString());
// read the characteristic from the service
BluetoothGattCharacteristic mBluetoothGattCharacteristic = mBluetoothGattService.getCharacteristic(CHARACTERISTIC_UUID);
boolean bcn = mBluetoothGatt.setCharacteristicNotification(mBluetoothGattCharacteristic, true);
Log.d(TAG, "onServicesDiscovered --> Is Characteristic Notification setted : " + bcn);
BluetoothGattDescriptor descriptor = mBluetoothGattCharacteristic.getDescriptor(DESCRIPTOR_UUID);
Log.w(TAG, "onServicesDiscovered --> Descriptor : " + (descriptor != null));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
boolean readDescriptor = mBluetoothGatt.readDescriptor(descriptor);
Log.e(TAG, "onServicesDiscovered --> Succeed to read descriptor : " + readDescriptor);
}
}
//endregion onServicesDiscovered
//region onDescriptorWrite
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.w(TAG, "onDescriptorWrite --> ******************************");
if (DESCRIPTOR_UUID.equals(descriptor.getUuid())) {
Log.d(TAG, "onDescriptorWrite --> Equals");
BluetoothGattCharacteristic characteristic = gatt
.getService(SERVICE_UUID)
.getCharacteristic(CHARACTERISTIC_UUID);
boolean characteristicRead = gatt.readCharacteristic(characteristic);
Log.d(TAG, "onDescriptorWrite --> Characteristic read : " + characteristicRead);
boolean characteristWrite = gatt.writeCharacteristic(characteristic);
Log.d(TAG, "onDescriptorWrite --> Characteristic write : " + characteristWrite);
}
}
//endregion onDescriptorWrite
//region onDescriptorRead
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
Log.w(TAG, "onDescriptorRead --> ******************************");
if (DESCRIPTOR_UUID.equals(descriptor.getUuid())) {
Log.d(TAG, "onDescriptorRead --> Equals");
BluetoothGattCharacteristic characteristic = gatt
.getService(SERVICE_UUID)
.getCharacteristic(CHARACTERISTIC_UUID);
boolean characteristicRead = gatt.readCharacteristic(characteristic);
Log.d(TAG, "onDescriptorRead --> Characteristic read : " + characteristicRead);
boolean characteristWrite = gatt.writeCharacteristic(characteristic);
Log.d(TAG, "onDescriptorRead --> Characteristic write : " + characteristWrite);
}
}
//endregion onDescriptorRead
//region onCharacteristicChanged
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
Log.w(TAG, "onCharacteristicRead ******************************");
readCharacteristic(gatt, characteristic);
}
//endregion onDescriptorRead
//region onCharacteristicRead
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.w(TAG, "onCharacteristicRead ******************************");
readCharacteristic(gatt, characteristic);
}
//endregion onCharacteristicRead
//region onCharacteristicWrite
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.w(TAG, "onCharacteristicWrite ******************************");
readCharacteristic(gatt, characteristic);
}
//endregion onCharacteristicWrite
//region onConnectionStateChange
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothGatt.STATE_CONNECTED) {
Log.d(TAG, "onConnectionStateChange CONNECTED.");
boolean isDiscoverable = gatt.discoverServices(); // Essential to declare right Here
Log.w(TAG, "onConnectionStateChange --> Discover Services : " + isDiscoverable);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
gatt.requestMtu(512);
}
}
mBluetoothGatt = gatt;
Log.d(TAG, "onConnectionStateChange --> discoverServices Size : " + mBluetoothGatt.getServices().size());
for (BluetoothGattService s : mBluetoothGatt.getServices()) {
Log.d(TAG, "onConnectionStateChange --> discoverServices : found " + s.getUuid());
for (BluetoothGattCharacteristic c : s.getCharacteristics()) {
Log.d(TAG, "onConnectionStateChange --> characteristic : " + c.getUuid() + ":" + String.format("%x", c.getInstanceId()));
}
}
super.onConnectionStateChange(gatt, status, newState);
Log.d(TAG, "onConnectionStateChange connectGatt.");
// readCustomCharacteristic(mBluetoothAdapter, mBluetoothGatt);
}
//endregion onConnectionStateChange
private void readCharacteristic(@NonNull BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.i("RawData", Arrays.toString(characteristic.getValue()));
Log.w(TAG, "readCharacteristic --> ******************************");
if (!gatt.readCharacteristic(characteristic)) {
Log.w(TAG, "readCharacteristic --> Failed to read characteristic");
return;
}
byte[] value = characteristic.getValue();
// Log.i(TAG, "readCharacteristic --> Succeed to read characteristic");
if (characteristic.getValue() == null || characteristic.getValue().length < 68) {
Log.e(TAG, "readCharacteristic --> Characteristic Bytes null / Bytes < 68");
return;
}
prepareToWrite(context, characteristic.getValue());
}
private void prepareToWrite(@NonNull Context context, @NonNull byte[] value) {
StringBuilder strRow = new StringBuilder();
strRow.append(context.getString(R.string.timestump_line_prefix))
.append(System.currentTimeMillis());
for (int i = 0; i < value.length; i += 4) {
// Log.i(TAG, "prepareToWrite index #" + i);
// Log.w(TAG, "prepareToWrite Step #" + 0);
byte[] b1 = {value[i + 3],
value[i + 2],
value[i + 1],
value[i]};
if (i % 16 / 4 == 0) {
strRow.append("\n");
} else {
strRow.append(" ");
}
if (i == 64) {
Log.w(TAG, "prepareToWrite --> Hex : " + toHexString(b1) + " , Decimal : " + Long.parseLong(toHexString(b1), 16));
}
strRow.append(context.getString(R.string.counter_line_prefix));
String strLong = String.valueOf(Long.parseLong(toHexString(b1), 16));
strRow.append(strLong);
Log.w(TAG, "prepareToWrite --> Here I am : " + strLong);
}
strRow.append("\n")
.append(context.getString(R.string.new_line));
Log.w(TAG, "prepareToWrite --> Row : " + strRow.toString());
try {
/*PackageManager m = context.getPackageManager();
PackageInfo p = m.getPackageInfo(context.getPackageName(), 0);
String dataDir = p.applicationInfo.dataDir;*/
/*String dataDir = context.getApplicationInfo().dataDir;*/
String dataDir = Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + "Android" + File.separator + "data" + File.separator + context.getPackageName();
// Log.d(TAG, "prepareToWrite --> Create File 'Data Dir' : " + new File(dataDir).mkdirs() + " : " + dataDir);
// Log.w(TAG, "prepareToWrite Data Dir : " + dataDir);
File storeDir = new File(dataDir + File.separator + "files" + File.separator + context.getString(R.string.store_dir_name));
// Log.d(TAG, "prepareToWrite --> Create File 'Store Dir' : " + storeDir.mkdirs());
// storeDir.mkdirs();
File destinationFile = new File(storeDir.getAbsolutePath(), "Force_Plate.txt");
if (!destinationFile.exists() || destinationFile.isDirectory()) {
if (destinationFile.createNewFile()) {
// Log.w(TAG, "prepareToWrite --> Create File Succeed : " + destinationFile.getAbsolutePath());
} else {
// Log.w(TAG, "prepareToWrite --> Create File Failed : " + destinationFile.getAbsolutePath());
}
}
// Log.i(TAG, "prepareToWrite readFromFile : " + readFromFile(context, destinationFile.getAbsolutePath()));
writeToFile(destinationFile, strRow.toString());
}/* catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "prepareToWrite --> PackageManager NameNotFoundException : " + e.getMessage(), e);
} */ catch (IOException e) {
Log.e(TAG, "prepareToWrite --> IOException : " + e.getMessage(), e);
}
}
});
LogCat shows :
W: prepareToWrite --> Hex : 00000b7e , Decimal : 2942
W: prepareToWrite --> Hex : 00000b87 , Decimal : 2951
W: prepareToWrite --> Hex : 00000b90 , Decimal : 2960
W: prepareToWrite --> Hex : 00000b97 , Decimal : 2967
W: prepareToWrite --> Hex : 00000b9e , Decimal : 2974
...
It should be like :
W: prepareToWrite --> Hex : 00000b7e , Decimal : 2942
W: prepareToWrite --> Hex : 00000b7e , Decimal : 2943
W: prepareToWrite --> Hex : 00000b7e , Decimal : 2944
W: prepareToWrite --> Hex : 00000b7e , Decimal : 2945
...
Upvotes: 0
Views: 1205
Reputation: 4555
Declared those lines before device.connectGatt()
AdvertiseSettings advertiseSettings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
.setConnectable(true)
.setTimeout(0)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
.build();
AdvertiseData advertiseData = new AdvertiseData.Builder()
.setIncludeDeviceName(true)
.setIncludeTxPowerLevel(false)
.addServiceUuid(new ParcelUuid(FP_SERVICE_UUID))
.build();
mBluetoothAdapter.getBluetoothLeAdvertiser().startAdvertising(advertiseSettings, advertiseData, new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
// Log.d(TAG, "BluetoothLeAdvertiser, onStartSuccess --> $isConnectable : " + settingsInEffect.isConnectable());
}
@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
// Log.d(TAG, "BluetoothLeAdvertiser, onStartSuccess --> errorCode : " + errorCode);
}
});
...
Upvotes: 0
Reputation: 18452
First make sure you never have more than one outstanding GATT request at a time. See Android BLE BluetoothGatt.writeDescriptor() return sometimes false.
When you get the onCharacteristicChanged, you can use getValue directly on the characteristic object to get the notified value.
After you call readCharacteristic, you need to wait for onCharacteristicRead before you can call getValue.
Upvotes: 1