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