BLE получает uuid, закодированную в рекламном пакете

Я пытаюсь получить UUID устройства. Я следил за руководством разработчиков Android и до сих пор могу получить только имя устройства и rssi. Я пытаюсь получить Uuid устройства, которое приходит к методу сканирования, который выглядит так:

    public void onLeScan(final BluetoothDevice device, int rssi,byte[] scanRecord) {

        ParcelUuid[] myUUid =device.getUuids();
        for(ParcelUuid a :myUUid){
            Log.d("UUID",a.getUuid().toString());
        }
        String s = new String(scanRecord);
        int len = scanRecord.length;
        String scanRecords =new String(scanRecord) ;



        deviceMap.put(device.getName().toString(), rssi);
        Message msg = MainActivity.myHandler.obtainMessage();
        Bundle bundle = new Bundle();
        bundle.putCharSequence("dev_name", device.getName().toString());
        bundle.putCharSequence("rssi", Integer.toString(rssi));
        msg.setData(bundle);
        MainActivity.myHandler.sendMessage(msg);
   }

это возвращает - btif_gattc_upstreams_evt: Событие 4096

Ответы

Ответ 1

Если вы хотите получить UUID/любые другие данные, например. Данные изготовителя из scanRec [] байт после BLE Scan, вам сначала нужно понять формат данных этого пакета данных рекламы.

Пришел с Bluetooth.org: Advertising or Scan Response Data format

Слишком много теории, хотите увидеть фрагмент кода? Эта функция, приведенная ниже, прямо вывела на печать проанализированные необработанные байты данных. Теперь вам нужно знать каждый тип кода, чтобы узнать, какой пакет данных относится к какой информации. например Тип: 0x09, относится к имени устройства BLE, Тип: 0x07, относится к UUID.

public void printScanRecord (byte[] scanRecord) {

    // Simply print all raw bytes   
    try {
        String decodedRecord = new String(scanRecord,"UTF-8");
        Log.d("DEBUG","decoded String : " + ByteArrayToString(scanRecord));
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    // Parse data bytes into individual records
    List<AdRecord> records = AdRecord.parseScanRecord(scanRecord);


    // Print individual records 
    if (records.size() == 0) {
        Log.i("DEBUG", "Scan Record Empty");
    } else {
        Log.i("DEBUG", "Scan Record: " + TextUtils.join(",", records));
    }

}


public static String ByteArrayToString(byte[] ba)
{
  StringBuilder hex = new StringBuilder(ba.length * 2);
  for (byte b : ba)
    hex.append(b + " ");

  return hex.toString();
}


public static class AdRecord {

    public AdRecord(int length, int type, byte[] data) {
        String decodedRecord = "";
        try {
            decodedRecord = new String(data,"UTF-8");

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        Log.d("DEBUG", "Length: " + length + " Type : " + type + " Data : " + ByteArrayToString(data));         
    }

    // ...

    public static List<AdRecord> parseScanRecord(byte[] scanRecord) {
        List<AdRecord> records = new ArrayList<AdRecord>();

        int index = 0;
        while (index < scanRecord.length) {
            int length = scanRecord[index++];
            //Done once we run out of records
            if (length == 0) break;

            int type = scanRecord[index];
            //Done if our record isn't a valid type
            if (type == 0) break;

            byte[] data = Arrays.copyOfRange(scanRecord, index+1, index+length);

            records.add(new AdRecord(length, type, data));
            //Advance
            index += length;
        }

        return records;
    }

    // ...
}

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

Ответ 2

Как упоминалось в комментариях, устройство BLE действительно не имеет определенного UUID (но довольно много для включенных сервисов). Однако некоторые схемы, такие как iBeacon, кодируют уникальный идентификатор в записи данных конкретного производителя в рекламном пакете.

Здесь довольно неэффективный, но концептуально простой способ преобразования всего файла scanRecord в шестнадцатеричное строковое представление для отладочной печати:

String msg = "payload = ";
for (byte b : scanRecord)
  msg += String.format("%02x ", b);

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

Ответ 3

У меня была эта же проблема при разработке моего приложения, но после прочтения документации по следующей ссылке: https://developer.android.com/reference/android/bluetooth/le/ScanResult.html

важными классами в отношении UUID (в зависимости от API, который вы разрабатываете для) являются:

AdvertiseData AdvertiseData.Builder ScanRecord ScanResult

после прочтения документации для этих классов, это код, который я написал, чтобы получить UUID для любого проверяемого устройства:

//Для API < 21:

private BluetoothAdapter.LeScanCallback scanCallBackLe =
        new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice device, int rssi, final byte[] scanRecord) {
                final int RSSI = rssi;
                if (RSSI >= signalThreshold){
                    scanHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            AdvertiseData data = new AdvertiseData.Builder()
                                    .addServiceUuid(ParcelUuid
                                            .fromString(UUID
                                                    .nameUUIDFromBytes(scanRecord).toString())).build();
                            scannerActivity.addDevice(device, RSSI, getUUID(data));
                        }
                    });
                }
            }
        };

//For APIs less than 21, Returns Device UUID
public String getUUID(AdvertiseData data){
    List<ParcelUuid> UUIDs = data.getServiceUuids();
    //ToastMakers.message(scannerActivity.getApplicationContext(), UUIDs.toString());
    String UUIDx = UUIDs.get(0).getUuid().toString();
    Log.e("UUID", " as list ->" + UUIDx);
    return UUIDx;
}

Для API > 21:

private ScanCallback mScanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, final ScanResult result) {
        Log.i("callbackType", String.valueOf(callbackType));
        Log.i("result", result.toString());
        final int RSSI = result.getRssi();
        if (RSSI>=signalThreshold) {
            scanHandler.post(
                    new Runnable() {
                        @Override
                        public void run() {
                            BluetoothDevice device = result.getDevice();
                            scannerActivity.addDevice(device, result.getRssi(), getUUID(result));
                        }
                    });
        }
    } ...}

//For APIs greater than 21, Returns Device UUID
public String getUUID(ScanResult result){
    String UUIDx = UUID
            .nameUUIDFromBytes(result.getScanRecord().getBytes()).toString();
    ToastMakers.message(scannerActivity.getApplicationContext(), UUIDx);
    Log.e("UUID", " as String ->>" + UUIDx);
    return UUIDx;
}

Мне удалось получить 128-битный UUID любого устройства, использующего этот код.:)

Ответ 4

Вы можете использовать стандартный android BluetoothGattCharacteristic apis, такой как getFloatValue (int formatType, int offset), getIntValue (int formatType, int offset), getStringValue (int offset).. обратитесь к очень хорошему учебному сайту разработчика Android здесь

 if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
        int flag = characteristic.getProperties();
        int format = -1;
        if ((flag & 0x01) != 0) {
            format = BluetoothGattCharacteristic.FORMAT_UINT16;
            Log.d(TAG, "Heart rate format UINT16.");
        } else {
            format = BluetoothGattCharacteristic.FORMAT_UINT8;
            Log.d(TAG, "Heart rate format UINT8.");
        }
        final int heartRate = characteristic.getIntValue(format, 1);
        Log.d(TAG, "Received heart rate: " + heartRate);
        intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
    }