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