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 Classic Inquiry 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 gap_remote_name_request( devices[i].address, devices[i].pageScanRepetitionMode, devices[i].clockOffset | 0x8000); 110 return; 111 } 112 } 113 } 114 115 static void continue_remote_names(void){ 116 if (has_more_remote_name_requests()){ 117 do_next_remote_name_request(); 118 return; 119 } 120 start_scan(); 121 } 122 123 /* @section Bluetooth Logic 124 * 125 * @text The Bluetooth logic is implemented as a state machine within the packet 126 * handler. In this example, the following states are passed sequentially: 127 * INIT, and ACTIVE. 128 */ 129 130 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 131 UNUSED(channel); 132 UNUSED(size); 133 134 bd_addr_t addr; 135 int i; 136 int index; 137 138 if (packet_type != HCI_EVENT_PACKET) return; 139 140 uint8_t event = hci_event_packet_get_type(packet); 141 142 switch(state){ 143 /* @text In INIT, an inquiry scan is started, and the application transits to 144 * ACTIVE state. 145 */ 146 case INIT: 147 switch(event){ 148 case BTSTACK_EVENT_STATE: 149 if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ 150 start_scan(); 151 state = ACTIVE; 152 } 153 break; 154 default: 155 break; 156 } 157 break; 158 159 /* @text In ACTIVE, the following events are processed: 160 * - GAP Inquiry result event: BTstack provides a unified inquiry result that contain 161 * Class of Device (CoD), page scan mode, clock offset. RSSI and name (from EIR) are optional. 162 * - Inquiry complete event: the remote name is requested for devices without a fetched 163 * name. The state of a remote name can be one of the following: 164 * REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, or REMOTE_NAME_FETCHED. 165 * - Remote name request complete event: the remote name is stored in the table and the 166 * state is updated to REMOTE_NAME_FETCHED. The query of remote names is continued. 167 */ 168 case ACTIVE: 169 switch(event){ 170 171 case GAP_EVENT_INQUIRY_RESULT: 172 if (deviceCount >= MAX_DEVICES) break; // already full 173 gap_event_inquiry_result_get_bd_addr(packet, addr); 174 index = getDeviceIndexForAddress(addr); 175 if (index >= 0) break; // already in our list 176 177 memcpy(devices[deviceCount].address, addr, 6); 178 devices[deviceCount].pageScanRepetitionMode = gap_event_inquiry_result_get_page_scan_repetition_mode(packet); 179 devices[deviceCount].clockOffset = gap_event_inquiry_result_get_clock_offset(packet); 180 // print info 181 printf("Device found: %s ", bd_addr_to_str(addr)); 182 printf("with COD: 0x%06x, ", (unsigned int) gap_event_inquiry_result_get_class_of_device(packet)); 183 printf("pageScan %d, ", devices[deviceCount].pageScanRepetitionMode); 184 printf("clock offset 0x%04x",devices[deviceCount].clockOffset); 185 if (gap_event_inquiry_result_get_rssi_available(packet)){ 186 printf(", rssi %d dBm", (int8_t) gap_event_inquiry_result_get_rssi(packet)); 187 } 188 if (gap_event_inquiry_result_get_name_available(packet)){ 189 char name_buffer[240]; 190 int name_len = gap_event_inquiry_result_get_name_len(packet); 191 memcpy(name_buffer, gap_event_inquiry_result_get_name(packet), name_len); 192 name_buffer[name_len] = 0; 193 printf(", name '%s'", name_buffer); 194 devices[deviceCount].state = REMOTE_NAME_FETCHED;; 195 } else { 196 devices[deviceCount].state = REMOTE_NAME_REQUEST; 197 } 198 printf("\n"); 199 deviceCount++; 200 break; 201 202 case GAP_EVENT_INQUIRY_COMPLETE: 203 for (i=0;i<deviceCount;i++) { 204 // retry remote name request 205 if (devices[i].state == REMOTE_NAME_INQUIRED) 206 devices[i].state = REMOTE_NAME_REQUEST; 207 } 208 continue_remote_names(); 209 break; 210 211 case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: 212 reverse_bd_addr(&packet[3], addr); 213 index = getDeviceIndexForAddress(addr); 214 if (index >= 0) { 215 if (packet[2] == 0) { 216 printf("Name: '%s'\n", &packet[9]); 217 devices[index].state = REMOTE_NAME_FETCHED; 218 } else { 219 printf("Failed to get name: page timeout\n"); 220 } 221 } 222 continue_remote_names(); 223 break; 224 225 default: 226 break; 227 } 228 break; 229 230 default: 231 break; 232 } 233 } 234 235 /* @text For more details on discovering remote devices, please see 236 * Section on [GAP](../profiles/#sec:GAPdiscoverRemoteDevices). 237 */ 238 239 240 /* @section Main Application Setup 241 * 242 * @text Listing MainConfiguration shows main application code. 243 * It registers the HCI packet handler and starts the Bluetooth stack. 244 */ 245 246 /* LISTING_START(MainConfiguration): Setup packet handler for GAP inquiry */ 247 int btstack_main(int argc, const char * argv[]); 248 int btstack_main(int argc, const char * argv[]) { 249 (void)argc; 250 (void)argv; 251 252 // enabled EIR 253 hci_set_inquiry_mode(INQUIRY_MODE_RSSI_AND_EIR); 254 255 hci_event_callback_registration.callback = &packet_handler; 256 hci_add_event_handler(&hci_event_callback_registration); 257 258 // turn on! 259 hci_power_control(HCI_POWER_ON); 260 261 return 0; 262 } 263 /* LISTING_END */ 264 /* EXAMPLE_END */ 265