4

I'm building an app with Android Studio that can read the value from a device BLE. This device, have 4 services. The fourth services have 3 characteristic. I want to read the all characteristic of this fourth service.

This device, can send more information, so I want that the application can storage the all information that arrive from device BLE.

So this is my code:

@TargetApi(21)
public class BLEActivity extends BaseActivity {

    private BluetoothAdapter mBluetoothAdapter;
    private int REQUEST_ENABLE_BT = 1;
    private Handler mHandler;
    private static final long SCAN_PERIOD = 10000;
    private BluetoothLeScanner mLEScanner;
    private ScanSettings settings;
    private List<ScanFilter> filters;
    private BluetoothGatt mGatt;
    String mCurrentService;
    TextView tvBLE;
    ImageButton ibDownload;
    BluetoothDevice currDevice;
    private int id = 1000;
    public SensorDataAdapter adapter;
    final BLEActivity classe = this;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ble);
        mHandler = new Handler();

        //mSensors = db.getAllSensorTypes();
        //BLUETOOTH LOW ENERGY NON SUPPORTATO
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this, "BLE Not Supported",
                    Toast.LENGTH_SHORT).show();
            finish();
        }
        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
        //VERIFICO SE IL BLUETOOTH DEL DISPOSITIVO E' ABILITATO
        //OPPURE NO. SE NON è ABILITATO DEVO CHIEDERE ALL'UTENTE DI ATTIVARLO
        // Ensures Bluetooth is available on the device and it is enabled. If not,
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        ibDownload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(currDevice!=null){
                    mGatt = currDevice.connectGatt(getBaseContext(), false, gattCallback);
                    scanLeDevice(false);// will stop after first device detection
                }
            }
        });
    }

    private void scanLeDevice(final boolean enable) {
        if (enable) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (Build.VERSION.SDK_INT < 21) {
                        mBluetoothAdapter.stopLeScan(mLeScanCallback);
                    } else {
                        mLEScanner.stopScan(mScanCallback);

                    }
                }
            }, SCAN_PERIOD);
            if (Build.VERSION.SDK_INT < 21) {
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            } else {
                mLEScanner.startScan(filters, settings, mScanCallback);
            }
        } else {
            if (Build.VERSION.SDK_INT < 21) {
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            } else {
                mLEScanner.stopScan(mScanCallback);
            }
        }
    }


    private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            Log.i("callbackType", String.valueOf(callbackType));
            Log.i("result", result.toString());
            BluetoothDevice btDevice = result.getDevice();
            connectToDevice(btDevice);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            for (ScanResult sr : results) {
                Log.i("ScanResult - Results", sr.toString());
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
            Log.e("Scan Failed", "Error Code: " + errorCode);
        }
    };

    private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi,
                                     byte[] scanRecord) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Log.i("onLeScan", device.toString());
                            connectToDevice(device);
                        }
                    });
                }
            };

    public void connectToDevice(BluetoothDevice device) {
        if (mGatt == null) {
            currDevice = device;
            ibDownload.setEnabled(true);
            ibDownload.setImageResource(R.drawable.download_ok);
        }
    }

    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            Log.i("onConnectionStateChange", "Status: " + status);
            switch (newState) {
                case BluetoothProfile.STATE_CONNECTED:
                    Log.i("gattCallback", "STATE_CONNECTED");
                    gatt.discoverServices();
                    break;
                case BluetoothProfile.STATE_DISCONNECTED:
                    Log.e("gattCallback", "STATE_DISCONNECTED");
                    break;
                default:
                    Log.e("gattCallback", "STATE_OTHER");
            }
        }

     @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            List<BluetoothGattService> services = gatt.getServices();
            Log.i("onServicesDiscovered", services.toString());
            ;
            for(BluetoothGattService srv : services){
               // if(srv.getUuid().toString().equals(mSensors.get(1).getServUid())){
                    mCurrentService = srv.getUuid().toString();
                    //RECUPERO SOLO IL SERVIZIO CON UID 1130
                if(mCurrentService.contains("1130")){
                    List<BluetoothGattCharacteristic> mListCars = srv.getCharacteristics();
                    //leggo le caratteristiche del servizio che cerco
                    for(BluetoothGattCharacteristic bc : mListCars){
                        //recupero solo le caratteristiche 1131, 1132
                        if(bc.getUuid().toString().contains("1131") ||
                                bc.getUuid().toString().contains("1132")){
                            //LEGGO LE 2 CARATTERISTICHE NECESSARIE
                           gatt.readCharacteristic(srv.getCharacteristic(bc.getUuid()));
                        }

                    }
                }else{
                    Log.i("SERVIZIO NON CORRETTO", "SERVIZIO NON CORRETTO");
                }

              //  }
            }


        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic
                                                 characteristic, int status) {
            Log.i("onCharacteristicRead", characteristic.toString());

               SensorData mSenData = new SensorData();
                    mSenData.setValue(characteristic.getStringValue(0));
                    Log.i("LETTURA DATI ", mSenData.getValue());
                    mSenData.setIdType(++id);
                    mSenData.setCharacteristic(characteristic.getUuid().toString());
                    mSenData.setValueTimestamp(db.getDateTime());
                    db.insertSensorData(mSenData);


        }




    };
}

with this code, I can read one the first characteristic of my service and only one value of the first characteristic.

I want to read all value of all characteristic automatically of my BLE device. How can I change my code to do this ?

bircastri
  • 2,169
  • 13
  • 50
  • 119

3 Answers3

3

You can achive multiple reads with the following code: First create a List

private int ReadQueueIndex;
private List<BluetoothGattCharacteristic> ReadQueue;

In onServicesDiscovered add characteristics in ReadQueue:

ReadQueue = new ArrayList<>();
ReadQueue.add(characteristicsList.get(2));        
ReadQueue.add(characteristicsList.get(1));            
ReadQueue.add(characteristicsList.get(0));
ReadQueueIndex = 2;
ReadCharacteristics(ReadQueueIndex);

Create ReadCharacteristics method

private void ReadCharacteristics(int index){
   bluetoothGatt.readCharacteristic(ReadQueue.get(index));
}

Then in your onCharacteristicRead callback:

String value =  Arrays.toString(characteristic.getValue());
if(characteristic.getUuid().equals(characteristicsList.get(0).getUuid())){
  Log.i("Characteristic 0:", value);
} else if(characteristic.getUuid().equals(characteristicsList.get(1).getUuid())){
  Log.i("Characteristic 1:", value);
} else if(characteristic.getUuid().equals(characteristicsList.get(2).getUuid())){
  Log.i("Characteristic 2:", value);
}
ReadQueue.remove(ReadQueue.get(ReadQueueIndex));
if (ReadQueue.size() >= 0) {
    ReadQueueIndex--;
    if (ReadQueueIndex == -1) {
       Log.i("Read Queue: ", "Complete");
    }
    else {
       ReadCharacteristics(ReadQueueIndex);
    }
 }

Hope its helpful.

Salman Naseem
  • 462
  • 4
  • 17
  • I had a similar problem,I tried this approach but onCharacteristicRead() is getting called only once. Anything am missing? – msk Jul 14 '18 at 11:31
  • Yes, am setting that value to the size of characteristicslist instead of harcoded value. Also, i have noticed that in the entire process the control is going into the onCharacteristicRead() value at the end of all services. – msk Jul 14 '18 at 11:36
  • yea you noticed right. And it's hard to point out problem with seeing you code. Ask a question if you can. – Salman Naseem Jul 14 '18 at 11:42
  • Sure, but any pointer why onCharacteristicRead() is not called as soon as the control hits gatt.readCharacteristic(characteristicList.get(charIndex)); instead it goes to onCharacteristicRead() later at the end? – msk Jul 14 '18 at 11:50
1

First store your read characteristics, and ghatt objects. and if you want to read a value from characteristic call this method:

private fun readDataFromCharacteristic(ghatt: BluetoothGhatt? , characteristic:BluetoothGhattCharacteristic) {
        Log.d(TAG, " readDataFromCharacteristic")
        ghatt?.readCharacteristic(characteristic)
    }

if you call readCharacteristic(characteristic) on ghatt , below method will give result

override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {}
Balu Sangem
  • 712
  • 4
  • 16
  • the method readDataFromCharacteristic where I can declare it ? on the BleActivity or under BluetoothGattCallback ? – bircastri Feb 06 '18 at 09:04
  • what i have done is used one BaseGhattCallback which extends BluetoothGattCallback , which does serialization of commands and calling read,write and setting notifications . now Our Callback Listener implements BaseGhattCallback which has call back methods like onServicesDiscovered() etc – Balu Sangem Feb 06 '18 at 09:07
  • I do not understand what you mean – bircastri Feb 06 '18 at 09:12
  • Please see this gist : https://gist.github.com/BALUSANGEM/050425bccef32784ffb32a1fcb5eedec. and implement that class. – Balu Sangem Feb 06 '18 at 09:14
0

You should not read whole list of characteristics in onServicesDiscovered method, because ble device could havent a time to performs all requests from android client.

I offer you:

  1. Keep all characteristics in onServicesDiscovered
  2. By turns try reading characteristics in onCharacteristicRead method (at first you read first characteristic, after characteristic has been read, try reading second characteristic and ... )
user2930077
  • 135
  • 2
  • 9