Overview Bluetooth Low Energy offers the ability to broadcast data in format of non-connectable advertising packets while not being in a connection. This GAP Advertisement is widely known as a beacon and is used in today’s IoT applications in different forms. This article will present the current beacon format in our demo application from the KW40Z software package and how to create the most popular beacon formats on the market. The advertising packet format and payload are declared in the gAppAdvertisingData structure from app_config.c. This structure points to an array of AD elements, advScanStruct: static const gapAdStructure_t advScanStruct[] = { { .length = NumberOfElements(adData0) + 1, .adType = gAdFlags_c, .aData = (void *)adData0 }, { .length = NumberOfElements(adData1) + 1, .adType = gAdManufacturerSpecificData_c, .aData = (void *)adData1 } }; Due to the fact that all beacons use the advertising flags structure and that the advertising PDU is 31 bytes in length (Bluetooth Low Energy v4.1), the maximum payload length is 28 bytes, including length and type for the AD elements. The AD Flags element is declared as it follows: static const uint8_t adData0[1] = { (gapAdTypeFlags_t)(gLeGeneralDiscoverableMode_c | gBrEdrNotSupported_c) }; The demo application uses a hash function to generate a random UUID for the KW40Z default beacon. This is done in BleApp_Init: void BleApp_Init(void) { sha1Context_t ctx; /* Initialize sha buffer with values from SIM_UID */ FLib_MemCopy32Unaligned(&ctx.buffer[0], SIM_UIDL); FLib_MemCopy32Unaligned(&ctx.buffer[4], SIM_UIDML); FLib_MemCopy32Unaligned(&ctx.buffer[8], SIM_UIDMH); FLib_MemCopy32Unaligned(&ctx.buffer[12], 0); SHA1_Hash(&ctx, ctx.buffer, 16); /* Updated UUID value from advertising data with the hashed value */ FLib_MemCpy(&gAppAdvertisingData.aAdStructures[1].aData[3], ctx.hash, 16); } When implementing a constant beacon payload, please bear in mind to disable this code section. KW40Z Default Beacon The KW40Z software implements a proprietary beacon with the maximum ADV payload and uses the following Manufacturer Specific Advertising Data structure of 26 bytes. This is the default implementation of the beacon demo example from the KW40Z Connectivity Software package. static uint8_t adData1[26] = { /* Company Identifier*/ 0xFF, 0x01 /* Beacon Identifier */ 0xBC, /* UUID */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* A */ 0x00, 0x00, /* B */ 0x00, 0x00, /* C */ 0x00, 0x00, /* RSSI at 1m */ 0x1E}; iBeacon iBeacon is a protocol designed by Apple. It uses a 20 byte payload that consists of the following identifying information [1] : To advertise an iBeacon packet, the user needs to change the second AD element, adData1, like below: static uint8_t adData1[25] = { 0x4C, 0x00, 0x02, 0x15, /* UUID */ 0xD9, 0xB9, 0xEC, 0x1F, 0x39, 0x25, 0x43, 0xD0, 0x80, 0xA9, 0x1E, 0x39, 0xD4, 0xCE, 0xA9, 0x5C, /* Major Version */ 0x00, 0x01 /* Minor Version */ 0x00, 0x0A, 0xC5}; AltBeacon AltBeacon is an open specification designed for proximity beacon advertisements [2]. It also uses a Manufacturer Specific Advertising Data structure: To advertise an AltBeacon packet, the user needs to change the second AD element, like below: static uint8_t adData1[26] = { /* MFG ID*/ 0xFF, 0x01, /* Beacon Code */ 0xBE, 0xAC, /* Beacon ID */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, /* Ref RSSI*/ 0xC5, /* MFG RSVD*/ 0x00}; Eddystone™ Eddystone™ is an open Bluetooth® Smart beacon format from Google [3]. It offers three data type packets: Eddystone™-UID Eddystone™-URL Eddystone™-TLM Eddystone™ uses two advertising structures: Complete List of 16-bit Service UUIDs structure, which contains the Eddystone Service UUID (0xFEAA). Service Data structure, which also contains the Eddystone™ Service UUID (0xFEAA). Thus, advScanStruct will now have 3 elements: static const gapAdStructure_t advScanStruct[] = { { .length = NumberOfElements(adData0) + 1, .adType = gAdFlags_c, .aData = (void *)adData0 }, { .length = NumberOfElements(adData1) + 1, .adType = gAdComplete16bitServiceList_c, .aData = (void *)adData1 }, { .length = NumberOfElements(adData2) + 1, .adType = gAdServiceData16bit_c, .aData = (void *)adData2 } }; The complete List of 16-bit Service UUIDs element will look like: static const uint8_t adData1[2] = { 0xAA, 0xFE }; Eddystone™-UID Eddystone™-UID broadcasts a unique 16-bit Beacon ID to identify a particular device in a group. The Service Data block has the following structure: To implement this, the user needs to add a third AD element, as follows: static uint8_t adData2[22] = { /* ID */ 0xAA, 0xFE, /* Frame Type */ 0x00, /* Ranging Data */ 0xEE, /* Namespace */ 0x8B, 0x0C, 0xA7, 0x50, 0x09, 0x54, 0x77, 0xCB, 0x3E, 0x77, /* Instance */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* RFU */ 0x00, 0x00}; Eddystone™-URL Eddystone™-URL broadcasts a compressed URL. The Service Data block has the following structure: In this example, we will implement a beacon which will advertise NXP’s webpage, http://www.nxp.com. To implement this, the user needs to add a third AD element, as follows: static const uint8_t adData2[9] = { /* ID */ 0xAA, 0xFE, /* Frame Type */ 0x10, /* TX Power */ 0xEE, /* URL scheme */ 0x00, /* Encode URL */ 'n', 'x, 'p', 0x07}; Eddystone™-TLM Eddystone™-TLM broadcasts telemetry data about the beacon device operation. The Service Data block has the following structure: To implement this, the user needs to add a third AD element, as follows: static uint8_t adData2[16] = { /* ID */ 0xAA, 0xFE, /* Frame Type */ 0x20, /* TLM Version */ 0x00, /* VBATT */ 0x00, 0x00, /* TEMP */ 0x00, 0x00, /* ADV_CNT */ 0x00, 0x00, 0x00, 0x00, /* SEC_CNT */ 0x00, 0x00, 0x00, 0x00};
View full article