Read advertisement packet in Android

醉酒当歌 提交于 2021-02-05 13:07:49

问题


I'm working on a BLE sensor that is advertising manufacturer specific data. Is there any sample code that demonstrates how to receive an advertisement packet in Android and parse its payload?


回答1:


This is what I was looking for:

The BLE scan API BluetoothAdapter.startLeScan(ScanCallback) requires a call back function for the scan results. the method needs to look like the following:

    private BluetoothAdapter.LeScanCallback ScanCallback =
        new BluetoothAdapter.LeScanCallback()onLeScan(final BluetoothDevice device, 
                                                            int rssi, 
                                                      final byte[] scanRecord)
    {...}

And the scanRecord variable is a byte array which contains the Advertisement packet payload.

Per the BLE specification the structure of the payload is very simple as follows:

The packets can be up to 47 bytes in length and consist of:

  • 1 byte preamble
  • 4 byte access address
  • 2-39 bytes advertising channelPDU
  • 3 bytes CRC

For advertisement communication channels, the access address is always 0x8E89BED6.

The PDU in turn has its own header (2 bytes: size of the payload and its type – whether the device supports connections, etc.) and the actual payload (up to 37 bytes).

Finally, the first 6 bytes of the payload are the MAC address of the device, and the actual information can have up to 31 bytes.

the format of the actual information is as follows:

first byte is length of the data and second byte is type followed by the data.

This is a clever way to allow any application to skip entire data records if they don't care about the contents.

Here is the sample code to determine the contents of the Advertisement packet:

parseAdvertisementPacket(final byte[] scanRecord) {

    byte[] advertisedData = Arrays.copyOf(scanRecord, scanRecord.length);

    int offset = 0;
    while (offset < (advertisedData.length - 2)) {
        int len = advertisedData[offset++];
        if (len == 0)
            break;

        int type = advertisedData[offset++];
        switch (type) {
            case 0x02: // Partial list of 16-bit UUIDs
            case 0x03: // Complete list of 16-bit UUIDs
                while (len > 1) {
                    int uuid16 = advertisedData[offset++] & 0xFF;
                    uuid16 |= (advertisedData[offset++] << 8);
                    len -= 2;
                    uuids.add(UUID.fromString(String.format(
                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
                }
                break;
            case 0x06:// Partial list of 128-bit UUIDs
            case 0x07:// Complete list of 128-bit UUIDs
                // Loop through the advertised 128-bit UUID's.
                while (len >= 16) {
                    try {
                        // Wrap the advertised bits and order them.
                        ByteBuffer buffer = ByteBuffer.wrap(advertisedData,
                                offset++, 16).order(ByteOrder.LITTLE_ENDIAN);
                        long mostSignificantBit = buffer.getLong();
                        long leastSignificantBit = buffer.getLong();
                        uuids.add(new UUID(leastSignificantBit,
                                mostSignificantBit));
                    } catch (IndexOutOfBoundsException e) {
                        // Defensive programming.
                        Log.e("BlueToothDeviceFilter.parseUUID", e.toString());
                        continue;
                    } finally {
                        // Move the offset to read the next uuid.
                        offset += 15;
                        len -= 16;
                    }
                }
                break;
            case 0xFF:  // Manufacturer Specific Data
                Log.d(TAG, "Manufacturer Specific Data size:" + len +" bytes" );
                while (len > 1) {
                    if(i < 32) {
                        MfgData[i++] = advertisedData[offset++];
                    }
                    len -= 1;
                }
                Log.d(TAG, "Manufacturer Specific Data saved." + MfgData.toString());
                break;
            default:
                offset += (len - 1);
                break;
        }
    }

thanks to

how-ibeacons-work

bluetooth org specs

mass for putting me on the right direction!




回答2:


ADPayloadParser in nv-bluetooth parses the payload of an advertising packet and returns a list of AD structures. The AD structure format is described in "11 ADVERTISING AND SCAN RESPONSE DATA FORMAT" of "Bluetooth Core Specification 4.2".

The following code snippet is an implementation example of onLeScan method.

public void onLeScan(
    BluetoothDevice device, int rssi, byte[] scanRecord)
{
    // Parse the payload of the advertising packet.
    List<ADStructure> structures =
        ADPayloadParser.getInstance().parse(scanRecord);

    // For each AD structure contained in the advertising packet.
    for (ADStructure structure : structures)
    {
        if (structure instanceof IBeacon)
        {
            // iBeacon packet was found.
            handleIBeacon((IBeacon)structure);
        }
        ......
    }
}

You can register a parser of your own for your manufacturer-specific format into ADPayloadParser. Refer to the following links for more information.

Blog: http://darutk-oboegaki.blogspot.jp/2015/03/ibeacon-as-kind-of-ad-structures.html

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

JavaDoc: http://takahikokawasaki.github.io/nv-bluetooth/

Maven: http://search.maven.org/#search|ga|1|a%3A%22nv-bluetooth%22




回答3:


edit 21.02.2016

The library i linked below seems to have been moved; see https://github.com/AltBeacon/android-beacon-library


You can use Android iBeacon Library for a start.

There is a reference application which you can use for the basics and with simulated data. ~https://github.com/RadiusNetworks/ibeacon-reference-android~

Once you get it up and running you may wish to import the library and use it with your real device, there is also some example code on the site: http://developer.radiusnetworks.com/ibeacon/android/samples.html



来源:https://stackoverflow.com/questions/24003777/read-advertisement-packet-in-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!