xref: /btstack/example/gap_inquiry.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 /* EXAMPLE_START(gap_inquiry): GAP Inquiry Example
40*bcf00d8fSMatthias Ringwald  *
41*bcf00d8fSMatthias Ringwald  * @text The Generic Access Profile (GAP) defines how Bluetooth devices discover
42*bcf00d8fSMatthias Ringwald  * and establish a connection with each other. In this example, the application
43*bcf00d8fSMatthias Ringwald  * discovers  surrounding Bluetooth devices and collects their Class of Device
44*bcf00d8fSMatthias Ringwald  * (CoD), page scan mode, clock offset, and RSSI. After that, the remote name of
45*bcf00d8fSMatthias Ringwald  * each device is requested. In the following section we outline the Bluetooth
46*bcf00d8fSMatthias Ringwald  * logic part, i.e., how the packet handler handles the asynchronous events and
47*bcf00d8fSMatthias Ringwald  * data packets.
48*bcf00d8fSMatthias Ringwald  */
49*bcf00d8fSMatthias Ringwald // *****************************************************************************
50*bcf00d8fSMatthias Ringwald 
51*bcf00d8fSMatthias Ringwald #include <stdint.h>
52*bcf00d8fSMatthias Ringwald #include <stdio.h>
53*bcf00d8fSMatthias Ringwald #include <stdlib.h>
54*bcf00d8fSMatthias Ringwald #include <string.h>
55*bcf00d8fSMatthias Ringwald 
56*bcf00d8fSMatthias Ringwald #include "btstack_config.h"
57*bcf00d8fSMatthias Ringwald 
58*bcf00d8fSMatthias Ringwald #include "btstack_run_loop.h"
59*bcf00d8fSMatthias Ringwald 
60*bcf00d8fSMatthias Ringwald #include "btstack_debug.h"
61*bcf00d8fSMatthias Ringwald #include "btstack_memory.h"
62*bcf00d8fSMatthias Ringwald #include "hci.h"
63*bcf00d8fSMatthias Ringwald #include "hci_dump.h"
64*bcf00d8fSMatthias Ringwald 
65*bcf00d8fSMatthias Ringwald #include "classic/sdp_util.h"
66*bcf00d8fSMatthias Ringwald 
67*bcf00d8fSMatthias Ringwald #define MAX_DEVICES 10
68*bcf00d8fSMatthias Ringwald enum DEVICE_STATE { REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, REMOTE_NAME_FETCHED };
69*bcf00d8fSMatthias Ringwald struct device {
70*bcf00d8fSMatthias Ringwald     bd_addr_t  address;
71*bcf00d8fSMatthias Ringwald     uint16_t   clockOffset;
72*bcf00d8fSMatthias Ringwald     uint32_t   classOfDevice;
73*bcf00d8fSMatthias Ringwald     uint8_t    pageScanRepetitionMode;
74*bcf00d8fSMatthias Ringwald     uint8_t    rssi;
75*bcf00d8fSMatthias Ringwald     enum DEVICE_STATE  state;
76*bcf00d8fSMatthias Ringwald };
77*bcf00d8fSMatthias Ringwald 
78*bcf00d8fSMatthias Ringwald #define INQUIRY_INTERVAL 5
79*bcf00d8fSMatthias Ringwald struct device devices[MAX_DEVICES];
80*bcf00d8fSMatthias Ringwald int deviceCount = 0;
81*bcf00d8fSMatthias Ringwald 
82*bcf00d8fSMatthias Ringwald 
83*bcf00d8fSMatthias Ringwald enum STATE {INIT, ACTIVE} ;
84*bcf00d8fSMatthias Ringwald enum STATE state = INIT;
85*bcf00d8fSMatthias Ringwald 
86*bcf00d8fSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
87*bcf00d8fSMatthias Ringwald 
88*bcf00d8fSMatthias Ringwald static int getDeviceIndexForAddress( bd_addr_t addr){
89*bcf00d8fSMatthias Ringwald     int j;
90*bcf00d8fSMatthias Ringwald     for (j=0; j< deviceCount; j++){
91*bcf00d8fSMatthias Ringwald         if (bd_addr_cmp(addr, devices[j].address) == 0){
92*bcf00d8fSMatthias Ringwald             return j;
93*bcf00d8fSMatthias Ringwald         }
94*bcf00d8fSMatthias Ringwald     }
95*bcf00d8fSMatthias Ringwald     return -1;
96*bcf00d8fSMatthias Ringwald }
97*bcf00d8fSMatthias Ringwald 
98*bcf00d8fSMatthias Ringwald static void start_scan(void){
99*bcf00d8fSMatthias Ringwald     printf("Starting inquiry scan..\n");
100*bcf00d8fSMatthias Ringwald     hci_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0);
101*bcf00d8fSMatthias Ringwald }
102*bcf00d8fSMatthias Ringwald 
103*bcf00d8fSMatthias Ringwald static int has_more_remote_name_requests(void){
104*bcf00d8fSMatthias Ringwald     int i;
105*bcf00d8fSMatthias Ringwald     for (i=0;i<deviceCount;i++) {
106*bcf00d8fSMatthias Ringwald         if (devices[i].state == REMOTE_NAME_REQUEST) return 1;
107*bcf00d8fSMatthias Ringwald     }
108*bcf00d8fSMatthias Ringwald     return 0;
109*bcf00d8fSMatthias Ringwald }
110*bcf00d8fSMatthias Ringwald 
111*bcf00d8fSMatthias Ringwald static void do_next_remote_name_request(void){
112*bcf00d8fSMatthias Ringwald     int i;
113*bcf00d8fSMatthias Ringwald     for (i=0;i<deviceCount;i++) {
114*bcf00d8fSMatthias Ringwald         // remote name request
115*bcf00d8fSMatthias Ringwald         if (devices[i].state == REMOTE_NAME_REQUEST){
116*bcf00d8fSMatthias Ringwald             devices[i].state = REMOTE_NAME_INQUIRED;
117*bcf00d8fSMatthias Ringwald             printf("Get remote name of %s...\n", bd_addr_to_str(devices[i].address));
118*bcf00d8fSMatthias Ringwald             hci_send_cmd(&hci_remote_name_request, devices[i].address,
119*bcf00d8fSMatthias Ringwald                         devices[i].pageScanRepetitionMode, 0, devices[i].clockOffset | 0x8000);
120*bcf00d8fSMatthias Ringwald             return;
121*bcf00d8fSMatthias Ringwald         }
122*bcf00d8fSMatthias Ringwald     }
123*bcf00d8fSMatthias Ringwald }
124*bcf00d8fSMatthias Ringwald 
125*bcf00d8fSMatthias Ringwald static void continue_remote_names(void){
126*bcf00d8fSMatthias Ringwald     if (has_more_remote_name_requests()){
127*bcf00d8fSMatthias Ringwald         do_next_remote_name_request();
128*bcf00d8fSMatthias Ringwald         return;
129*bcf00d8fSMatthias Ringwald     }
130*bcf00d8fSMatthias Ringwald     start_scan();
131*bcf00d8fSMatthias Ringwald }
132*bcf00d8fSMatthias Ringwald 
133*bcf00d8fSMatthias Ringwald /* @section Bluetooth Logic
134*bcf00d8fSMatthias Ringwald  *
135*bcf00d8fSMatthias Ringwald  * @text The Bluetooth logic is implemented as a state machine within the packet
136*bcf00d8fSMatthias Ringwald  * handler. In this example, the following states are passed sequentially:
137*bcf00d8fSMatthias Ringwald  * INIT, and ACTIVE.
138*bcf00d8fSMatthias Ringwald  */
139*bcf00d8fSMatthias Ringwald 
140*bcf00d8fSMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
141*bcf00d8fSMatthias Ringwald     bd_addr_t addr;
142*bcf00d8fSMatthias Ringwald     int i;
143*bcf00d8fSMatthias Ringwald     int numResponses;
144*bcf00d8fSMatthias Ringwald     int index;
145*bcf00d8fSMatthias Ringwald 
146*bcf00d8fSMatthias Ringwald     // printf("packet_handler: pt: 0x%02x, packet[0]: 0x%02x\n", packet_type, packet[0]);
147*bcf00d8fSMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
148*bcf00d8fSMatthias Ringwald 
149*bcf00d8fSMatthias Ringwald     uint8_t event = packet[0];
150*bcf00d8fSMatthias Ringwald 
151*bcf00d8fSMatthias Ringwald     switch(state){
152*bcf00d8fSMatthias Ringwald         /* @text In INIT, an inquiry  scan is started, and the application transits to
153*bcf00d8fSMatthias Ringwald          * ACTIVE state.
154*bcf00d8fSMatthias Ringwald          */
155*bcf00d8fSMatthias Ringwald         case INIT:
156*bcf00d8fSMatthias Ringwald             if (packet[2] == HCI_STATE_WORKING) {
157*bcf00d8fSMatthias Ringwald                 start_scan();
158*bcf00d8fSMatthias Ringwald                 state = ACTIVE;
159*bcf00d8fSMatthias Ringwald             }
160*bcf00d8fSMatthias Ringwald             break;
161*bcf00d8fSMatthias Ringwald 
162*bcf00d8fSMatthias Ringwald         /* @text In ACTIVE, the following events are processed:
163*bcf00d8fSMatthias Ringwald          *  - Inquiry result event: the list of discovered devices is processed and the
164*bcf00d8fSMatthias Ringwald          *    Class of Device (CoD), page scan mode, clock offset, and RSSI are stored in a table.
165*bcf00d8fSMatthias Ringwald          *  - Inquiry complete event: the remote name is requested for devices without a fetched
166*bcf00d8fSMatthias Ringwald          *    name. The state of a remote name can be one of the following:
167*bcf00d8fSMatthias Ringwald          *    REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, or REMOTE_NAME_FETCHED.
168*bcf00d8fSMatthias Ringwald          *  - Remote name cached event: prints cached remote names provided by BTstack,
169*bcf00d8fSMatthias Ringwald          *    if persistent storage is provided.
170*bcf00d8fSMatthias Ringwald          *  - Remote name request complete event: the remote name is stored in the table and the
171*bcf00d8fSMatthias Ringwald          *    state is updated to REMOTE_NAME_FETCHED. The query of remote names is continued.
172*bcf00d8fSMatthias Ringwald          */
173*bcf00d8fSMatthias Ringwald         case ACTIVE:
174*bcf00d8fSMatthias Ringwald             switch(event){
175*bcf00d8fSMatthias Ringwald                 case HCI_EVENT_INQUIRY_RESULT:
176*bcf00d8fSMatthias Ringwald                 case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
177*bcf00d8fSMatthias Ringwald                     numResponses = packet[2];
178*bcf00d8fSMatthias Ringwald                     for (i=0; i<numResponses && deviceCount < MAX_DEVICES;i++){
179*bcf00d8fSMatthias Ringwald                         reverse_bd_addr(&packet[3 + i * 6], addr);
180*bcf00d8fSMatthias Ringwald                         index = getDeviceIndexForAddress(addr);
181*bcf00d8fSMatthias Ringwald                         if (index >= 0) continue;   // already in our list
182*bcf00d8fSMatthias Ringwald 
183*bcf00d8fSMatthias Ringwald                         memcpy(devices[deviceCount].address, addr, 6);
184*bcf00d8fSMatthias Ringwald                         devices[deviceCount].pageScanRepetitionMode =   packet [3 + numResponses*(6)         + i*1];
185*bcf00d8fSMatthias Ringwald                         if (event == HCI_EVENT_INQUIRY_RESULT){
186*bcf00d8fSMatthias Ringwald                             devices[deviceCount].classOfDevice = little_endian_read_24(packet, 3 + numResponses*(6+1+1+1)   + i*3);
187*bcf00d8fSMatthias Ringwald                             devices[deviceCount].clockOffset =   little_endian_read_16(packet, 3 + numResponses*(6+1+1+1+3) + i*2) & 0x7fff;
188*bcf00d8fSMatthias Ringwald                             devices[deviceCount].rssi  = 0;
189*bcf00d8fSMatthias Ringwald                         } else {
190*bcf00d8fSMatthias Ringwald                             devices[deviceCount].classOfDevice = little_endian_read_24(packet, 3 + numResponses*(6+1+1)     + i*3);
191*bcf00d8fSMatthias Ringwald                             devices[deviceCount].clockOffset =   little_endian_read_16(packet, 3 + numResponses*(6+1+1+3)   + i*2) & 0x7fff;
192*bcf00d8fSMatthias Ringwald                             devices[deviceCount].rssi  =                    packet [3 + numResponses*(6+1+1+3+2) + i*1];
193*bcf00d8fSMatthias Ringwald                         }
194*bcf00d8fSMatthias Ringwald                         devices[deviceCount].state = REMOTE_NAME_REQUEST;
195*bcf00d8fSMatthias Ringwald                         printf("Device found: %s with COD: 0x%06x, pageScan %d, clock offset 0x%04x, rssi 0x%02x\n", bd_addr_to_str(addr),
196*bcf00d8fSMatthias Ringwald                                 devices[deviceCount].classOfDevice, devices[deviceCount].pageScanRepetitionMode,
197*bcf00d8fSMatthias Ringwald                                 devices[deviceCount].clockOffset, devices[deviceCount].rssi);
198*bcf00d8fSMatthias Ringwald                         deviceCount++;
199*bcf00d8fSMatthias Ringwald                     }
200*bcf00d8fSMatthias Ringwald                     break;
201*bcf00d8fSMatthias Ringwald 
202*bcf00d8fSMatthias Ringwald                 case HCI_EVENT_INQUIRY_COMPLETE:
203*bcf00d8fSMatthias Ringwald                     for (i=0;i<deviceCount;i++) {
204*bcf00d8fSMatthias Ringwald                         // retry remote name request
205*bcf00d8fSMatthias Ringwald                         if (devices[i].state == REMOTE_NAME_INQUIRED)
206*bcf00d8fSMatthias Ringwald                             devices[i].state = REMOTE_NAME_REQUEST;
207*bcf00d8fSMatthias Ringwald                     }
208*bcf00d8fSMatthias Ringwald                     continue_remote_names();
209*bcf00d8fSMatthias Ringwald                     break;
210*bcf00d8fSMatthias Ringwald 
211*bcf00d8fSMatthias Ringwald                 case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
212*bcf00d8fSMatthias Ringwald                     reverse_bd_addr(&packet[3], addr);
213*bcf00d8fSMatthias Ringwald                     index = getDeviceIndexForAddress(addr);
214*bcf00d8fSMatthias Ringwald                     if (index >= 0) {
215*bcf00d8fSMatthias Ringwald                         if (packet[2] == 0) {
216*bcf00d8fSMatthias Ringwald                             printf("Name: '%s'\n", &packet[9]);
217*bcf00d8fSMatthias Ringwald                             devices[index].state = REMOTE_NAME_FETCHED;
218*bcf00d8fSMatthias Ringwald                         } else {
219*bcf00d8fSMatthias Ringwald                             printf("Failed to get name: page timeout\n");
220*bcf00d8fSMatthias Ringwald                         }
221*bcf00d8fSMatthias Ringwald                     }
222*bcf00d8fSMatthias Ringwald                     continue_remote_names();
223*bcf00d8fSMatthias Ringwald                     break;
224*bcf00d8fSMatthias Ringwald 
225*bcf00d8fSMatthias Ringwald                 default:
226*bcf00d8fSMatthias Ringwald                     break;
227*bcf00d8fSMatthias Ringwald             }
228*bcf00d8fSMatthias Ringwald             break;
229*bcf00d8fSMatthias Ringwald 
230*bcf00d8fSMatthias Ringwald         default:
231*bcf00d8fSMatthias Ringwald             break;
232*bcf00d8fSMatthias Ringwald     }
233*bcf00d8fSMatthias Ringwald }
234*bcf00d8fSMatthias Ringwald 
235*bcf00d8fSMatthias Ringwald /* @text For more details on discovering remote devices, please see
236*bcf00d8fSMatthias Ringwald  * Section on [GAP](../profiles/#sec:GAPdiscoverRemoteDevices).
237*bcf00d8fSMatthias Ringwald  */
238*bcf00d8fSMatthias Ringwald 
239*bcf00d8fSMatthias Ringwald 
240*bcf00d8fSMatthias Ringwald /* @section Main Application Setup
241*bcf00d8fSMatthias Ringwald  *
242*bcf00d8fSMatthias Ringwald  * @text Listing MainConfiguration shows main application code.
243*bcf00d8fSMatthias Ringwald  * It registers the HCI packet handler and starts the Bluetooth stack.
244*bcf00d8fSMatthias Ringwald  */
245*bcf00d8fSMatthias Ringwald 
246*bcf00d8fSMatthias Ringwald /* LISTING_START(MainConfiguration): Setup packet handler for GAP inquiry */
247*bcf00d8fSMatthias Ringwald int btstack_main(int argc, const char * argv[]);
248*bcf00d8fSMatthias Ringwald int btstack_main(int argc, const char * argv[]) {
249*bcf00d8fSMatthias Ringwald 
250*bcf00d8fSMatthias Ringwald     hci_event_callback_registration.callback = &packet_handler;
251*bcf00d8fSMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
252*bcf00d8fSMatthias Ringwald 
253*bcf00d8fSMatthias Ringwald     // turn on!
254*bcf00d8fSMatthias Ringwald     hci_power_control(HCI_POWER_ON);
255*bcf00d8fSMatthias Ringwald 
256*bcf00d8fSMatthias Ringwald     return 0;
257*bcf00d8fSMatthias Ringwald }
258*bcf00d8fSMatthias Ringwald /* LISTING_END */
259*bcf00d8fSMatthias Ringwald /* EXAMPLE_END */
260