xref: /btstack/example/gap_le_advertisements.c (revision ced70f9bfeafe291ec597a3a9cc862e39e0da3ce)
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                 }
161                 break;
162             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS:
163             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS:
164             case BLUETOOTH_DATA_TYPE_LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS:
165                 for (i=0; i<size;i+=2){
166                     printf("%02X ", little_endian_read_16(data, i));
167                 }
168                 break;
169             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS:
170             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS:
171             case BLUETOOTH_DATA_TYPE_LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS:
172                 for (i=0; i<size;i+=4){
173                     printf("%04"PRIX32, little_endian_read_32(data, i));
174                 }
175                 break;
176             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS:
177             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS:
178             case BLUETOOTH_DATA_TYPE_LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS:
179                 reverse_128(data, uuid_128);
180                 printf("%s", uuid128_to_str(uuid_128));
181                 break;
182             case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME:
183             case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME:
184                 for (i=0; i<size;i++){
185                     printf("%c", (char)(data[i]));
186                 }
187                 break;
188             case BLUETOOTH_DATA_TYPE_TX_POWER_LEVEL:
189                 printf("%d dBm", *(int8_t*)data);
190                 break;
191             case BLUETOOTH_DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE:
192                 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);
193                 break;
194             case BLUETOOTH_DATA_TYPE_SERVICE_DATA:
195                 printf_hexdump(data, size);
196                 break;
197             case BLUETOOTH_DATA_TYPE_PUBLIC_TARGET_ADDRESS:
198             case BLUETOOTH_DATA_TYPE_RANDOM_TARGET_ADDRESS:
199                 reverse_bd_addr(data, address);
200                 printf("%s", bd_addr_to_str(address));
201                 break;
202             case BLUETOOTH_DATA_TYPE_APPEARANCE:
203                 // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
204                 printf("%02X", little_endian_read_16(data, 0) );
205                 break;
206             case BLUETOOTH_DATA_TYPE_ADVERTISING_INTERVAL:
207                 printf("%u ms", little_endian_read_16(data, 0) * 5/8 );
208                 break;
209             case BLUETOOTH_DATA_TYPE_3D_INFORMATION_DATA:
210                 printf_hexdump(data, size);
211                 break;
212             case BLUETOOTH_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA: // Manufacturer Specific Data
213                 break;
214             case BLUETOOTH_DATA_TYPE_CLASS_OF_DEVICE:
215             case BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_HASH_C:
216             case BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R:
217             case BLUETOOTH_DATA_TYPE_DEVICE_ID:
218             case BLUETOOTH_DATA_TYPE_SECURITY_MANAGER_OUT_OF_BAND_FLAGS:
219             default:
220                 printf("Advertising Data Type 0x%2x not handled yet", data_type);
221                 break;
222         }
223         printf("\n");
224     }
225     printf("\n");
226 }
227 /* LISTING_END */
228 
229 /* @section HCI packet handler
230  *
231  * @text The HCI packet handler has to start the scanning,
232  * and to handle received advertisements. Advertisements are received
233  * as HCI event packets of the GAP_EVENT_ADVERTISING_REPORT type,
234  * see Listing GAPLEAdvPacketHandler.
235  */
236 
237 /* LISTING_START(GAPLEAdvPacketHandler): Scanning and receiving advertisements */
238 
239 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
240     UNUSED(channel);
241     UNUSED(size);
242 
243     if (packet_type != HCI_EVENT_PACKET) return;
244 
245     bd_addr_t address;
246     uint8_t address_type;
247     uint8_t event_type;
248     int8_t rssi;
249     uint8_t length;
250     const uint8_t * data;
251 
252     switch (hci_event_packet_get_type(packet)) {
253         case GAP_EVENT_ADVERTISING_REPORT:
254             gap_event_advertising_report_get_address(packet, address);
255             event_type = gap_event_advertising_report_get_advertising_event_type(packet);
256             address_type = gap_event_advertising_report_get_address_type(packet);
257             rssi = gap_event_advertising_report_get_rssi(packet);
258             length = gap_event_advertising_report_get_data_length(packet);
259             data = gap_event_advertising_report_get_data(packet);
260             printf("Advertisement (legacy) event: evt-type %u, addr-type %u, addr %s, rssi %d, data[%u] ", event_type,
261                address_type, bd_addr_to_str(address), rssi, length);
262             printf_hexdump(data, length);
263             dump_advertisement_data(data, length);
264             break;
265 #ifdef ENABLE_LE_EXTENDED_ADVERTISING
266         case GAP_EVENT_EXTENDED_ADVERTISING_REPORT:
267             gap_event_extended_advertising_report_get_address(packet, address);
268             event_type = gap_event_extended_advertising_report_get_advertising_event_type(packet);
269             address_type = gap_event_extended_advertising_report_get_address_type(packet);
270             rssi = gap_event_extended_advertising_report_get_rssi(packet);
271             length = gap_event_extended_advertising_report_get_data_length(packet);
272             data = gap_event_extended_advertising_report_get_data(packet);
273             printf("Advertisement (extended) event: evt-type %u, addr-type %u, addr %s, rssi %d, data[%u] ", event_type,
274                address_type, bd_addr_to_str(address), rssi, length);
275             printf_hexdump(data, length);
276             dump_advertisement_data(data, length);
277             break;
278 #endif
279         default:
280             break;
281     }
282 }
283 /* LISTING_END */
284 
285 int btstack_main(void);
286 int btstack_main(void)
287 {
288     gap_le_advertisements_setup();
289 
290     // turn on!
291     hci_power_control(HCI_POWER_ON);
292 
293     return 0;
294 }
295 
296 /* EXAMPLE_END */
297