Hossein Kurd
Hossein Kurd

Reputation: 4555

BLE Data lost on reading characteristic when the device sends data frequently

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

Answers (2)

Hossein Kurd
Hossein Kurd

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

Emil
Emil

Reputation: 18452

  1. First make sure you never have more than one outstanding GATT request at a time. See Android BLE BluetoothGatt.writeDescriptor() return sometimes false.

  2. When you get the onCharacteristicChanged, you can use getValue directly on the characteristic object to get the notified value.

  3. After you call readCharacteristic, you need to wait for onCharacteristicRead before you can call getValue.

Upvotes: 1

Related Questions