нет обратного вызова при использовании ScanFilter в соединении Bluetooth LE - PullRequest
0 голосов
/ 04 июля 2019

Я хотел бы настроить ScanFilter для сканирования устройства BLE на основе его рекламных данных: имени, UUID службы и первого символа данных его производства. Проблема в том, что когда я использую ScanFilter, обратного вызова нет, что означает, что .onScanResult () не вызывается.

Имя устройства правильное, потому что я проверил, обнаружив устройство в обратном вызове. Когда я не использую ScanFilter, происходит обратный вызов, и устройство может быть найдено по его имени. И он может успешно подключиться к устройству.

  1. Вот мой проблемный код. Можете ли вы помочь с указанием его проблемы?

  2. Кроме того, у меня есть еще один вопрос: как ввести три параметра для .setManufacturerData ()?

    protected void scan(){
    
        List<ScanFilter> filters = new ArrayList<>();
        ScanFilter filterName = new ScanFilter.Builder().setDeviceName(this.mDeviceName).build();
        filters.add(filterName);
        //ScanFilter filterUUID = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString("00001814-0000-1000-8000-00805F9B34FB")).build();
        //filters.add(filterUUID);
        //ScanFilter filterManu = new ScanFilter.Builder().setManufacturerData().build();
        //filters.add(filterManu);
    
        ScanSettings settings = (new Builder()).setScanMode(2).build();
        this.mBluetoothLeScanner.startScan(filters, settings, this);
        this.mScanning = true;
    }
    
    @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            BluetoothDevice _device = result.getDevice();
                    Log.i("onScanResult", " callback function is being called");
    
            // find device by name
            if (_device != null && _device.getName() != null && _device.getName().matches(this.mDeviceName) ) {
                this.stopScan();
                this.mDevice = _device;
                Log.i(TAG, "mac address : " + this.mDevice.getAddress() + ", name : " + this.mDevice.getName());
                this.mDeviceFoundLatch.countDown();
            }
    
            long m = mDeviceFoundLatch.getCount();
            Log.i("onResultscallbackLatch", String.valueOf(m));
    
        }
    

Я получил эти ошибки:

E/ScanRecord: unable to parse scan record: [2, 1, 6, 3, 2, 20, 24, 2, -1, 82, 20, 9, 83, 116, 114, 105, 100, 97, 108, 121, 122, 101, 114, 32, 73, 78, 83, 73, 71, 72, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

E/BluetoothServiceJni: An exception was thrown by callback 'btgattc_scan_result_cb'.

E/BluetoothServiceJni: java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.Map.get(java.lang.Object)' on a null object reference
        at android.bluetooth.le.ScanRecord.getServiceData(ScanRecord.java:121)
        at android.bluetooth.le.ScanFilter.matches(ScanFilter.java:305)
        at com.android.bluetooth.gatt.GattService.matchesFilters(GattService.java:659)
        at com.android.bluetooth.gatt.GattService.onScanResult(GattService.java:611)

Вот правильно работающий код. Я могу использовать его, чтобы найти устройство. Но я бы хотел отфильтровать устройство по данным производителя. Нужно ли устанавливать фильтр при сканировании? Есть ли способ фильтровать данные устройства здесь?

protected void scan(){    
        ScanSettings settings = (new Builder()).setScanMode(2).build();
        this.mBluetoothLeScanner.startScan(null, settings, this);
        this.mScanning = true;
    }

    @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            BluetoothDevice _device = result.getDevice();
            if (_device != null && _device.getName() != null && _device.getName().matches(this.mDeviceName) ) {
                this.stopScan();
                this.mDevice = _device;
                this.mDeviceFoundLatch.countDown();
            }
        }

Ответы [ 2 ]

0 голосов
/ 06 июля 2019

Наконец-то получилось! Вот мое решение:

Из-за неверных данных производителя (см. Пояснение к @code выше) мы не можем напрямую использовать функцию Android - scanRecord.getManufacturerSpecificData (). Вместо этого я вручную анализирую рекламу, используя следующие коды:

@Override
public void onScanResult(int callbackType, ScanResult result) {
    super.onScanResult(callbackType, result);


    BluetoothDevice _device = result.getDevice();
    ScanRecord scanRecord = result.getScanRecord();
    byte[] byte_ScanRocord = scanRecord.getBytes();
    int isLeft = byte_ScanRocord[9];//the 9th byte stores the information that can be used to filter the device
    String byte_ScanRocord_str = Arrays.toString(byte_ScanRocord);
    Log.i("onScanRecordAdv",byte_ScanRocord_str);
    Log.i("onScanRecordisLeft",String.valueOf(isLeft));

    if (_device != null && _device.getName() != null && _device.getName().matches(this.mDeviceName) && isLeft == 76 ) {
        this.stopScan();
        this.mDevice = _device;
        Log.i("InsoleScanner", "mac address : " + this.mDevice.getAddress() + ", name : " + this.mDevice.getName());
        this.mDeviceFoundLatch.countDown();
    }
}
0 голосов
/ 05 июля 2019

Действительно данные, отправленные устройством, являются недействительными.Формат в основном представляет собой последовательность:

  • длина данных (включая тип поля)
  • тип поля
  • данные

Итакесли мы разделим данные, мы получим:

2: length 2 bytes
1: field type "flags"
6: data (flags)

3: length 3 bytes
2: field type "partial 16 bit UUID"
20, 24: data (UUID bytes 0x14 0x18, that will be converted into the full UUID 00001814-0000-1000-8000-00805F9B34FB)

2: length 2 bytes
-1 (or 0xff): field type "manufacturer data"
82: data (manufacturer data)

20: length 20 bytes
9: field type "local name complete"
83, 116, 114, 105, 100, 97, 108, 121, 122, 101, 114, 32, 73, 78, 83, 73, 71, 72, 84: data (local name, decoded as "Stridalyzer INSIGHT")
0, 0, ...: ignored data

К сожалению, данные производителя недействительны.Он должен быть не менее 3 байтов (4 с полем типа) и начинаться с 2 байтов для идентификатора производителя.Поэтому на данный момент Android отбрасывает анализ и создает ScanResult без данных вообще.

Так что вам не повезет с фильтрами.Вместо этого вам нужно будет отфильтровать его самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...