xref: /btstack/example/gap_le_advertisements.c (revision b3fcedb9c9ccbcc9680da165cd86f394be5d84a8)
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 MATTHIAS
24  * RINGWALD 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 
39 // *****************************************************************************
40 /* EXAMPLE_START(gap_le_advertisements): GAP LE Advertisements Dumper
41  *
42  * @text This example shows how to scan and parse advertisements.
43  *
44  */
45  // *****************************************************************************
46 
47 
48 #include <stdint.h>
49 #include <inttypes.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 
54 #include "btstack.h"
55 
56 static btstack_packet_callback_registration_t hci_event_callback_registration;
57 
58 /* @section GAP LE setup for receiving advertisements
59  *
60  * @text GAP LE advertisements are received as custom HCI events of the
61  * GAP_EVENT_ADVERTISING_REPORT type. To receive them, you'll need to register
62  * the HCI packet handler, as shown in Listing GAPLEAdvSetup.
63  */
64 
65 /* LISTING_START(GAPLEAdvSetup): Setting up GAP LE client for receiving advertisements */
66 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
67 
68 static void gap_le_advertisements_setup(void){
69     hci_event_callback_registration.callback = &packet_handler;
70     hci_add_event_handler(&hci_event_callback_registration);
71 }
72 
73 /* LISTING_END */
74 
75 /* @section GAP LE Advertising Data Dumper
76  *
77  * @text Here, we use the definition of advertising data types and flags as specified in
78  * [Assigned Numbers GAP](https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile)
79  * and [Supplement to the Bluetooth Core Specification, v4](https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=282152).
80  */
81 
82 /* LISTING_START(GAPLEAdvDataTypesAndFlags): Advertising data types and flags */
83 static char * ad_types[] = {
84     "",
85     "Flags",
86     "Incomplete List of 16-bit Service Class UUIDs",
87     "Complete List of 16-bit Service Class UUIDs",
88     "Incomplete List of 32-bit Service Class UUIDs",
89     "Complete List of 32-bit Service Class UUIDs",
90     "Incomplete List of 128-bit Service Class UUIDs",
91     "Complete List of 128-bit Service Class UUIDs",
92     "Shortened Local Name",
93     "Complete Local Name",
94     "Tx Power Level",
95     "",
96     "",
97     "Class of Device",
98     "Simple Pairing Hash C",
99     "Simple Pairing Randomizer R",
100     "Device ID",
101     "Security Manager TK Value",
102     "Slave Connection Interval Range",
103     "",
104     "List of 16-bit Service Solicitation UUIDs",
105     "List of 128-bit Service Solicitation UUIDs",
106     "Service Data",
107     "Public Target Address",
108     "Random Target Address",
109     "Appearance",
110     "Advertising Interval"
111 };
112 
113 static char * flags[] = {
114     "LE Limited Discoverable Mode",
115     "LE General Discoverable Mode",
116     "BR/EDR Not Supported",
117     "Simultaneous LE and BR/EDR to Same Device Capable (Controller)",
118     "Simultaneous LE and BR/EDR to Same Device Capable (Host)",
119     "Reserved",
120     "Reserved",
121     "Reserved"
122 };
123 /* LISTING_END */
124 
125 /* @text BTstack offers an iterator for parsing sequence of advertising data (AD) structures,
126  * see [BLE advertisements parser API](../appendix/apis/#ble-advertisements-parser-api).
127  * After initializing the iterator, each AD structure is dumped according to its type.
128  */
129 
130 /* LISTING_START(GAPLEAdvDataParsing): Parsing advertising data */
131 static void dump_advertisement_data(const uint8_t * adv_data, uint8_t adv_size){
132     ad_context_t context;
133     bd_addr_t address;
134     uint8_t uuid_128[16];
135     for (ad_iterator_init(&context, adv_size, (uint8_t *)adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
136         uint8_t data_type = ad_iterator_get_data_type(&context);
137         uint8_t size      = ad_iterator_get_data_len(&context);
138         uint8_t * data    = ad_iterator_get_data(&context);
139 
140         if (data_type > 0 && data_type < 0x1B){
141             printf("    %s: ", ad_types[data_type]);
142         }
143         int i;
144         // Assigned Numbers GAP
145 
146         switch (data_type){
147             case 0x01: // Flags
148                 // show only first octet, ignore rest
149                 for (i=0; i<8;i++){
150                     if (data[0] & (1<<i)){
151                         printf("%s; ", flags[i]);
152                     }
153 
154                 }
155                 break;
156             case 0x02: // Incomplete List of 16-bit Service Class UUIDs
157             case 0x03: // Complete List of 16-bit Service Class UUIDs
158             case 0x14: // List of 16-bit Service Solicitation UUIDs
159                 for (i=0; i<size;i+=2){
160                     printf("%02X ", little_endian_read_16(data, i));
161                 }
162                 break;
163             case 0x04: // Incomplete List of 32-bit Service Class UUIDs
164             case 0x05: // Complete List of 32-bit Service Class UUIDs
165                 for (i=0; i<size;i+=4){
166                     printf("%04"PRIX32, little_endian_read_32(data, i));
167                 }
168                 break;
169             case 0x06: // Incomplete List of 128-bit Service Class UUIDs
170             case 0x07: // Complete List of 128-bit Service Class UUIDs
171             case 0x15: // List of 128-bit Service Solicitation UUIDs
172                 reverse_128(data, uuid_128);
173                 printf("%s", uuid128_to_str(uuid_128));
174                 break;
175             case 0x08: // Shortened Local Name
176             case 0x09: // Complete Local Name
177                 for (i=0; i<size;i++){
178                     printf("%c", (char)(data[i]));
179                 }
180                 break;
181             case 0x0A: // Tx Power Level
182                 printf("%d dBm", *(int8_t*)data);
183                 break;
184             case 0x12: // Slave Connection Interval Range
185                 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);
186                 break;
187             case 0x16: // Service Data
188                 printf_hexdump(data, size);
189                 break;
190             case 0x17: // Public Target Address
191             case 0x18: // Random Target Address
192                 reverse_bd_addr(data, address);
193                 printf("%s", bd_addr_to_str(address));
194                 break;
195             case 0x19: // Appearance
196                 // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
197                 printf("%02X", little_endian_read_16(data, 0) );
198                 break;
199             case 0x1A: // Advertising Interval
200                 printf("%u ms", little_endian_read_16(data, 0) * 5/8 );
201                 break;
202             case 0x3D: // 3D Information Data
203                 printf_hexdump(data, size);
204                 break;
205             case 0xFF: // Manufacturer Specific Data
206                 break;
207             case 0x0D: // Class of Device (3B)
208             case 0x0E: // Simple Pairing Hash C (16B)
209             case 0x0F: // Simple Pairing Randomizer R (16B)
210             case 0x10: // Device ID
211             case 0x11: // Security Manager TK Value (16B)
212             default:
213                 printf("Unknown Advertising Data Type");
214                 break;
215         }
216         printf("\n");
217     }
218     printf("\n");
219 }
220 /* LISTING_END */
221 
222 /* @section HCI packet handler
223  *
224  * @text The HCI packet handler has to start the scanning,
225  * and to handle received advertisements. Advertisements are received
226  * as HCI event packets of the GAP_EVENT_ADVERTISING_REPORT type,
227  * see Listing GAPLEAdvPacketHandler.
228  */
229 
230 /* LISTING_START(GAPLEAdvPacketHandler): Scanning and receiving advertisements */
231 
232 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
233     if (packet_type != HCI_EVENT_PACKET) return;
234 
235     switch (hci_event_packet_get_type(packet)) {
236         case BTSTACK_EVENT_STATE:
237             // BTstack activated, get started
238             if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
239                 printf("Start scaning!\n");
240                 gap_set_scan_parameters(0,0x0030, 0x0030);
241                 gap_start_scan();
242             }
243             break;
244         case GAP_EVENT_ADVERTISING_REPORT:{
245             bd_addr_t address;
246             gap_event_advertising_report_get_address(packet, address);
247             uint8_t event_type = gap_event_advertising_report_get_advertising_event_type(packet);
248             uint8_t address_type = gap_event_advertising_report_get_address_type(packet);
249             int8_t rssi = gap_event_advertising_report_get_rssi(packet);
250             uint8_t length = gap_event_advertising_report_get_data_length(packet);
251             const uint8_t * data = gap_event_advertising_report_get_data(packet);
252 
253             printf("Advertisement event: evt-type %u, addr-type %u, addr %s, rssi %d, data[%u] ", event_type,
254                address_type, bd_addr_to_str(address), rssi, length);
255             printf_hexdump(data, length);
256             dump_advertisement_data(data, length);
257             break;
258         }
259         default:
260             break;
261     }
262 }
263 /* LISTING_END */
264 
265 int btstack_main(void);
266 int btstack_main(void)
267 {
268     gap_le_advertisements_setup();
269 
270     // turn on!
271     hci_power_control(HCI_POWER_ON);
272 
273     return 0;
274 }
275 
276 /* EXAMPLE_END */