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