BLE onDescriptorWrite is not trigger when writeDescriptor receive true

▼魔方 西西 提交于 2020-01-25 09:22:07

问题


It's my code to enable characteristic notification.

private void enableNotification(BluetoothGattCharacteristic characteristic) {
    boolean s = bluetoothGatt.setCharacteristicNotification(characteristic, true);
    Log.d(TAG, "enableNotification: setCharacteristicNotification " + s);
    List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();
    if (null != descriptors && descriptors.size() > 0) {
        for (BluetoothGattDescriptor descriptor : descriptors) {
            Log.d(TAG, "enableNotification: " + descriptor.getUuid());
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            boolean s1 = bluetoothGatt.writeDescriptor(descriptor);
            Log.d(TAG, "enableNotification: writeDescriptor " + s1);
        }
    } else {
        Log.d(TAG, "enableNotification: descriptors is null");
    }
}

The following are the logs

BluetoothGatt: setCharacteristicNotification() - uuid: 00002a4d-0000-1000-8000-00805f9b34fb enable: true
BleService: enableNotification: setCharacteristicNotification true
BleService: enableNotification: 00002902-0000-1000-8000-00805f9b34fb
BleService: enableNotification: writeDescriptor true
BluetoothGatt: onConnectionUpdated() - Device=5C:B6:CC:00:1E:23 interval=40 latency=4 timeout=600 status=0

As we can see, writeDescriptor return true, but the onDescriptorWrite() method is not trigger, and the BluetoothGatt shows the log onConnectionUpdated(). If someone could tell why my notify have no trigger. the following is my onDescriptorWrite code in BluetoothGattCallback, if the code executed, in any case there will have some logs.

@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
    super.onDescriptorWrite(gatt, descriptor, status);
    if (status == BluetoothGatt.GATT_SUCCESS) {
        Log.d(TAG, "onDescriptorWrite: GATT_SUCCESS");
        connectCallback.readMeterId();
    } else if (status == BluetoothGatt.GATT_FAILURE) {
        Log.d(TAG, "onDescriptorWrite: GATT_FAILURE");
    } else {
        Log.d(TAG, "onDescriptorWrite: something");
    }
}

my BluetoothGattCallback code as follows

private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                bluetoothGatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                gatt.close();
                Log.d(TAG, "onConnectionStateChange: DISCONNECTED");
            } else {
                Log.d(TAG, "onConnectionStateChange: FAIL");
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //print all the service and characteristic
                for (BluetoothGattService service : bluetoothGatt.getServices()) {
                    Log.d(TAG, "onServicesDiscovered: service ->" + service.getUuid());
                    for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
                        Log.d(TAG, "onServicesDiscovered: characteristic ->" + characteristic.getUuid());
                    }
                }

                BluetoothGattService service = bluetoothGatt.getService(UUID.fromString(BleConstant.SERVICE_UUID.SERVICE));
                characteristics = service.getCharacteristics().subList(0, 2);
//                enableNotification(characteristics.get(0));
                for (BluetoothGattCharacteristic characteristic : characteristics) {
                    Log.d(TAG, "onServicesDiscovered: Properties -> " + characteristic.getUuid() + " " + characteristic.getProperties());
                    enableNotification(characteristic);
                }
            } else {
                Log.d(TAG, "onServicesDiscovered received: " + status);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            Log.d(TAG, "onCharacteristicChanged: " + Arrays.toString(characteristic.getValue()));
            Log.d(TAG, "onCharacteristicChanged: string -> " + characteristic.getStringValue(0));

            String callbackDataString = characteristic.getStringValue(0);
            byte[] callbackDataByte = characteristic.getValue();
//            boolean checkData = CRC16Util.getInstance().verification(callbackDataString);

            dosomething with the response date

            if (CRC16Util.getInstance().verification(callbackDataString)) {
                connectCallback.crcError();
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.d(TAG, "onCharacteristicRead: " + Arrays.toString(characteristic.getValue()));
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.d(TAG, "onCharacteristicWrite: " + Arrays.toString(characteristic.getValue()));
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.d(TAG, "onDescriptorWrite: GATT_SUCCESS");
                connectCallback.readMeterId();
            } else if (status == BluetoothGatt.GATT_FAILURE) {
                Log.d(TAG, "onDescriptorWrite: GATT_FAILURE");
            } else {
                Log.d(TAG, "onDescriptorWrite: something");
            }
        }
    };

in this code connectCallback is a interface like this

    public interface ConnectCallback {
        /**
         * It needs to be triggered after notify successful
         */
        void readMeterId();

        /**
         * callback of CRC ERROR
         */
        void crcError();

        /**
         * callback of Transmission completed
         */
        void onComplete();

        /**
         * callback of Read MeterId Error
         */
        void onReadMeterIdError();

    }

I only send command to ble when I onDescriptorWrite success(notify success)

The following is my connect code

    public boolean connectToDevice(final String address, ConnectCallback connectCallback) {
        if (null == bluetoothAdapter || null == address) {
            Log.d(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return false;
        }

        if (null != bluetoothGatt) {
            bluetoothGatt = null;
        }

        final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
        if (device == null) {
            Log.d(TAG, "Device not found.  Unable to connect.");
            return false;
        }
        Log.d(TAG, "Trying to create a new connection.");
        this.connectCallback = connectCallback;
        bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback);
        return true;
    }

I write all the ble code in Service and use it in an activity like this

 private void bindBleService() {
        serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                BleService.LocalBinder binder = (BleService.LocalBinder) service;
                bleService = binder.getService();

                if (!bleService.init()) {
                    Log.e(TAG, "Unable to initialize Bluetooth");
                    finish();
                }

                boolean isConn = bleService.connectToDevice(deviceAddress, new BleService.ConnectCallback() {

                    @Override
                    public void readMeterId() {
                        notifySuccess = true;
                        runOnUiThread(() -> {
                            waitBleDialog.setTitle(getString(R.string.edit_read_meter_id));
                            waitBleDialog.show();
                        });
                        bleService.sendDataToBle(READ_METER_ID.OCP);
                        meterIdUsed.put(READ_METER_ID.OCP, true);
                    }

                    @Override
                    public void crcError() {
                        if (waitBleDialog.isShowing()) {
                            waitBleDialog.cancel();
                        }
                        runOnUiThread(() -> {
                            Toast.makeText(BleResultActivity.this, getString(R.string.ble_crc_error), Toast.LENGTH_SHORT).show();
                            finish();
                        });
                    }


                    @Override
                    public void onComplete() {
                        if (recordList.size() == 0) {
                            if (waitBleDialog.isShowing()) {
                                waitBleDialog.cancel();
                            }
                            runOnUiThread(() -> Toast.makeText(BleResultActivity.this, getString(R.string.edit_no_new_record), Toast.LENGTH_SHORT).show());
                            recordTestButton.setOnClickListener(v -> runOnUiThread(() -> Toast.makeText(BleResultActivity.this, getString(R.string.edit_no_new_record), Toast.LENGTH_SHORT).show()));
                        } else {
                            runOnUiThread(() -> {
                                recordTestButton.setEnabled(true);
                                Toast.makeText(BleResultActivity.this, getString(R.string.edit_transmit_finish), Toast.LENGTH_SHORT).show();
                            });
                            recordTestButton.setOnClickListener(recordTest);
                        }
                    }


                    @Override
                    public void onReadMeterIdError() {
                        boolean haveCommendNotUsed = true;
                        for (String command : meterIdUsed.keySet()) {
                            Boolean commandUsed = meterIdUsed.get(command);
                            if (null == commandUsed) {
                                commandUsed = false;
                            }
                            if (!commandUsed) {
                                haveCommendNotUsed = true;
                                bleService.sendDataToBle(command);
                                meterIdUsed.put(command, true);
                                break;
                            } else {
                                haveCommendNotUsed = false;
                            }
                        }
                        if (!haveCommendNotUsed) {
                            waitBleDialog.cancel();
                            runOnUiThread(() -> Toast.makeText(BleResultActivity.this, getString(R.string.edit_read_meter_id_failed), Toast.LENGTH_SHORT).show());
                            finish();
                        }
                    }
                });
                if (!isConn) {
                    Log.d(TAG, "onServiceConnected: false");
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                bleService = null;
            }
        };
        final Intent intent = new Intent(this, BleService.class);
        bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);
    }

What I know now is that after run the enableNotification() method and the writeDescriptor() return true, the onConnectionUpdated() happened and I lose my connection. The onConnectionUpdated() is hide in souce code, and I don't know why it occurs and how to deal with it.


回答1:


It seems your app is not connected to your BLE device.

To know whether the connection is succesful, you need to check the given status is equal to BluetoothGatt.GATT_SUCCESS in onConnectionStateChange().

Also, check for possible GATT_CONN_TIMEOUT:

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

     super.onConnectionStateChange(gatt, status, newState);

     if ((newState == BluetoothProfile.STATE_CONNECTED) && (status == BluetoothGatt.GATT_SUCCESS)) {
           bluetoothGatt.discoverServices();
     } else if ((newState == BluetoothProfile.STATE_DISCONNECTED) && (status == BluetoothGatt.GATT_SUCCESS)) {
           gatt.close();
           Log.d(TAG, "onConnectionStateChange: DISCONNECTED");
     } else if (status == GATT_CONN_TIMEOUT) {
           Log.e(TAG, "GATT_CONN_TIMEOUT !");  
     } else {
           Log.e(TAG, "onConnectionStateChange: FAIL");
     }
}


来源:https://stackoverflow.com/questions/58555820/ble-ondescriptorwrite-is-not-trigger-when-writedescriptor-receive-true

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!