Nephilim
Nephilim

Reputation: 524

Write characteristic always false

Now I know this question has been asked about a billion times.

I've read through most of them(this website hasn't been that helpful for my problem), I've read through the docs and I've read through the examples and tutorials.

What I'm trying to do is:

Send hello world to a BLE device(Connected to an arduino)

What I've done so far:

Paired with the device using the inbuilt settings(no programmed logic in my app)

Connected with the device using the GATT server.

However when I try to write a characteristic, the corresponding status return boolean is always false. This is the most relevant code:

private void setupServer(BluetoothAdapter bAdapter) {
    Log.d(TAG, "Started setting up server");

    BluetoothLeAdvertiser bAdvertiser = bAdapter.getBluetoothLeAdvertiser();
    if (bAdapter != null) {
        bGattServer = bManager.openGattServer(getApplicationContext(), new BluetoothGattServerCallback() {
            @Override
            public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
                super.onConnectionStateChange(device, status, newState);
            }
        });
        //Create a service using a random UUID
        //Create characteristics with WRITE property and write a value
        BluetoothGattService service = new BluetoothGattService(UUID.randomUUID(), BluetoothGattService.SERVICE_TYPE_PRIMARY);
        BluetoothGattCharacteristic bluetoothGattCharacteristic = new BluetoothGattCharacteristic(bUUID, BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE);
        Log.d(TAG, "Adding characteristic to service " + service.addCharacteristic(bluetoothGattCharacteristic));
        bluetoothGattCharacteristic.setValue("hello");
        Log.d(TAG, "Trying to write characteristic..., first value: " + bluetoothGattCharacteristic.getValue()[0]);
        if (bGatt != null) {
            boolean success = bGatt.writeCharacteristic(bluetoothGattCharacteristic);
            if (success) {
                Log.d(TAG, "Successfuly wrote characteristic to" + bUUID);
            } else {
                 //THIS ALWAYS EXECUTES??
                Log.e(TAG, "Failed to write to characteristic");
            }
        } else {
            Log.e(TAG, "BGATT IS NULL");
        }
        service.addCharacteristic(bluetoothGattCharacteristic);
        bGatt.setCharacteristicNotification(bluetoothGattCharacteristic, true);
        bGattServer.addService(service);
    }

These are my permissions:

    <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

And this is the rest of the relevant code

    private boolean scanBluetooth(final BluetoothAdapter bAdapter, final BluetoothDevice[] bDevice) {

    final BluetoothLeScanner bScanner = bAdapter.getBluetoothLeScanner();
    final boolean[] stopCallback = {false};
    Log.d(TAG,"Started scanning");
    bScanner.startScan(new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            bDevice[0] = result.getDevice();
            if (bDevice[0] == null || stopCallback[0]) {
                Toast.makeText(getApplicationContext(), "Didn't find a device", Toast.LENGTH_LONG);

            } else {
                stopCallback[0] = true;
                System.out.println("DEVICE" + bDevice[0]);
                bGatt = bDevice[0].connectGatt(getApplicationContext(), true, new BluetoothGattCallback() {
                    @Override
                    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                        super.onConnectionStateChange(gatt, status, newState);
                        if(status == BluetoothGatt.GATT_SUCCESS){
                            Log.d(TAG, "Successful GATT " + newState);
                            setupServer(bAdapter);
                            return;
                        }
                        if(status == BluetoothGatt.GATT_FAILURE){
                            Log.e(TAG,"Bigg error boi");
                            System.exit(1);
                        }
                        else{
                            Log.w(TAG,"Oh no, gatt failed " + status + " retrying");
                            return;
                        }

                    }
                    @Override
                    public void onCharacteristicWrite(BluetoothGatt gatt,
                                                      BluetoothGattCharacteristic characteristic, int status) {
                        Log.d(TAG, "Characteristic written" + status);
                    }

                }, BluetoothDevice.TRANSPORT_LE);
                Log.d(TAG, "Bgatt value:" + bGatt);


            }
        }
    });
    if(bGatt==null){
        Log.w(TAG, "BGATT IS NULL WHILE SCANNING");
    }
    Log.d(TAG, "Finished scanning...");
    return true;
}

I've gotten bUUID using the app BLEScanner, which showed a UUID for read and write. The goal of my application is to mirror the functionality of that app, but I'm starting to lose my mind. I can't even send a simple hello world yet.

Android Studio output:

018-12-01 23:58:56.214 25024-25136/com.iopt.davidv7.iopt W/DBG: Oh no, gatt failed 22 retrying
2018-12-01 23:58:56.675 25024-25136/com.iopt.davidv7.iopt D/DBG: Successful GATT 2
2018-12-01 23:58:56.675 25024-25136/com.iopt.davidv7.iopt D/DBG: Started setting up server
2018-12-01 23:58:56.692 25024-25136/com.iopt.davidv7.iopt D/DBG: Adding characteristic to service true
2018-12-01 23:58:56.693 25024-25136/com.iopt.davidv7.iopt D/DBG: Trying to write characteristic..., first value: 104
2018-12-01 23:58:56.693 25024-25136/com.iopt.davidv7.iopt E/DBG: Failed to write to characteristic

The client is a simple HM-10 Bluetooth module and I want to mirror what I send in the app on the serial monitor using ARDUINO IDE for now.

I hope I've given you all the context, because I'm losing hope. I'm not manually checking for permissions because I've set them up using the system dialogue, however, there was only "location" to enable? Could this be the root of my issue? Checking with checkSelfPermission for bluetooth, bluetooth admin returns true though, so I dont think that is it:

        if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_ADMIN)
            != PackageManager.PERMISSION_GRANTED) {
        Log.e(TAG,"No permission for bluetooth");
        // Permission is not granted
    }
    else{
        Log.d(TAG,"Bluetooth permission granted");
    }

Upvotes: 2

Views: 2327

Answers (1)

Nephilim
Nephilim

Reputation: 524

Seems my issue was in creating a new service, instead of using discover services then parsing the discovered services. So what you do,algorithmically is: 1. Trigger discoverServices(), which in turn triggers onServicesDiscovered() in the callback 2. After that, create a service out of the discovered service and a characteristic out of the service. Because my current hardware only supports one characteristic, I can only take out the first(and only) service. 3. Set value to the service with setValue 4. Add characteristic to the service

I won't be explaining what my readData code does in depth, but it might help someone figure out how to trigger notifications and read data from those.

private boolean scanBluetooth(final BluetoothAdapter bAdapter, final BluetoothDevice[] bDevice) {

    final BluetoothLeScanner bScanner = bAdapter.getBluetoothLeScanner();
    final boolean[] stopCallback = {false};
    Log.d(TAG,"Started scanning");
    bScanner.startScan(new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            bDevice[0] = result.getDevice();
            if (bDevice[0] == null || stopCallback[0]) {
                Toast.makeText(getApplicationContext(), "Didn't find a device", Toast.LENGTH_LONG);

            } else {
                stopCallback[0] = true;
                System.out.println("DEVICE" + bDevice[0]);
                bGatt = bDevice[0].connectGatt(getApplicationContext(), true, new BluetoothGattCallback() {
                    @Override
                    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                        super.onConnectionStateChange(gatt, status, newState);
                        if(status == BluetoothGatt.GATT_SUCCESS){
                            Log.d(TAG, "Successful GATT " + newState);
                            //Simply triggers a discoverService method, which in return triggers onServiceDiscovered, which writes sample data into the characteristic
                            setupClient(bAdapter);
                            return;

                        }
                        if(status == BluetoothGatt.GATT_FAILURE){
                            Log.e(TAG,"Bigg error boi");
                            System.exit(1);
                        }
                        else{
                            Log.w(TAG,"Oh no, gatt failed " + status + " retrying");
                            return;
                        }

                    }
                    @Override
                    //Triggered after we write data in a characteristic
                    public void onCharacteristicWrite(BluetoothGatt gatt,
                                                      BluetoothGattCharacteristic characteristic, int status) {
                        Log.d(TAG, "Characteristic written" + status);
                    }
                    //Triggered when someone(the remote device if everything is set up correctly) changes a characteristic!

                    public void onCharacteristicChanged(BluetoothGatt gatt,
                                                        BluetoothGattCharacteristic characteristic) {
                        Log.w(TAG,"Characteristic changed");
                        try {
                            Log.d(TAG,"Change characteristic" + new String(characteristic.getValue(),"UTF-8"));
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    }
                    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                        Log.d(TAG,"Size of discovered" + gatt.getServices().size());
                        getData(gatt);
                        writeCharacteristic(gatt);
                        Log.d(TAG,"Services discovered");
                    }


                }, BluetoothDevice.TRANSPORT_LE);
                Log.d(TAG, "Bgatt value:" + bGatt);


            }
        }
    });
    if(bGatt==null){
        Log.w(TAG, "BGATT IS NULL WHILE SCANNING");
    }
    Log.d(TAG, "Finished scanning...");
    return true;
}
//Doesn't do much, starts discovering services, which triggers onServicesDiscovered
private void setupClient(BluetoothAdapter bAdapter) {
    Log.d(TAG, "Started setting up server");

    if (bAdapter != null) {
        Log.d(TAG, "SERVICE DISCOVERED" + bGatt.discoverServices());

    }
}
//Write characteristic into the discovered service
//There is only one characteristic, so we can just take the first index
private void writeCharacteristic(BluetoothGatt gatt){
                                BluetoothGattService bService = gatt.getService(bUUID);
                        BluetoothGattCharacteristic bChars = bService.getCharacteristics().get(0);

                        if(bChars != null){
                            bChars.setValue("Hello");
                            bService.addCharacteristic(bChars);
                            boolean success = gatt.writeCharacteristic(bChars);
                            if(success){
                                Log.d(TAG, "Write characteristic successful");
                            }
                            else{
                                Log.e(TAG, "Write characteristic failed");
                            }
                        }
                        else{
                            Log.e(TAG,"Characteristic not found");
                        }
}
//Set up notifications for the discovered service!
    private void getData(BluetoothGatt gatt){

        BluetoothGattService bService = gatt.getService(bUUID);
        BluetoothGattCharacteristic bChars = bService.getCharacteristics().get(0);
        gatt.setCharacteristicNotification(bChars,true);
    }

Upvotes: 1

Related Questions