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