2

I want to transmit iBluetooth over android with the BluetoothLeAdvertiser class from android.bluetooth.le. But it seems I can't set some of the Manufacturer spec data fields to match those of the iBeacon.


iBeacon structure: iBeacon data packet

This and this tell you what an iBeacon's Manufacturer spec data values need to contain. Basically:

Apple Company Identifier (Little Endian), 0x004c = 76
data type, 0x02 => iBeacon
data length, 0x15 = 21
uuid: 585CDE931B0142CC9A1325009BEDC65E
major: [0000]
minor: 0000
meaured power at 1 meter: 0xc5 = -59




I've been following this tutorial that has these steps:
  1. Create the AdvertiseData object using AdvertiseData.Builder.addManufacturerData() (which I believe should be the Manufacturer spec data, see below for the issues with that)

    protected void setAdvertiseData() {
    
      AdvertiseData.Builder mBuilder = new AdvertiseData.Builder();
    
      ByteBuffer mManufacturerData = ByteBuffer.allocate(24);
    
      byte[] uuid = getIdAsByte(UUID.fromString("0CF052C2-97CA-407C-84F8-B62AAC4E9020"));
    
      mManufacturerData.put(0, (byte)0xBE); // Beacon Identifier
    
      mManufacturerData.put(1, (byte)0xAC); // Beacon Identifier
    
      for (int i=2; i<=17; i++) {
    
        mManufacturerData.put(i, uuid[i-2]); // adding the UUID
    
      }
    
      mManufacturerData.put(18, (byte)0x00); // first byte of Major
      mManufacturerData.put(19, (byte)0x09); // second byte of Major
      mManufacturerData.put(20, (byte)0x00); // first minor
      mManufacturerData.put(21, (byte)0x06); // second minor
      mManufacturerData.put(22, (byte)0xB5); // txPower
      mBuilder.addManufacturerData(224, mManufacturerData.array()); // using google's company ID
      mAdvertiseData = mBuilder.build();
    }
    
  2. Create AdvertiseSettings using the AdvertiseSettings.Builder

    protected void setAdvertiseSettings() {
      AdvertiseSettings.Builder mBuilder = new AdvertiseSettings.Builder();
      mBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);
      mBuilder.setConnectable(false);
      mBuilder.setTimeout(0);
      mBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM);
      mAdvertiseSettings = mBuilder.build();
    }
    
  3. Broadcast the AdvertiseSettings and AdvertiseData using BluetoothLeAdvertiser. (This also takes a callBack that tells if Bluetooth transmission worked, no problems there)

    mBluetoothLeAdvertiser.startAdvertising(mAdvertiseSettings, mAdvertiseData, mAdvertiseCallback);
    




The problem with these steps are:




At first I was following this tutorial, and was transmitting an Alt-Beacon. Perhaps the BluetoothLeAdvertiser class is assuming I'm still transmitting Alt-Beacon which is differently structured than iBeacons.

Alt-Beacon structure:Alt-Beacon Data packet



other resources:

updated code

public AdvertiseData getiBeaconData() {
    AdvertiseData.Builder mBuilder = new AdvertiseData.Builder();
    ByteBuffer mManufacturerData = ByteBuffer.allocate(24);

    byte[] uuid = getIdAsByte(UUID.fromString(thisCont.getString( R.string.ble_uuid )) );
    ParcelUuid parced = new ParcelUuid(UUID.fromString(thisCont.getString( R.string.ble_uuid )) );
    /*

R.string.ble_uuid == CDB7950D-73F1-4D4D-8E47-C090502DBD63 this is about the iBeacon structure http://smlie-blog.blogspot.com/2014/06/bluetooth-ibeacon-packet-format.html */

    //mManufacturerData.put((byte)0x00); //Manufactor Id 1
    //mManufacturerData.put((byte)0x4C); //Manufactor Id 2
   // mManufacturerData.put((byte)0xBE); //ibeconid1
    mManufacturerData.put((byte)0x02); //ibeconid2
    mManufacturerData.put((byte)0x15); //Data length
    for (byte i:uuid) {
        mManufacturerData.put(i); // adding the UUID
    }
    mManufacturerData.put((byte)0x00); //major first
    mManufacturerData.put((byte)0x00); //major second
    mManufacturerData.put((byte)0x00); //minor first
    mManufacturerData.put((byte)0x00); //minor second
    //mManufacturerData.put((byte)0xC5); //TX power

    /*
    mManufacturerData.put((byte)0x1A); // Beacon Identifier was BE  iBeacon = 00
    mManufacturerData.put((byte)0xFF); // Beacon Identifier was AC  iBeacon = 02
    /* the above 2 lines are the ibeacon AD Indicator

    for (byte i:uuid) {
        mManufacturerData.put(i); // adding the UUID
    }
    mManufacturerData.put((byte)0x00); // first byte of Major
    mManufacturerData.put((byte)0x00); // second byte of Major
    mManufacturerData.put((byte)0x00); // first minor
    mManufacturerData.put((byte)0x00); // second minor
    mManufacturerData.put((byte)0xC5); // txPower (RSSI) (from tx)
    mBuilder.addManufacturerData(16, mManufacturerData.array()); // using google's company ID
    */

    mBuilder.addManufacturerData(76, mManufacturerData.array()); // using google's company ID
    //mBuilder.addServiceUuid(parced);
    return mBuilder.build();

}

parsed data nrfBeacon raw packet data

mikeLundquist
  • 769
  • 1
  • 12
  • 26

1 Answers1

1

I think your code is quite good. Some remarks:

  • Manufacture ID for Apple is 76: mBuilder.addManufacturerData(76, mManufacturerData.array())
  • iBeacon type is 0x02: mManufacturerData.put(0, (byte)0x02); // Beacon Identifier
  • length is 0x15: mManufacturerData.put(1, (byte)0x15); // Beacon Identifier
  • I am not sure if that works: UUID.fromString("0CF052C297CA407C84F8B62AAC4E9020"). Usually the fromString() method expects something like: UUID.fromString("F0018B9B-7509-4C31-A905-1A27D39C003D")

to sum up:

protected void setAdvertiseData() {

     AdvertiseData.Builder mBuilder = new AdvertiseData.Builder()

     ByteBuffer mManufacturerData = ByteBuffer.allocate(23);

     byte[] uuid = getIdAsByte(UUID.fromString("0CF052C297CA407C84F8B62AAC4E9020"));

     mManufacturerData.put(0, (byte)0x02);
     mManufacturerData.put(1, (byte)0x15); 

     for (int i=2; i<=17; i++) {
       mManufacturerData.put(i, uuid[i-2]); // adding the UUID
     }

     mManufacturerData.put(18, (byte)0x00); // first byte of Major
     mManufacturerData.put(19, (byte)0x09); // second byte of Major
     mManufacturerData.put(20, (byte)0x00); // first minor
     mManufacturerData.put(21, (byte)0x06); // second minor
     mManufacturerData.put(22, (byte)0xB5); // txPower

     mBuilder.addManufacturerData(76, mManufacturerData.array()); 
     mAdvertiseData = mBuilder.build();
}
Christopher
  • 9,682
  • 7
  • 47
  • 76
  • Correct, I left the Alt-Beacon values in because they were in the tutorial I got the code from. I tried having the Beacon Identifier as 2 bytes (0x00,0x02). When I tried adding the 0x15 (with 00,02) I got a buffer overflow, which I also got with 0xFF and 0x00 (for the length) – mikeLundquist Jan 25 '18 at 14:05
  • Not adding. Replace the parts I mentioned. – Christopher Jan 25 '18 at 14:07
  • I mean the byte at index 1. -> `mManufacturerData.put(1, (byte)0xAC); ` -> replace with `mManufacturerData.put(1, (byte)0x15);` – Christopher Jan 25 '18 at 14:09
  • Just tried these values, this beacon is still showing up as an AltBeacon in nrfConnect (a bluetooth receiving app) – mikeLundquist Jan 25 '18 at 14:20
  • 1
    Can you update your question with your current code and can you present the raw view of the advertisement frame in nrf app? If you change the manufacturer id, it can't be an Altbeacon any longer. – Christopher Jan 25 '18 at 14:22
  • @user4757074 I just checked your implementation and the screenshot. From my point of view this is a valid iBeacon frame and definitely no AltBeacon format. You can check this with e.g. Beaconscanner: http://play.google.com/store/apps/details?id=com.bridou_n.beaconscanner – Christopher Jan 25 '18 at 14:55
  • Beaconscanner picked up an iBeacon with my uuid with no changes to the code I posted!!!! – mikeLundquist Jan 25 '18 at 15:08