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