设备频繁发送数据时 BLE Data lost on reading 特性

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

Android BLE Data lost on reading 特性当设备频繁发送数据时。

字节数组从大端转换

每 4 个字节生成 One 个单元格,我应该将其转换为 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 显示:

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

...

应该是这样的:

W: prepareToWrite --> Hex : 00000b7e , Decimal : 2942

W: prepareToWrite --> Hex : 00000b7e , Decimal : 2943

W: prepareToWrite --> Hex : 00000b7e , Decimal : 2944

W: prepareToWrite --> Hex : 00000b7e , Decimal : 2945

...

  1. 首先确保您一次不会有超过一个未完成的 GATT 请求。见 .

  2. 在获取onCharacteristicChanged时,可以直接在特征对象上使用getValue获取通知值

  3. 调用readCharacteristic后,需要等待onCharacteristicRead才能调用getValue

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);
        }
    });
...