it-swarm.com.de

BLE erhält im Werbepaket codierte UUID

Ich versuche, die UUID des ble-Geräts abzurufen. Ich folgte dem Android-Entwicklerhandbuch und bisher konnte ich nur den Gerätenamen und das rssi erhalten. Ich versuche, Uuid von dem Gerät zu erhalten, das für die Scan-Methode verwendet wird.

    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);
   }

dies gibt zurück - btif_gattc_upstreams_evt: Event 4096 

17
Boris Pawlowski

Wenn Sie UUID/andere Daten erhalten möchten, z. Herstellerdaten aus scanRec [] Bytes nach dem BLE-Scan, müssen Sie zunächst das Datenformat dieser Werbedatenpakete verstehen. 

Kam von Bluetooth.org :Advertising or Scan Response Data format

Zu viel Theorie, möchten Sie Code-Schnipsel sehen? Mit dieser Funktion können Sie die analysierten Rohdatenbytes direkt ausdrucken. Nun müssen Sie jeden Typencode kennen, um zu wissen, welches Datenpaket auf welche Informationen verweist. z.B. Typ: 0x09, bezieht sich auf BLE-Gerätename, Typ: 0x07, bezieht sich auf 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;
    }

    // ...
}

Nach dieser Analyse sind diese Datenbytes sinnvoller, und Sie können die nächste Dekodierungsebene ermitteln.

38
Khulja Sim Sim

Wie in Kommentaren erwähnt, hat ein BLE-Gerät nicht wirklich eine bestimmte UUID (sondern viele für eingeschlossene Dienste). Einige Schemata wie iBeacon kodieren jedoch einen eindeutigen Bezeichner in einem herstellerspezifischen Datensatz in einem Werbepaket. 

Hier ist eine recht ineffiziente, aber konzeptionell einfache Möglichkeit, den gesamten scanRecord in eine Hex-String-Darstellung für den Debug-Druck zu konvertieren:

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

Beachten Sie, dass dies sowohl das eigentliche Werbepaket als auch eine Anzahl bedeutungsloser nacheilender Bytes umfasst, die nach der Analyse der im Werbepaket enthaltenen Struktur (Längenfeld) ignoriert werden sollten.

3
Chris Stratton

Ich hatte das gleiche Problem während der Entwicklung meiner Ble-App, aber nachdem ich die Dokumentation unter folgendem Link gelesen hatte: https://developer.Android.com/reference/Android/bluetooth/le/ScanResult.html

die wichtigsten Klassen für UUID (abhängig von der API, für die Sie entwickeln) sind:

AdvertiseData AdvertiseData.Builder ScanRecord ScanResult

nachdem ich die Dokumentation für diese Klassen durchgelesen habe, ist dies der Code, den ich geschrieben habe, um eine UUID für jedes gescannte Gerät zu erhalten:

// Für 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;
}

Für APIs> 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;
}

Mit diesem Code konnte ich eine 128-Bit-UUID eines Geräts abrufen. :)

0

Ich habe eine Java-Bibliothek gefunden, um das Werbepaket zu analysieren

https://github.com/TakahikoKawasaki/nv-bluetooth

0
Andy J