xref: /btstack/example/gap_le_advertisements.c (revision e6c9673776c7f85e24c76da7f4b1b83031102d2b)
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 #define __BTSTACK_FILE__ "gap_le_advertisements.c"
39 
40 
41 // *****************************************************************************
42 /* EXAMPLE_START(gap_le_advertisements): GAP LE Advertisements Dumper
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     hci_event_callback_registration.callback = &packet_handler;
72     hci_add_event_handler(&hci_event_callback_registration);
73     // Active scanning, 100% (scan interval = scan window)
74     gap_set_scan_parameters(1,48,48);
75 }
76 
77 /* LISTING_END */
78 
79 /* @section GAP LE Advertising Data Dumper
80  *
81  * @text Here, we use the definition of advertising data types and flags as specified in
82  * [Assigned Numbers GAP](https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile)
83  * and [Supplement to the Bluetooth Core Specification, v4](https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=282152).
84  */
85 
86 /* LISTING_START(GAPLEAdvDataTypesAndFlags): Advertising data types and flags */
87 static char * ad_types[] = {
88     "",
89     "Flags",
90     "Incomplete List of 16-bit Service Class UUIDs",
91     "Complete List of 16-bit Service Class UUIDs",
92     "Incomplete List of 32-bit Service Class UUIDs",
93     "Complete List of 32-bit Service Class UUIDs",
94     "Incomplete List of 128-bit Service Class UUIDs",
95     "Complete List of 128-bit Service Class UUIDs",
96     "Shortened Local Name",
97     "Complete Local Name",
98     "Tx Power Level",
99     "",
100     "",
101     "Class of Device",
102     "Simple Pairing Hash C",
103     "Simple Pairing Randomizer R",
104     "Device ID",
105     "Security Manager TK Value",
106     "Slave Connection Interval Range",
107     "",
108     "List of 16-bit Service Solicitation UUIDs",
109     "List of 128-bit Service Solicitation UUIDs",
110     "Service Data",
111     "Public Target Address",
112     "Random Target Address",
113     "Appearance",
114     "Advertising Interval"
115 };
116 
117 static char * flags[] = {
118     "LE Limited Discoverable Mode",
119     "LE General Discoverable Mode",
120     "BR/EDR Not Supported",
121     "Simultaneous LE and BR/EDR to Same Device Capable (Controller)",
122     "Simultaneous LE and BR/EDR to Same Device Capable (Host)",
123     "Reserved",
124     "Reserved",
125     "Reserved"
126 };
127 /* LISTING_END */
128 
129 /* @text BTstack offers an iterator for parsing sequence of advertising data (AD) structures,
130  * see [BLE advertisements parser API](../appendix/apis/#ble-advertisements-parser-api).
131  * After initializing the iterator, each AD structure is dumped according to its type.
132  */
133 
134 /* LISTING_START(GAPLEAdvDataParsing): Parsing advertising data */
135 static void dump_advertisement_data(const uint8_t * adv_data, uint8_t adv_size){
136     ad_context_t context;
137     bd_addr_t address;
138     uint8_t uuid_128[16];
139     for (ad_iterator_init(&context, adv_size, (uint8_t *)adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
140         uint8_t data_type    = ad_iterator_get_data_type(&context);
141         uint8_t size         = ad_iterator_get_data_len(&context);
142         const uint8_t * data = ad_iterator_get_data(&context);
143 
144         if (data_type > 0 && data_type < 0x1B){
145             printf("    %s: ", ad_types[data_type]);
146         }
147         int i;
148         // Assigned Numbers GAP
149 
150         switch (data_type){
151             case BLUETOOTH_DATA_TYPE_FLAGS:
152                 // show only first octet, ignore rest
153                 for (i=0; i<8;i++){
154                     if (data[0] & (1<<i)){
155                         printf("%s; ", flags[i]);
156                     }
157 
158                 }
159                 break;
160             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS:
161             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS:
162             case BLUETOOTH_DATA_TYPE_LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS:
163                 for (i=0; i<size;i+=2){
164                     printf("%02X ", little_endian_read_16(data, i));
165                 }
166                 break;
167             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS:
168             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS:
169             case BLUETOOTH_DATA_TYPE_LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS:
170                 for (i=0; i<size;i+=4){
171                     printf("%04"PRIX32, little_endian_read_32(data, i));
172                 }
173                 break;
174             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS:
175             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS:
176             case BLUETOOTH_DATA_TYPE_LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS:
177                 reverse_128(data, uuid_128);
178                 printf("%s", uuid128_to_str(uuid_128));
179                 break;
180             case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME:
181             case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME:
182                 for (i=0; i<size;i++){
183                     printf("%c", (char)(data[i]));
184                 }
185                 break;
186             case BLUETOOTH_DATA_TYPE_TX_POWER_LEVEL:
187                 printf("%d dBm", *(int8_t*)data);
188                 break;
189             case BLUETOOTH_DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE:
190                 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);
191                 break;
192             case BLUETOOTH_DATA_TYPE_SERVICE_DATA:
193                 printf_hexdump(data, size);
194                 break;
195             case BLUETOOTH_DATA_TYPE_PUBLIC_TARGET_ADDRESS:
196             case BLUETOOTH_DATA_TYPE_RANDOM_TARGET_ADDRESS:
197                 reverse_bd_addr(data, address);
198                 printf("%s", bd_addr_to_str(address));
199                 break;
200             case BLUETOOTH_DATA_TYPE_APPEARANCE:
201                 // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
202                 printf("%02X", little_endian_read_16(data, 0) );
203                 break;
204             case BLUETOOTH_DATA_TYPE_ADVERTISING_INTERVAL:
205                 printf("%u ms", little_endian_read_16(data, 0) * 5/8 );
206                 break;
207             case BLUETOOTH_DATA_TYPE_3D_INFORMATION_DATA:
208                 printf_hexdump(data, size);
209                 break;
210             case BLUETOOTH_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA: // Manufacturer Specific Data
211                 break;
212             case BLUETOOTH_DATA_TYPE_CLASS_OF_DEVICE:
213             case BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_HASH_C:
214             case BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R:
215             case BLUETOOTH_DATA_TYPE_DEVICE_ID:
216             case BLUETOOTH_DATA_TYPE_SECURITY_MANAGER_OUT_OF_BAND_FLAGS:
217             default:
218                 printf("Advertising Data Type 0x%2x not handled yet", data_type);
219                 break;
220         }
221         printf("\n");
222     }
223     printf("\n");
224 }
225 /* LISTING_END */
226 
227 /* @section HCI packet handler
228  *
229  * @text The HCI packet handler has to start the scanning,
230  * and to handle received advertisements. Advertisements are received
231  * as HCI event packets of the GAP_EVENT_ADVERTISING_REPORT type,
232  * see Listing GAPLEAdvPacketHandler.
233  */
234 
235 /* LISTING_START(GAPLEAdvPacketHandler): Scanning and receiving advertisements */
236 
237 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
238     UNUSED(channel);
239     UNUSED(size);
240 
241     if (packet_type != HCI_EVENT_PACKET) return;
242 
243     switch (hci_event_packet_get_type(packet)) {
244         case BTSTACK_EVENT_STATE:
245             // BTstack activated, get started
246             if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
247                 printf("Start scaning!\n");
248                 gap_set_scan_parameters(0,0x0030, 0x0030);
249                 gap_start_scan();
250             }
251             break;
252         case GAP_EVENT_ADVERTISING_REPORT:{
253             bd_addr_t address;
254             gap_event_advertising_report_get_address(packet, address);
255             uint8_t event_type = gap_event_advertising_report_get_advertising_event_type(packet);
256             uint8_t address_type = gap_event_advertising_report_get_address_type(packet);
257             int8_t rssi = gap_event_advertising_report_get_rssi(packet);
258             uint8_t length = gap_event_advertising_report_get_data_length(packet);
259             const uint8_t * data = gap_event_advertising_report_get_data(packet);
260 
261             printf("Advertisement event: evt-type %u, addr-type %u, addr %s, rssi %d, data[%u] ", event_type,
262                address_type, bd_addr_to_str(address), rssi, length);
263             printf_hexdump(data, length);
264             dump_advertisement_data(data, length);
265             break;
266         }
267         default:
268             break;
269     }
270 }
271 /* LISTING_END */
272 
273 int btstack_main(void);
274 int btstack_main(void)
275 {
276     gap_le_advertisements_setup();
277 
278     // turn on!
279     hci_power_control(HCI_POWER_ON);
280 
281     return 0;
282 }
283 
284 /* EXAMPLE_END */