1*bcf00d8fSMatthias Ringwald /* 2*bcf00d8fSMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3*bcf00d8fSMatthias Ringwald * 4*bcf00d8fSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*bcf00d8fSMatthias Ringwald * modification, are permitted provided that the following conditions 6*bcf00d8fSMatthias Ringwald * are met: 7*bcf00d8fSMatthias Ringwald * 8*bcf00d8fSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*bcf00d8fSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*bcf00d8fSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*bcf00d8fSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*bcf00d8fSMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*bcf00d8fSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*bcf00d8fSMatthias Ringwald * contributors may be used to endorse or promote products derived 15*bcf00d8fSMatthias Ringwald * from this software without specific prior written permission. 16*bcf00d8fSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*bcf00d8fSMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*bcf00d8fSMatthias Ringwald * monetary gain. 19*bcf00d8fSMatthias Ringwald * 20*bcf00d8fSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*bcf00d8fSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*bcf00d8fSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*bcf00d8fSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*bcf00d8fSMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*bcf00d8fSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*bcf00d8fSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*bcf00d8fSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*bcf00d8fSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*bcf00d8fSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*bcf00d8fSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*bcf00d8fSMatthias Ringwald * SUCH DAMAGE. 32*bcf00d8fSMatthias Ringwald * 33*bcf00d8fSMatthias Ringwald * Please inquire about commercial licensing options at 34*bcf00d8fSMatthias Ringwald * [email protected] 35*bcf00d8fSMatthias Ringwald * 36*bcf00d8fSMatthias Ringwald */ 37*bcf00d8fSMatthias Ringwald 38*bcf00d8fSMatthias Ringwald 39*bcf00d8fSMatthias Ringwald // ***************************************************************************** 40*bcf00d8fSMatthias Ringwald /* EXAMPLE_START(gap_le_advertisements): GAP LE Advertisements Dumper 41*bcf00d8fSMatthias Ringwald * 42*bcf00d8fSMatthias Ringwald * @text This example shows how to scan and parse advertisements. 43*bcf00d8fSMatthias Ringwald * 44*bcf00d8fSMatthias Ringwald */ 45*bcf00d8fSMatthias Ringwald // ***************************************************************************** 46*bcf00d8fSMatthias Ringwald 47*bcf00d8fSMatthias Ringwald 48*bcf00d8fSMatthias Ringwald #include <stdint.h> 49*bcf00d8fSMatthias Ringwald #include <stdio.h> 50*bcf00d8fSMatthias Ringwald #include <stdlib.h> 51*bcf00d8fSMatthias Ringwald #include <string.h> 52*bcf00d8fSMatthias Ringwald 53*bcf00d8fSMatthias Ringwald #include "hci_cmd.h" 54*bcf00d8fSMatthias Ringwald 55*bcf00d8fSMatthias Ringwald #include "btstack_memory.h" 56*bcf00d8fSMatthias Ringwald #include "hci.h" 57*bcf00d8fSMatthias Ringwald #include "ble/ad_parser.h" 58*bcf00d8fSMatthias Ringwald 59*bcf00d8fSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 60*bcf00d8fSMatthias Ringwald 61*bcf00d8fSMatthias Ringwald /* @section GAP LE setup for receiving advertisements 62*bcf00d8fSMatthias Ringwald * 63*bcf00d8fSMatthias Ringwald * @text GAP LE advertisements are received as custom HCI events of the 64*bcf00d8fSMatthias Ringwald * GAP_LE_EVENT_ADVERTISING_REPORT type. To receive them, you'll need to register 65*bcf00d8fSMatthias Ringwald * the HCI packet handler, as shown in Listing GAPLEAdvSetup. 66*bcf00d8fSMatthias Ringwald */ 67*bcf00d8fSMatthias Ringwald 68*bcf00d8fSMatthias Ringwald /* LISTING_START(GAPLEAdvSetup): Setting up GAP LE client for receiving advertisements */ 69*bcf00d8fSMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 70*bcf00d8fSMatthias Ringwald 71*bcf00d8fSMatthias Ringwald static void gap_le_advertisements_setup(void){ 72*bcf00d8fSMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 73*bcf00d8fSMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 74*bcf00d8fSMatthias Ringwald } 75*bcf00d8fSMatthias Ringwald 76*bcf00d8fSMatthias Ringwald /* LISTING_END */ 77*bcf00d8fSMatthias Ringwald 78*bcf00d8fSMatthias Ringwald /* @section GAP LE Advertising Data Dumper 79*bcf00d8fSMatthias Ringwald * 80*bcf00d8fSMatthias Ringwald * @text Here, we use the definition of advertising data types and flags as specified in 81*bcf00d8fSMatthias Ringwald * [Assigned Numbers GAP](https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile) 82*bcf00d8fSMatthias Ringwald * and [Supplement to the Bluetooth Core Specification, v4](https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=282152). 83*bcf00d8fSMatthias Ringwald */ 84*bcf00d8fSMatthias Ringwald 85*bcf00d8fSMatthias Ringwald /* LISTING_START(GAPLEAdvDataTypesAndFlags): Advertising data types and flags */ 86*bcf00d8fSMatthias Ringwald static char * ad_types[] = { 87*bcf00d8fSMatthias Ringwald "", 88*bcf00d8fSMatthias Ringwald "Flags", 89*bcf00d8fSMatthias Ringwald "Incomplete List of 16-bit Service Class UUIDs", 90*bcf00d8fSMatthias Ringwald "Complete List of 16-bit Service Class UUIDs", 91*bcf00d8fSMatthias Ringwald "Incomplete List of 32-bit Service Class UUIDs", 92*bcf00d8fSMatthias Ringwald "Complete List of 32-bit Service Class UUIDs", 93*bcf00d8fSMatthias Ringwald "Incomplete List of 128-bit Service Class UUIDs", 94*bcf00d8fSMatthias Ringwald "Complete List of 128-bit Service Class UUIDs", 95*bcf00d8fSMatthias Ringwald "Shortened Local Name", 96*bcf00d8fSMatthias Ringwald "Complete Local Name", 97*bcf00d8fSMatthias Ringwald "Tx Power Level", 98*bcf00d8fSMatthias Ringwald "", 99*bcf00d8fSMatthias Ringwald "", 100*bcf00d8fSMatthias Ringwald "Class of Device", 101*bcf00d8fSMatthias Ringwald "Simple Pairing Hash C", 102*bcf00d8fSMatthias Ringwald "Simple Pairing Randomizer R", 103*bcf00d8fSMatthias Ringwald "Device ID", 104*bcf00d8fSMatthias Ringwald "Security Manager TK Value", 105*bcf00d8fSMatthias Ringwald "Slave Connection Interval Range", 106*bcf00d8fSMatthias Ringwald "", 107*bcf00d8fSMatthias Ringwald "List of 16-bit Service Solicitation UUIDs", 108*bcf00d8fSMatthias Ringwald "List of 128-bit Service Solicitation UUIDs", 109*bcf00d8fSMatthias Ringwald "Service Data", 110*bcf00d8fSMatthias Ringwald "Public Target Address", 111*bcf00d8fSMatthias Ringwald "Random Target Address", 112*bcf00d8fSMatthias Ringwald "Appearance", 113*bcf00d8fSMatthias Ringwald "Advertising Interval" 114*bcf00d8fSMatthias Ringwald }; 115*bcf00d8fSMatthias Ringwald 116*bcf00d8fSMatthias Ringwald static char * flags[] = { 117*bcf00d8fSMatthias Ringwald "LE Limited Discoverable Mode", 118*bcf00d8fSMatthias Ringwald "LE General Discoverable Mode", 119*bcf00d8fSMatthias Ringwald "BR/EDR Not Supported", 120*bcf00d8fSMatthias Ringwald "Simultaneous LE and BR/EDR to Same Device Capable (Controller)", 121*bcf00d8fSMatthias Ringwald "Simultaneous LE and BR/EDR to Same Device Capable (Host)", 122*bcf00d8fSMatthias Ringwald "Reserved", 123*bcf00d8fSMatthias Ringwald "Reserved", 124*bcf00d8fSMatthias Ringwald "Reserved" 125*bcf00d8fSMatthias Ringwald }; 126*bcf00d8fSMatthias Ringwald /* LISTING_END */ 127*bcf00d8fSMatthias Ringwald 128*bcf00d8fSMatthias Ringwald /* @text BTstack offers an iterator for parsing sequence of advertising data (AD) structures, 129*bcf00d8fSMatthias Ringwald * see [BLE advertisements parser API](../appendix/apis/#ble-advertisements-parser-api). 130*bcf00d8fSMatthias Ringwald * After initializing the iterator, each AD structure is dumped according to its type. 131*bcf00d8fSMatthias Ringwald */ 132*bcf00d8fSMatthias Ringwald 133*bcf00d8fSMatthias Ringwald /* LISTING_START(GAPLEAdvDataParsing): Parsing advertising data */ 134*bcf00d8fSMatthias Ringwald static void dump_advertisement_data(uint8_t * adv_data, uint8_t adv_size){ 135*bcf00d8fSMatthias Ringwald ad_context_t context; 136*bcf00d8fSMatthias Ringwald bd_addr_t address; 137*bcf00d8fSMatthias Ringwald uint8_t uuid_128[16]; 138*bcf00d8fSMatthias Ringwald for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){ 139*bcf00d8fSMatthias Ringwald uint8_t data_type = ad_iterator_get_data_type(&context); 140*bcf00d8fSMatthias Ringwald uint8_t size = ad_iterator_get_data_len(&context); 141*bcf00d8fSMatthias Ringwald uint8_t * data = ad_iterator_get_data(&context); 142*bcf00d8fSMatthias Ringwald 143*bcf00d8fSMatthias Ringwald if (data_type > 0 && data_type < 0x1B){ 144*bcf00d8fSMatthias Ringwald printf(" %s: ", ad_types[data_type]); 145*bcf00d8fSMatthias Ringwald } 146*bcf00d8fSMatthias Ringwald int i; 147*bcf00d8fSMatthias Ringwald // Assigned Numbers GAP 148*bcf00d8fSMatthias Ringwald 149*bcf00d8fSMatthias Ringwald switch (data_type){ 150*bcf00d8fSMatthias Ringwald case 0x01: // Flags 151*bcf00d8fSMatthias Ringwald // show only first octet, ignore rest 152*bcf00d8fSMatthias Ringwald for (i=0; i<8;i++){ 153*bcf00d8fSMatthias Ringwald if (data[0] & (1<<i)){ 154*bcf00d8fSMatthias Ringwald printf("%s; ", flags[i]); 155*bcf00d8fSMatthias Ringwald } 156*bcf00d8fSMatthias Ringwald 157*bcf00d8fSMatthias Ringwald } 158*bcf00d8fSMatthias Ringwald break; 159*bcf00d8fSMatthias Ringwald case 0x02: // Incomplete List of 16-bit Service Class UUIDs 160*bcf00d8fSMatthias Ringwald case 0x03: // Complete List of 16-bit Service Class UUIDs 161*bcf00d8fSMatthias Ringwald case 0x14: // List of 16-bit Service Solicitation UUIDs 162*bcf00d8fSMatthias Ringwald for (i=0; i<size;i+=2){ 163*bcf00d8fSMatthias Ringwald printf("%02X ", little_endian_read_16(data, i)); 164*bcf00d8fSMatthias Ringwald } 165*bcf00d8fSMatthias Ringwald break; 166*bcf00d8fSMatthias Ringwald case 0x04: // Incomplete List of 32-bit Service Class UUIDs 167*bcf00d8fSMatthias Ringwald case 0x05: // Complete List of 32-bit Service Class UUIDs 168*bcf00d8fSMatthias Ringwald for (i=0; i<size;i+=4){ 169*bcf00d8fSMatthias Ringwald printf("%04X ", little_endian_read_32(data, i)); 170*bcf00d8fSMatthias Ringwald } 171*bcf00d8fSMatthias Ringwald break; 172*bcf00d8fSMatthias Ringwald case 0x06: // Incomplete List of 128-bit Service Class UUIDs 173*bcf00d8fSMatthias Ringwald case 0x07: // Complete List of 128-bit Service Class UUIDs 174*bcf00d8fSMatthias Ringwald case 0x15: // List of 128-bit Service Solicitation UUIDs 175*bcf00d8fSMatthias Ringwald reverse_128(data, uuid_128); 176*bcf00d8fSMatthias Ringwald printf("%s", uuid128_to_str(uuid_128)); 177*bcf00d8fSMatthias Ringwald break; 178*bcf00d8fSMatthias Ringwald case 0x08: // Shortened Local Name 179*bcf00d8fSMatthias Ringwald case 0x09: // Complete Local Name 180*bcf00d8fSMatthias Ringwald for (i=0; i<size;i++){ 181*bcf00d8fSMatthias Ringwald printf("%c", (char)(data[i])); 182*bcf00d8fSMatthias Ringwald } 183*bcf00d8fSMatthias Ringwald break; 184*bcf00d8fSMatthias Ringwald case 0x0A: // Tx Power Level 185*bcf00d8fSMatthias Ringwald printf("%d dBm", *(int8_t*)data); 186*bcf00d8fSMatthias Ringwald break; 187*bcf00d8fSMatthias Ringwald case 0x12: // Slave Connection Interval Range 188*bcf00d8fSMatthias Ringwald printf("Connection Interval Min = %u ms, Max = %u ms", little_endian_read_16(data, 0) * 5/4, little_endian_read_16(data, 2) * 5/4); 189*bcf00d8fSMatthias Ringwald break; 190*bcf00d8fSMatthias Ringwald case 0x16: // Service Data 191*bcf00d8fSMatthias Ringwald printf_hexdump(data, size); 192*bcf00d8fSMatthias Ringwald break; 193*bcf00d8fSMatthias Ringwald case 0x17: // Public Target Address 194*bcf00d8fSMatthias Ringwald case 0x18: // Random Target Address 195*bcf00d8fSMatthias Ringwald reverse_bd_addr(data, address); 196*bcf00d8fSMatthias Ringwald printf("%s", bd_addr_to_str(address)); 197*bcf00d8fSMatthias Ringwald break; 198*bcf00d8fSMatthias Ringwald case 0x19: // Appearance 199*bcf00d8fSMatthias Ringwald // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml 200*bcf00d8fSMatthias Ringwald printf("%02X", little_endian_read_16(data, 0) ); 201*bcf00d8fSMatthias Ringwald break; 202*bcf00d8fSMatthias Ringwald case 0x1A: // Advertising Interval 203*bcf00d8fSMatthias Ringwald printf("%u ms", little_endian_read_16(data, 0) * 5/8 ); 204*bcf00d8fSMatthias Ringwald break; 205*bcf00d8fSMatthias Ringwald case 0x3D: // 3D Information Data 206*bcf00d8fSMatthias Ringwald printf_hexdump(data, size); 207*bcf00d8fSMatthias Ringwald break; 208*bcf00d8fSMatthias Ringwald case 0xFF: // Manufacturer Specific Data 209*bcf00d8fSMatthias Ringwald break; 210*bcf00d8fSMatthias Ringwald case 0x0D: // Class of Device (3B) 211*bcf00d8fSMatthias Ringwald case 0x0E: // Simple Pairing Hash C (16B) 212*bcf00d8fSMatthias Ringwald case 0x0F: // Simple Pairing Randomizer R (16B) 213*bcf00d8fSMatthias Ringwald case 0x10: // Device ID 214*bcf00d8fSMatthias Ringwald case 0x11: // Security Manager TK Value (16B) 215*bcf00d8fSMatthias Ringwald default: 216*bcf00d8fSMatthias Ringwald printf("Unknown Advertising Data Type"); 217*bcf00d8fSMatthias Ringwald break; 218*bcf00d8fSMatthias Ringwald } 219*bcf00d8fSMatthias Ringwald printf("\n"); 220*bcf00d8fSMatthias Ringwald } 221*bcf00d8fSMatthias Ringwald printf("\n"); 222*bcf00d8fSMatthias Ringwald } 223*bcf00d8fSMatthias Ringwald /* LISTING_END */ 224*bcf00d8fSMatthias Ringwald 225*bcf00d8fSMatthias Ringwald /* @section HCI packet handler 226*bcf00d8fSMatthias Ringwald * 227*bcf00d8fSMatthias Ringwald * @text The HCI packet handler has to start the scanning, 228*bcf00d8fSMatthias Ringwald * and to handle received advertisements. Advertisements are received 229*bcf00d8fSMatthias Ringwald * as HCI event packets of the GAP_LE_EVENT_ADVERTISING_REPORT type, 230*bcf00d8fSMatthias Ringwald * see Listing GAPLEAdvPacketHandler. 231*bcf00d8fSMatthias Ringwald */ 232*bcf00d8fSMatthias Ringwald 233*bcf00d8fSMatthias Ringwald /* LISTING_START(GAPLEAdvPacketHandler): Scanning and receiving advertisements */ 234*bcf00d8fSMatthias Ringwald 235*bcf00d8fSMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 236*bcf00d8fSMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 237*bcf00d8fSMatthias Ringwald 238*bcf00d8fSMatthias Ringwald switch (packet[0]) { 239*bcf00d8fSMatthias Ringwald case BTSTACK_EVENT_STATE: 240*bcf00d8fSMatthias Ringwald // BTstack activated, get started 241*bcf00d8fSMatthias Ringwald if (packet[2] == HCI_STATE_WORKING) { 242*bcf00d8fSMatthias Ringwald printf("BTstack activated, start scaning!\n"); 243*bcf00d8fSMatthias Ringwald gap_set_scan_parameters(0,0x0030, 0x0030); 244*bcf00d8fSMatthias Ringwald gap_start_scan(); 245*bcf00d8fSMatthias Ringwald } 246*bcf00d8fSMatthias Ringwald break; 247*bcf00d8fSMatthias Ringwald case GAP_LE_EVENT_ADVERTISING_REPORT:{ 248*bcf00d8fSMatthias Ringwald int pos = 2; 249*bcf00d8fSMatthias Ringwald uint8_t event_type = packet[pos++]; 250*bcf00d8fSMatthias Ringwald uint8_t address_type = packet[pos++]; 251*bcf00d8fSMatthias Ringwald bd_addr_t address; 252*bcf00d8fSMatthias Ringwald reverse_bd_addr(&packet[pos], address); 253*bcf00d8fSMatthias Ringwald pos += 6; 254*bcf00d8fSMatthias Ringwald uint8_t rssi = packet[pos++]; 255*bcf00d8fSMatthias Ringwald uint8_t length = packet[pos++]; 256*bcf00d8fSMatthias Ringwald uint8_t * data = &packet[pos]; 257*bcf00d8fSMatthias Ringwald 258*bcf00d8fSMatthias Ringwald printf("Advertisement event: evt-type %u, addr-type %u, addr %s, rssi %u, data[%u] ", event_type, 259*bcf00d8fSMatthias Ringwald address_type, bd_addr_to_str(address), rssi, length); 260*bcf00d8fSMatthias Ringwald printf_hexdump(data, length); 261*bcf00d8fSMatthias Ringwald dump_advertisement_data(data, length); 262*bcf00d8fSMatthias Ringwald break; 263*bcf00d8fSMatthias Ringwald } 264*bcf00d8fSMatthias Ringwald default: 265*bcf00d8fSMatthias Ringwald break; 266*bcf00d8fSMatthias Ringwald } 267*bcf00d8fSMatthias Ringwald } 268*bcf00d8fSMatthias Ringwald /* LISTING_END */ 269*bcf00d8fSMatthias Ringwald 270*bcf00d8fSMatthias Ringwald int btstack_main(void); 271*bcf00d8fSMatthias Ringwald int btstack_main(void) 272*bcf00d8fSMatthias Ringwald { 273*bcf00d8fSMatthias Ringwald gap_le_advertisements_setup(); 274*bcf00d8fSMatthias Ringwald 275*bcf00d8fSMatthias Ringwald // turn on! 276*bcf00d8fSMatthias Ringwald hci_power_control(HCI_POWER_ON); 277*bcf00d8fSMatthias Ringwald 278*bcf00d8fSMatthias Ringwald return 0; 279*bcf00d8fSMatthias Ringwald } 280*bcf00d8fSMatthias Ringwald 281*bcf00d8fSMatthias Ringwald /* EXAMPLE_END */