Search code examples
androidarraysbluetooth-lowenergyibeacon

What is / how do I find the universal ibeacon identifier?


I am trying to write an android application to interface with iBeacons, but I need to find the start of the UUID / major / minor characteristics in the byte array. Through look at a couple of resources including this question, it seems like ALL iBeacons transmit some pattern in the byte array that is the same that identifies them as iBeacons.

I asked another question recently and got a useful answer, link here but 1) I haven't been able to test it's functionality (waiting on my device) and 2) I want to know how it is working.

So my questions: What is that pattern? Can I find it just by searching that array for the pattern? And is the UUID / Major / Minor always a predefined number of spots in the array from that identifying pattern?

Thanks!


Solution

  • So after looking around on a few different sites, I have found that 3 people list their patterns as

     02 01 06 1A FF 4C 00 02 15
    

    or

     02 01 1A 1A FF 4C 00 02 15 
    

    which isn't super helpful, since the 4C 00 appears to just be the Apple identifier, which I'm assuming could switch based on the manufacturer (Estimote, GE, Apple, whatever). However, it appears that the

    02 15
    

    is static, so I'm using that. My solution for finding it basically is just searching the byte array that I get for the first occurrence of that sequence of 2 bytes, and starting right after that I grab the next 16 as the UUID, the next 2 after that as the Major, and the next 2 after that as the Minor. So to clarify with code:

       //adPacket is an array I created to represent an iBeacon ad for testing
     byte[] adPacket = {(byte) 0xd6, (byte) 0xbe, (byte) 0x89, (byte) 0x8e, 0x40, 0x24, 0x05, (byte) 0xa2, 
                0x17, 0x6e, 0x3d, 0x71, 0x02, 0x01, 0x06, 0x1A, (byte) 0xFF, 0x4C, 0x00, 0x02, 0x15, (byte) 0xe2,
                (byte) 0xc5, 0x6d, (byte) 0xb5, (byte) 0xdf, (byte) 0xfb, 0x48, (byte) 0xd2, (byte) 0xb0, 0x60, (byte) 0xd0,
                (byte) 0xf5, (byte) 0xa7, 0x10, (byte) 0x96, (byte) 0xe0, 0x00, 0x00, 0x00, 0x00, (byte) 0xc5, 0x52, (byte) 0xab, (byte) 0x8d, 0x38, (byte) 0xa5};
        byte[] pattern = {0x02, 0x15};
        int startIndex = findAdPacketEnd(adPacket, pattern) + 1;
        if(startIndex == 0){ System.out.println("Pattern not found"); return;}
        int endIndex = startIndex + 21;
        ArrayList<Byte> tempArray = new ArrayList<Byte>();
        for(int i = startIndex; i<endIndex; i++){
            tempArray.add(adPacket[i]);
        }
        byte[] proxUUID = new byte[16];
        for(int i = 0; i<16; i++){
            proxUUID[i] = tempArray.get(i);
        }
        byte[] major = new byte[2];
        major[0] = tempArray.get(16);
        major[1] = tempArray.get(17);
    
        byte[] minor = new byte[2];
        minor[0] = tempArray.get(18);
        minor[1] = tempArray.get(19);
     ... 
    

    where my findAdPacketEnd function is (not the most efficient but it works):

        private static int findAdPacketEnd(byte[] adPacket, byte[] pattern){
        //return -1 if pattern is too long
        if(adPacket.length < pattern.length)
            return -1;
        //iterate over  adPacket
        for(int i = 0; i<adPacket.length - pattern.length; i++){
            System.out.println("Searching Ad Packet");
            //iterate over pattern
            for(int j = 0; j<pattern.length; j++){
                //compare wherever you are in the adpacket to the pattern, break if it doesn't match
                if(adPacket[i+j] != pattern[j])
                    break;
                // if you get to the end of the pattern and there wasn't a mismatch, return the index
                if(j == pattern.length-1)
                    return i+pattern.length-1;
            }
        }
        //pattern not found
        return -1;
    }