Fabian Schneider
Fabian Schneider

Reputation: 809

Cannot write to BLE GattCharacteristic

I am trying to connect to a BLE device and then stay connected to it (as I have to write to a characteristic approx 1 time per second. Although I can successfully connect to the device as evidenced by being able to see this log System.out.println("dev connected..");, I get an exception whenever I call send message. The exception tells me that finalGatt is a null object reference. (See code and error below).

public class BluetoothLeService2 extends Service {
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothLeScanner mLEScanner;
    private ScanSettings settings;
    private List<ScanFilter> filters;
    private BluetoothGatt mGatt;
    private BluetoothGatt finalGatt;
    private Application app;

    final BluetoothManager bluetoothManager;

    BluetoothLeService2(Application app) throws NullPointerException {
        this.app = app;
        bluetoothManager =
                (BluetoothManager) app.getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();


        mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
        settings = new ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                .build();
        filters = new ArrayList<>();
        scanLeDevice(true);
    }



    private void scanLeDevice(final boolean enable) {
        if (enable) {
                mLEScanner.startScan(filters, settings, mScanCallback);
        } else {
                mLEScanner.stopScan(mScanCallback);
        }
    }


    private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            BluetoothDevice btDevice = result.getDevice();
            try {
                if(btDevice.getAddress().equals("mac")){
                    connectToDevice(btDevice);
                    scanLeDevice(false);
                }
            } catch (NullPointerException e) {
                //NULL
            }
        }

    };



    private void connectToDevice(final BluetoothDevice device) {
        new Thread(new Runnable() {
            public void run() {
                while(true) {              //keep device connected
                    if (mGatt == null) {
                        mGatt = device.connectGatt(app, true, gattCallback);
                        scanLeDevice(false);
                    }

                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }


    public void sendMessage() {
            try {
                List<BluetoothGattService> bgsList = finalGatt.getServices();
                BluetoothGattService mSVC = bgsList.get(3);
                List<BluetoothGattCharacteristic> bgcList = mSVC.getCharacteristics();
                BluetoothGattCharacteristic mCH = bgcList.get(0);
                mCH.setValue(Base64.decode("sth".getBytes(), Base64.URL_SAFE));
                if (bluetoothManager.getConnectionState(finalGatt.getDevice(), BluetoothGatt.GATT) == 0) {
                    connectToDevice(finalGatt.getDevice());
                    return;
                }
            } catch (Exception e) {
                Log.wtf("connection", "dev not connected");
            }
        }
    }

    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            switch (newState) {
                case BluetoothProfile.STATE_CONNECTED:                        
                    if(gatt.getDevice().getAddress().equals("mac")) {
                        gatt.discoverServices();
                    }
            }

        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            List<BluetoothGattService> services = gatt.getServices();
            if (status == BluetoothGatt.GATT_SUCCESS) {
               if(gatt.getDevice().getAddress().equals("mac")){
                    finalGatt = gatt;
                    connectToDevice(finalGatt.getDevice());
                    System.out.println("dev connected..");
                    scanLeDevice(false);
                }
            }
        }

    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

The exception:

Attempt to invoke virtual method 'java.util.List android.bluetooth.BluetoothGatt.getServices()' on a null object reference
  java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List android.bluetooth.BluetoothGatt.getServices()' on a null object reference
      at com.faebl.BluetoothLeService2.sendMessage(BluetoothLeService2.java:135)
      at com.faebl.Activator.execute(Activator.java:56)
      at com.faebl.Activator.doInBackground(Activator.java:42)
      at android.os.AsyncTask$2.call(AsyncTask.java:295)
      at java.util.concurrent.FutureTask.run(FutureTask.java:237)
      at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
      at java.lang.Thread.run(Thread.java:818)

I execute it like this from another class:

bles = new BluetoothLeService2(app);
bles.sendMessage();

Where am I going wrong? Maybe I have to do it another way?

Thank you for your help.

Upvotes: 2

Views: 415

Answers (1)

Jakub Licznerski
Jakub Licznerski

Reputation: 1088

You didn't show when and how do you call sendMessage in which the exception is thrown. Most probably you do it before onServicesDiscovered is called because only there finalGatt value is set.

Upvotes: 3

Related Questions