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