xref: /btstack/example/gap_le_advertisements.c (revision bcf00d8fa453bd3a5c441c3b99e6e4b685f0d8f0)
1*bcf00d8fSMatthias Ringwald /*
2*bcf00d8fSMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*bcf00d8fSMatthias Ringwald  *
4*bcf00d8fSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*bcf00d8fSMatthias Ringwald  * modification, are permitted provided that the following conditions
6*bcf00d8fSMatthias Ringwald  * are met:
7*bcf00d8fSMatthias Ringwald  *
8*bcf00d8fSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*bcf00d8fSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*bcf00d8fSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*bcf00d8fSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*bcf00d8fSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*bcf00d8fSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*bcf00d8fSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*bcf00d8fSMatthias Ringwald  *    from this software without specific prior written permission.
16*bcf00d8fSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*bcf00d8fSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*bcf00d8fSMatthias Ringwald  *    monetary gain.
19*bcf00d8fSMatthias Ringwald  *
20*bcf00d8fSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*bcf00d8fSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*bcf00d8fSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*bcf00d8fSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*bcf00d8fSMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*bcf00d8fSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*bcf00d8fSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*bcf00d8fSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*bcf00d8fSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*bcf00d8fSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*bcf00d8fSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*bcf00d8fSMatthias Ringwald  * SUCH DAMAGE.
32*bcf00d8fSMatthias Ringwald  *
33*bcf00d8fSMatthias Ringwald  * Please inquire about commercial licensing options at
34*bcf00d8fSMatthias Ringwald  * [email protected]
35*bcf00d8fSMatthias Ringwald  *
36*bcf00d8fSMatthias Ringwald  */
37*bcf00d8fSMatthias Ringwald 
38*bcf00d8fSMatthias Ringwald 
39*bcf00d8fSMatthias Ringwald // *****************************************************************************
40*bcf00d8fSMatthias Ringwald /* EXAMPLE_START(gap_le_advertisements): GAP LE Advertisements Dumper
41*bcf00d8fSMatthias Ringwald  *
42*bcf00d8fSMatthias Ringwald  * @text This example shows how to scan and parse advertisements.
43*bcf00d8fSMatthias Ringwald  *
44*bcf00d8fSMatthias Ringwald  */
45*bcf00d8fSMatthias Ringwald  // *****************************************************************************
46*bcf00d8fSMatthias Ringwald 
47*bcf00d8fSMatthias Ringwald 
48*bcf00d8fSMatthias Ringwald #include <stdint.h>
49*bcf00d8fSMatthias Ringwald #include <stdio.h>
50*bcf00d8fSMatthias Ringwald #include <stdlib.h>
51*bcf00d8fSMatthias Ringwald #include <string.h>
52*bcf00d8fSMatthias Ringwald 
53*bcf00d8fSMatthias Ringwald #include "hci_cmd.h"
54*bcf00d8fSMatthias Ringwald 
55*bcf00d8fSMatthias Ringwald #include "btstack_memory.h"
56*bcf00d8fSMatthias Ringwald #include "hci.h"
57*bcf00d8fSMatthias Ringwald #include "ble/ad_parser.h"
58*bcf00d8fSMatthias Ringwald 
59*bcf00d8fSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
60*bcf00d8fSMatthias Ringwald 
61*bcf00d8fSMatthias Ringwald /* @section GAP LE setup for receiving advertisements
62*bcf00d8fSMatthias Ringwald  *
63*bcf00d8fSMatthias Ringwald  * @text GAP LE advertisements are received as custom HCI events of the
64*bcf00d8fSMatthias Ringwald  * GAP_LE_EVENT_ADVERTISING_REPORT type. To receive them, you'll need to register
65*bcf00d8fSMatthias Ringwald  * the HCI packet handler, as shown in Listing GAPLEAdvSetup.
66*bcf00d8fSMatthias Ringwald  */
67*bcf00d8fSMatthias Ringwald 
68*bcf00d8fSMatthias Ringwald /* LISTING_START(GAPLEAdvSetup): Setting up GAP LE client for receiving advertisements */
69*bcf00d8fSMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
70*bcf00d8fSMatthias Ringwald 
71*bcf00d8fSMatthias Ringwald static void gap_le_advertisements_setup(void){
72*bcf00d8fSMatthias Ringwald     hci_event_callback_registration.callback = &packet_handler;
73*bcf00d8fSMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
74*bcf00d8fSMatthias Ringwald }
75*bcf00d8fSMatthias Ringwald 
76*bcf00d8fSMatthias Ringwald /* LISTING_END */
77*bcf00d8fSMatthias Ringwald 
78*bcf00d8fSMatthias Ringwald /* @section GAP LE Advertising Data Dumper
79*bcf00d8fSMatthias Ringwald  *
80*bcf00d8fSMatthias Ringwald  * @text Here, we use the definition of advertising data types and flags as specified in
81*bcf00d8fSMatthias Ringwald  * [Assigned Numbers GAP](https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile)
82*bcf00d8fSMatthias Ringwald  * and [Supplement to the Bluetooth Core Specification, v4](https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=282152).
83*bcf00d8fSMatthias Ringwald  */
84*bcf00d8fSMatthias Ringwald 
85*bcf00d8fSMatthias Ringwald /* LISTING_START(GAPLEAdvDataTypesAndFlags): Advertising data types and flags */
86*bcf00d8fSMatthias Ringwald static char * ad_types[] = {
87*bcf00d8fSMatthias Ringwald     "",
88*bcf00d8fSMatthias Ringwald     "Flags",
89*bcf00d8fSMatthias Ringwald     "Incomplete List of 16-bit Service Class UUIDs",
90*bcf00d8fSMatthias Ringwald     "Complete List of 16-bit Service Class UUIDs",
91*bcf00d8fSMatthias Ringwald     "Incomplete List of 32-bit Service Class UUIDs",
92*bcf00d8fSMatthias Ringwald     "Complete List of 32-bit Service Class UUIDs",
93*bcf00d8fSMatthias Ringwald     "Incomplete List of 128-bit Service Class UUIDs",
94*bcf00d8fSMatthias Ringwald     "Complete List of 128-bit Service Class UUIDs",
95*bcf00d8fSMatthias Ringwald     "Shortened Local Name",
96*bcf00d8fSMatthias Ringwald     "Complete Local Name",
97*bcf00d8fSMatthias Ringwald     "Tx Power Level",
98*bcf00d8fSMatthias Ringwald     "",
99*bcf00d8fSMatthias Ringwald     "",
100*bcf00d8fSMatthias Ringwald     "Class of Device",
101*bcf00d8fSMatthias Ringwald     "Simple Pairing Hash C",
102*bcf00d8fSMatthias Ringwald     "Simple Pairing Randomizer R",
103*bcf00d8fSMatthias Ringwald     "Device ID",
104*bcf00d8fSMatthias Ringwald     "Security Manager TK Value",
105*bcf00d8fSMatthias Ringwald     "Slave Connection Interval Range",
106*bcf00d8fSMatthias Ringwald     "",
107*bcf00d8fSMatthias Ringwald     "List of 16-bit Service Solicitation UUIDs",
108*bcf00d8fSMatthias Ringwald     "List of 128-bit Service Solicitation UUIDs",
109*bcf00d8fSMatthias Ringwald     "Service Data",
110*bcf00d8fSMatthias Ringwald     "Public Target Address",
111*bcf00d8fSMatthias Ringwald     "Random Target Address",
112*bcf00d8fSMatthias Ringwald     "Appearance",
113*bcf00d8fSMatthias Ringwald     "Advertising Interval"
114*bcf00d8fSMatthias Ringwald };
115*bcf00d8fSMatthias Ringwald 
116*bcf00d8fSMatthias Ringwald static char * flags[] = {
117*bcf00d8fSMatthias Ringwald     "LE Limited Discoverable Mode",
118*bcf00d8fSMatthias Ringwald     "LE General Discoverable Mode",
119*bcf00d8fSMatthias Ringwald     "BR/EDR Not Supported",
120*bcf00d8fSMatthias Ringwald     "Simultaneous LE and BR/EDR to Same Device Capable (Controller)",
121*bcf00d8fSMatthias Ringwald     "Simultaneous LE and BR/EDR to Same Device Capable (Host)",
122*bcf00d8fSMatthias Ringwald     "Reserved",
123*bcf00d8fSMatthias Ringwald     "Reserved",
124*bcf00d8fSMatthias Ringwald     "Reserved"
125*bcf00d8fSMatthias Ringwald };
126*bcf00d8fSMatthias Ringwald /* LISTING_END */
127*bcf00d8fSMatthias Ringwald 
128*bcf00d8fSMatthias Ringwald /* @text BTstack offers an iterator for parsing sequence of advertising data (AD) structures,
129*bcf00d8fSMatthias Ringwald  * see [BLE advertisements parser API](../appendix/apis/#ble-advertisements-parser-api).
130*bcf00d8fSMatthias Ringwald  * After initializing the iterator, each AD structure is dumped according to its type.
131*bcf00d8fSMatthias Ringwald  */
132*bcf00d8fSMatthias Ringwald 
133*bcf00d8fSMatthias Ringwald /* LISTING_START(GAPLEAdvDataParsing): Parsing advertising data */
134*bcf00d8fSMatthias Ringwald static void dump_advertisement_data(uint8_t * adv_data, uint8_t adv_size){
135*bcf00d8fSMatthias Ringwald     ad_context_t context;
136*bcf00d8fSMatthias Ringwald     bd_addr_t address;
137*bcf00d8fSMatthias Ringwald     uint8_t uuid_128[16];
138*bcf00d8fSMatthias Ringwald     for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
139*bcf00d8fSMatthias Ringwald         uint8_t data_type = ad_iterator_get_data_type(&context);
140*bcf00d8fSMatthias Ringwald         uint8_t size      = ad_iterator_get_data_len(&context);
141*bcf00d8fSMatthias Ringwald         uint8_t * data    = ad_iterator_get_data(&context);
142*bcf00d8fSMatthias Ringwald 
143*bcf00d8fSMatthias Ringwald         if (data_type > 0 && data_type < 0x1B){
144*bcf00d8fSMatthias Ringwald             printf("    %s: ", ad_types[data_type]);
145*bcf00d8fSMatthias Ringwald         }
146*bcf00d8fSMatthias Ringwald         int i;
147*bcf00d8fSMatthias Ringwald         // Assigned Numbers GAP
148*bcf00d8fSMatthias Ringwald 
149*bcf00d8fSMatthias Ringwald         switch (data_type){
150*bcf00d8fSMatthias Ringwald             case 0x01: // Flags
151*bcf00d8fSMatthias Ringwald                 // show only first octet, ignore rest
152*bcf00d8fSMatthias Ringwald                 for (i=0; i<8;i++){
153*bcf00d8fSMatthias Ringwald                     if (data[0] & (1<<i)){
154*bcf00d8fSMatthias Ringwald                         printf("%s; ", flags[i]);
155*bcf00d8fSMatthias Ringwald                     }
156*bcf00d8fSMatthias Ringwald 
157*bcf00d8fSMatthias Ringwald                 }
158*bcf00d8fSMatthias Ringwald                 break;
159*bcf00d8fSMatthias Ringwald             case 0x02: // Incomplete List of 16-bit Service Class UUIDs
160*bcf00d8fSMatthias Ringwald             case 0x03: // Complete List of 16-bit Service Class UUIDs
161*bcf00d8fSMatthias Ringwald             case 0x14: // List of 16-bit Service Solicitation UUIDs
162*bcf00d8fSMatthias Ringwald                 for (i=0; i<size;i+=2){
163*bcf00d8fSMatthias Ringwald                     printf("%02X ", little_endian_read_16(data, i));
164*bcf00d8fSMatthias Ringwald                 }
165*bcf00d8fSMatthias Ringwald                 break;
166*bcf00d8fSMatthias Ringwald             case 0x04: // Incomplete List of 32-bit Service Class UUIDs
167*bcf00d8fSMatthias Ringwald             case 0x05: // Complete List of 32-bit Service Class UUIDs
168*bcf00d8fSMatthias Ringwald                 for (i=0; i<size;i+=4){
169*bcf00d8fSMatthias Ringwald                     printf("%04X ", little_endian_read_32(data, i));
170*bcf00d8fSMatthias Ringwald                 }
171*bcf00d8fSMatthias Ringwald                 break;
172*bcf00d8fSMatthias Ringwald             case 0x06: // Incomplete List of 128-bit Service Class UUIDs
173*bcf00d8fSMatthias Ringwald             case 0x07: // Complete List of 128-bit Service Class UUIDs
174*bcf00d8fSMatthias Ringwald             case 0x15: // List of 128-bit Service Solicitation UUIDs
175*bcf00d8fSMatthias Ringwald                 reverse_128(data, uuid_128);
176*bcf00d8fSMatthias Ringwald                 printf("%s", uuid128_to_str(uuid_128));
177*bcf00d8fSMatthias Ringwald                 break;
178*bcf00d8fSMatthias Ringwald             case 0x08: // Shortened Local Name
179*bcf00d8fSMatthias Ringwald             case 0x09: // Complete Local Name
180*bcf00d8fSMatthias Ringwald                 for (i=0; i<size;i++){
181*bcf00d8fSMatthias Ringwald                     printf("%c", (char)(data[i]));
182*bcf00d8fSMatthias Ringwald                 }
183*bcf00d8fSMatthias Ringwald                 break;
184*bcf00d8fSMatthias Ringwald             case 0x0A: // Tx Power Level
185*bcf00d8fSMatthias Ringwald                 printf("%d dBm", *(int8_t*)data);
186*bcf00d8fSMatthias Ringwald                 break;
187*bcf00d8fSMatthias Ringwald             case 0x12: // Slave Connection Interval Range
188*bcf00d8fSMatthias 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);
189*bcf00d8fSMatthias Ringwald                 break;
190*bcf00d8fSMatthias Ringwald             case 0x16: // Service Data
191*bcf00d8fSMatthias Ringwald                 printf_hexdump(data, size);
192*bcf00d8fSMatthias Ringwald                 break;
193*bcf00d8fSMatthias Ringwald             case 0x17: // Public Target Address
194*bcf00d8fSMatthias Ringwald             case 0x18: // Random Target Address
195*bcf00d8fSMatthias Ringwald                 reverse_bd_addr(data, address);
196*bcf00d8fSMatthias Ringwald                 printf("%s", bd_addr_to_str(address));
197*bcf00d8fSMatthias Ringwald                 break;
198*bcf00d8fSMatthias Ringwald             case 0x19: // Appearance
199*bcf00d8fSMatthias Ringwald                 // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
200*bcf00d8fSMatthias Ringwald                 printf("%02X", little_endian_read_16(data, 0) );
201*bcf00d8fSMatthias Ringwald                 break;
202*bcf00d8fSMatthias Ringwald             case 0x1A: // Advertising Interval
203*bcf00d8fSMatthias Ringwald                 printf("%u ms", little_endian_read_16(data, 0) * 5/8 );
204*bcf00d8fSMatthias Ringwald                 break;
205*bcf00d8fSMatthias Ringwald             case 0x3D: // 3D Information Data
206*bcf00d8fSMatthias Ringwald                 printf_hexdump(data, size);
207*bcf00d8fSMatthias Ringwald                 break;
208*bcf00d8fSMatthias Ringwald             case 0xFF: // Manufacturer Specific Data
209*bcf00d8fSMatthias Ringwald                 break;
210*bcf00d8fSMatthias Ringwald             case 0x0D: // Class of Device (3B)
211*bcf00d8fSMatthias Ringwald             case 0x0E: // Simple Pairing Hash C (16B)
212*bcf00d8fSMatthias Ringwald             case 0x0F: // Simple Pairing Randomizer R (16B)
213*bcf00d8fSMatthias Ringwald             case 0x10: // Device ID
214*bcf00d8fSMatthias Ringwald             case 0x11: // Security Manager TK Value (16B)
215*bcf00d8fSMatthias Ringwald             default:
216*bcf00d8fSMatthias Ringwald                 printf("Unknown Advertising Data Type");
217*bcf00d8fSMatthias Ringwald                 break;
218*bcf00d8fSMatthias Ringwald         }
219*bcf00d8fSMatthias Ringwald         printf("\n");
220*bcf00d8fSMatthias Ringwald     }
221*bcf00d8fSMatthias Ringwald     printf("\n");
222*bcf00d8fSMatthias Ringwald }
223*bcf00d8fSMatthias Ringwald /* LISTING_END */
224*bcf00d8fSMatthias Ringwald 
225*bcf00d8fSMatthias Ringwald /* @section HCI packet handler
226*bcf00d8fSMatthias Ringwald  *
227*bcf00d8fSMatthias Ringwald  * @text The HCI packet handler has to start the scanning,
228*bcf00d8fSMatthias Ringwald  * and to handle received advertisements. Advertisements are received
229*bcf00d8fSMatthias Ringwald  * as HCI event packets of the GAP_LE_EVENT_ADVERTISING_REPORT type,
230*bcf00d8fSMatthias Ringwald  * see Listing GAPLEAdvPacketHandler.
231*bcf00d8fSMatthias Ringwald  */
232*bcf00d8fSMatthias Ringwald 
233*bcf00d8fSMatthias Ringwald /* LISTING_START(GAPLEAdvPacketHandler): Scanning and receiving advertisements */
234*bcf00d8fSMatthias Ringwald 
235*bcf00d8fSMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
236*bcf00d8fSMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
237*bcf00d8fSMatthias Ringwald 
238*bcf00d8fSMatthias Ringwald     switch (packet[0]) {
239*bcf00d8fSMatthias Ringwald         case BTSTACK_EVENT_STATE:
240*bcf00d8fSMatthias Ringwald             // BTstack activated, get started
241*bcf00d8fSMatthias Ringwald             if (packet[2] == HCI_STATE_WORKING) {
242*bcf00d8fSMatthias Ringwald                 printf("BTstack activated, start scaning!\n");
243*bcf00d8fSMatthias Ringwald                 gap_set_scan_parameters(0,0x0030, 0x0030);
244*bcf00d8fSMatthias Ringwald                 gap_start_scan();
245*bcf00d8fSMatthias Ringwald             }
246*bcf00d8fSMatthias Ringwald             break;
247*bcf00d8fSMatthias Ringwald         case GAP_LE_EVENT_ADVERTISING_REPORT:{
248*bcf00d8fSMatthias Ringwald             int pos = 2;
249*bcf00d8fSMatthias Ringwald             uint8_t event_type = packet[pos++];
250*bcf00d8fSMatthias Ringwald             uint8_t address_type = packet[pos++];
251*bcf00d8fSMatthias Ringwald             bd_addr_t address;
252*bcf00d8fSMatthias Ringwald             reverse_bd_addr(&packet[pos], address);
253*bcf00d8fSMatthias Ringwald             pos += 6;
254*bcf00d8fSMatthias Ringwald             uint8_t rssi = packet[pos++];
255*bcf00d8fSMatthias Ringwald             uint8_t length = packet[pos++];
256*bcf00d8fSMatthias Ringwald             uint8_t * data = &packet[pos];
257*bcf00d8fSMatthias Ringwald 
258*bcf00d8fSMatthias Ringwald             printf("Advertisement event: evt-type %u, addr-type %u, addr %s, rssi %u, data[%u] ", event_type,
259*bcf00d8fSMatthias Ringwald                address_type, bd_addr_to_str(address), rssi, length);
260*bcf00d8fSMatthias Ringwald             printf_hexdump(data, length);
261*bcf00d8fSMatthias Ringwald             dump_advertisement_data(data, length);
262*bcf00d8fSMatthias Ringwald             break;
263*bcf00d8fSMatthias Ringwald         }
264*bcf00d8fSMatthias Ringwald         default:
265*bcf00d8fSMatthias Ringwald             break;
266*bcf00d8fSMatthias Ringwald     }
267*bcf00d8fSMatthias Ringwald }
268*bcf00d8fSMatthias Ringwald /* LISTING_END */
269*bcf00d8fSMatthias Ringwald 
270*bcf00d8fSMatthias Ringwald int btstack_main(void);
271*bcf00d8fSMatthias Ringwald int btstack_main(void)
272*bcf00d8fSMatthias Ringwald {
273*bcf00d8fSMatthias Ringwald     gap_le_advertisements_setup();
274*bcf00d8fSMatthias Ringwald 
275*bcf00d8fSMatthias Ringwald     // turn on!
276*bcf00d8fSMatthias Ringwald     hci_power_control(HCI_POWER_ON);
277*bcf00d8fSMatthias Ringwald 
278*bcf00d8fSMatthias Ringwald     return 0;
279*bcf00d8fSMatthias Ringwald }
280*bcf00d8fSMatthias Ringwald 
281*bcf00d8fSMatthias Ringwald /* EXAMPLE_END */