1*1aadab7aSMatthias Ringwald /* 2*1aadab7aSMatthias Ringwald * Copyright (C) 2020 BlueKitchen GmbH 3*1aadab7aSMatthias Ringwald * 4*1aadab7aSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*1aadab7aSMatthias Ringwald * modification, are permitted provided that the following conditions 6*1aadab7aSMatthias Ringwald * are met: 7*1aadab7aSMatthias Ringwald * 8*1aadab7aSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*1aadab7aSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*1aadab7aSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*1aadab7aSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*1aadab7aSMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*1aadab7aSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*1aadab7aSMatthias Ringwald * contributors may be used to endorse or promote products derived 15*1aadab7aSMatthias Ringwald * from this software without specific prior written permission. 16*1aadab7aSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*1aadab7aSMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*1aadab7aSMatthias Ringwald * monetary gain. 19*1aadab7aSMatthias Ringwald * 20*1aadab7aSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*1aadab7aSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*1aadab7aSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*1aadab7aSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*1aadab7aSMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*1aadab7aSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*1aadab7aSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*1aadab7aSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*1aadab7aSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*1aadab7aSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*1aadab7aSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*1aadab7aSMatthias Ringwald * SUCH DAMAGE. 32*1aadab7aSMatthias Ringwald * 33*1aadab7aSMatthias Ringwald * Please inquire about commercial licensing options at 34*1aadab7aSMatthias Ringwald * [email protected] 35*1aadab7aSMatthias Ringwald * 36*1aadab7aSMatthias Ringwald */ 37*1aadab7aSMatthias Ringwald 38*1aadab7aSMatthias Ringwald #define BTSTACK_FILE__ "hog_boot_host_demo.c" 39*1aadab7aSMatthias Ringwald 40*1aadab7aSMatthias Ringwald /* 41*1aadab7aSMatthias Ringwald * hog_boot_host_demo.c 42*1aadab7aSMatthias Ringwald */ 43*1aadab7aSMatthias Ringwald 44*1aadab7aSMatthias Ringwald /* EXAMPLE_START(hog_boot_host_demo): HID-over-GATT Boot Host Demo 45*1aadab7aSMatthias Ringwald * 46*1aadab7aSMatthias Ringwald * @text This example implements a minimal HID-over-GATT Boot Host. It scans for LE HID devices, connects to it, 47*1aadab7aSMatthias Ringwald * discovers the Characteristics relevant for the HID Service and enables Notifications on them. 48*1aadab7aSMatthias Ringwald * It then dumps all Boot Keyboard and Mouse Input Reports 49*1aadab7aSMatthias Ringwald */ 50*1aadab7aSMatthias Ringwald 51*1aadab7aSMatthias Ringwald #include <inttypes.h> 52*1aadab7aSMatthias Ringwald #include <stdio.h> 53*1aadab7aSMatthias Ringwald #include <btstack_tlv.h> 54*1aadab7aSMatthias Ringwald 55*1aadab7aSMatthias Ringwald #include "btstack_config.h" 56*1aadab7aSMatthias Ringwald #include "btstack.h" 57*1aadab7aSMatthias Ringwald 58*1aadab7aSMatthias Ringwald // TAG to store remote device address and type in TLV 59*1aadab7aSMatthias Ringwald #define TLV_TAG_HOGD ((((uint32_t) 'H') << 24 ) | (((uint32_t) 'O') << 16) | (((uint32_t) 'G') << 8) | 'D') 60*1aadab7aSMatthias Ringwald 61*1aadab7aSMatthias Ringwald typedef struct { 62*1aadab7aSMatthias Ringwald bd_addr_t addr; 63*1aadab7aSMatthias Ringwald bd_addr_type_t addr_type; 64*1aadab7aSMatthias Ringwald } le_device_addr_t; 65*1aadab7aSMatthias Ringwald 66*1aadab7aSMatthias Ringwald static enum { 67*1aadab7aSMatthias Ringwald W4_WORKING, 68*1aadab7aSMatthias Ringwald W4_HID_DEVICE_FOUND, 69*1aadab7aSMatthias Ringwald W4_CONNECTED, 70*1aadab7aSMatthias Ringwald W4_ENCRYPTED, 71*1aadab7aSMatthias Ringwald W4_HID_SERVICE_FOUND, 72*1aadab7aSMatthias Ringwald W4_HID_CHARACTERISTICS_FOUND, 73*1aadab7aSMatthias Ringwald W4_BOOT_KEYBOARD_ENABLED, 74*1aadab7aSMatthias Ringwald W4_BOOT_MOUSE_ENABLED, 75*1aadab7aSMatthias Ringwald READY, 76*1aadab7aSMatthias Ringwald W4_TIMEOUT_THEN_SCAN, 77*1aadab7aSMatthias Ringwald W4_TIMEOUT_THEN_RECONNECT, 78*1aadab7aSMatthias Ringwald } app_state; 79*1aadab7aSMatthias Ringwald 80*1aadab7aSMatthias Ringwald static le_device_addr_t remote_device; 81*1aadab7aSMatthias Ringwald static hci_con_handle_t connection_handle; 82*1aadab7aSMatthias Ringwald 83*1aadab7aSMatthias Ringwald // used for GATT queries 84*1aadab7aSMatthias Ringwald static gatt_client_service_t hid_service; 85*1aadab7aSMatthias Ringwald static gatt_client_characteristic_t protocol_mode_characteristic; 86*1aadab7aSMatthias Ringwald static gatt_client_characteristic_t boot_keyboard_input_characteristic; 87*1aadab7aSMatthias Ringwald static gatt_client_characteristic_t boot_mouse_input_characteristic; 88*1aadab7aSMatthias Ringwald static gatt_client_notification_t keyboard_notifications; 89*1aadab7aSMatthias Ringwald static gatt_client_notification_t mouse_notifications; 90*1aadab7aSMatthias Ringwald 91*1aadab7aSMatthias Ringwald // used to implement connection timeout and reconnect timer 92*1aadab7aSMatthias Ringwald static btstack_timer_source_t connection_timer; 93*1aadab7aSMatthias Ringwald 94*1aadab7aSMatthias Ringwald // register for events from HCI/GAP and SM 95*1aadab7aSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 96*1aadab7aSMatthias Ringwald static btstack_packet_callback_registration_t sm_event_callback_registration; 97*1aadab7aSMatthias Ringwald 98*1aadab7aSMatthias Ringwald // used to store remote device in TLV 99*1aadab7aSMatthias Ringwald static const btstack_tlv_t * btstack_tlv_singleton_impl; 100*1aadab7aSMatthias Ringwald static void * btstack_tlv_singleton_context; 101*1aadab7aSMatthias Ringwald 102*1aadab7aSMatthias Ringwald // Simplified US Keyboard with Shift modifier 103*1aadab7aSMatthias Ringwald 104*1aadab7aSMatthias Ringwald #define CHAR_ILLEGAL 0xff 105*1aadab7aSMatthias Ringwald #define CHAR_RETURN '\n' 106*1aadab7aSMatthias Ringwald #define CHAR_ESCAPE 27 107*1aadab7aSMatthias Ringwald #define CHAR_TAB '\t' 108*1aadab7aSMatthias Ringwald #define CHAR_BACKSPACE 0x7f 109*1aadab7aSMatthias Ringwald 110*1aadab7aSMatthias Ringwald /** 111*1aadab7aSMatthias Ringwald * English (US) 112*1aadab7aSMatthias Ringwald */ 113*1aadab7aSMatthias Ringwald static const uint8_t keytable_us_none [] = { 114*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 0-3 */ 115*1aadab7aSMatthias Ringwald 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 4-13 */ 116*1aadab7aSMatthias Ringwald 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 14-23 */ 117*1aadab7aSMatthias Ringwald 'u', 'v', 'w', 'x', 'y', 'z', /* 24-29 */ 118*1aadab7aSMatthias Ringwald '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', /* 30-39 */ 119*1aadab7aSMatthias Ringwald CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', /* 40-44 */ 120*1aadab7aSMatthias Ringwald '-', '=', '[', ']', '\\', CHAR_ILLEGAL, ';', '\'', 0x60, ',', /* 45-54 */ 121*1aadab7aSMatthias Ringwald '.', '/', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 55-60 */ 122*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 61-64 */ 123*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 65-68 */ 124*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 69-72 */ 125*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 73-76 */ 126*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 77-80 */ 127*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 81-84 */ 128*1aadab7aSMatthias Ringwald '*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */ 129*1aadab7aSMatthias Ringwald '6', '7', '8', '9', '0', '.', 0xa7, /* 97-100 */ 130*1aadab7aSMatthias Ringwald }; 131*1aadab7aSMatthias Ringwald 132*1aadab7aSMatthias Ringwald static const uint8_t keytable_us_shift[] = { 133*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 0-3 */ 134*1aadab7aSMatthias Ringwald 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 4-13 */ 135*1aadab7aSMatthias Ringwald 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 14-23 */ 136*1aadab7aSMatthias Ringwald 'U', 'V', 'W', 'X', 'Y', 'Z', /* 24-29 */ 137*1aadab7aSMatthias Ringwald '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', /* 30-39 */ 138*1aadab7aSMatthias Ringwald CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', /* 40-44 */ 139*1aadab7aSMatthias Ringwald '_', '+', '{', '}', '|', CHAR_ILLEGAL, ':', '"', 0x7E, '<', /* 45-54 */ 140*1aadab7aSMatthias Ringwald '>', '?', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 55-60 */ 141*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 61-64 */ 142*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 65-68 */ 143*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 69-72 */ 144*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 73-76 */ 145*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 77-80 */ 146*1aadab7aSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 81-84 */ 147*1aadab7aSMatthias Ringwald '*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */ 148*1aadab7aSMatthias Ringwald '6', '7', '8', '9', '0', '.', 0xb1, /* 97-100 */ 149*1aadab7aSMatthias Ringwald }; 150*1aadab7aSMatthias Ringwald 151*1aadab7aSMatthias Ringwald /** 152*1aadab7aSMatthias Ringwald * @section HOG Boot Keyboard Handler 153*1aadab7aSMatthias Ringwald * @text Boot Keyboard Input Report contains a report of format 154*1aadab7aSMatthias Ringwald * [ modifier, reserved, led status, 6 x usage for usage page keyboard] 155*1aadab7aSMatthias Ringwald * Track new usages, map key usage to actual character and simulate terminal 156*1aadab7aSMatthias Ringwald */ 157*1aadab7aSMatthias Ringwald 158*1aadab7aSMatthias Ringwald /* last_keys stores keyboard report to detect new key down events */ 159*1aadab7aSMatthias Ringwald #define NUM_KEYS 6 160*1aadab7aSMatthias Ringwald static uint8_t last_keys[NUM_KEYS]; 161*1aadab7aSMatthias Ringwald 162*1aadab7aSMatthias Ringwald static void handle_boot_keyboard_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 163*1aadab7aSMatthias Ringwald UNUSED(packet_type); 164*1aadab7aSMatthias Ringwald UNUSED(channel); 165*1aadab7aSMatthias Ringwald UNUSED(size); 166*1aadab7aSMatthias Ringwald 167*1aadab7aSMatthias Ringwald if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return; 168*1aadab7aSMatthias Ringwald const uint8_t * data = gatt_event_notification_get_value(packet); 169*1aadab7aSMatthias Ringwald 170*1aadab7aSMatthias Ringwald uint8_t new_keys[NUM_KEYS]; 171*1aadab7aSMatthias Ringwald memset(new_keys, 0, sizeof(new_keys)); 172*1aadab7aSMatthias Ringwald int new_keys_count = 0; 173*1aadab7aSMatthias Ringwald 174*1aadab7aSMatthias Ringwald bool shift = (data[0] & 1) != 0; 175*1aadab7aSMatthias Ringwald 176*1aadab7aSMatthias Ringwald uint8_t key_index; 177*1aadab7aSMatthias Ringwald for (key_index = 0; key_index < NUM_KEYS; key_index++){ 178*1aadab7aSMatthias Ringwald 179*1aadab7aSMatthias Ringwald uint16_t usage = data[3 + key_index]; 180*1aadab7aSMatthias Ringwald if (usage == 0) continue; 181*1aadab7aSMatthias Ringwald if (usage >= sizeof(keytable_us_none)) continue; 182*1aadab7aSMatthias Ringwald 183*1aadab7aSMatthias Ringwald // store new keys 184*1aadab7aSMatthias Ringwald new_keys[new_keys_count++] = usage; 185*1aadab7aSMatthias Ringwald 186*1aadab7aSMatthias Ringwald // check if usage was used last time (and ignore in that case) 187*1aadab7aSMatthias Ringwald int i; 188*1aadab7aSMatthias Ringwald for (i=0;i<NUM_KEYS;i++){ 189*1aadab7aSMatthias Ringwald if (usage == last_keys[i]){ 190*1aadab7aSMatthias Ringwald usage = 0; 191*1aadab7aSMatthias Ringwald } 192*1aadab7aSMatthias Ringwald } 193*1aadab7aSMatthias Ringwald if (usage == 0) continue; 194*1aadab7aSMatthias Ringwald 195*1aadab7aSMatthias Ringwald // lookup character based on usage + shift modifier 196*1aadab7aSMatthias Ringwald uint8_t key; 197*1aadab7aSMatthias Ringwald if (shift){ 198*1aadab7aSMatthias Ringwald key = keytable_us_shift[usage]; 199*1aadab7aSMatthias Ringwald } else { 200*1aadab7aSMatthias Ringwald key = keytable_us_none[usage]; 201*1aadab7aSMatthias Ringwald } 202*1aadab7aSMatthias Ringwald if (key == CHAR_ILLEGAL) continue; 203*1aadab7aSMatthias Ringwald if (key == CHAR_BACKSPACE){ 204*1aadab7aSMatthias Ringwald printf("\b \b"); // go back one char, print space, go back one char again 205*1aadab7aSMatthias Ringwald continue; 206*1aadab7aSMatthias Ringwald } 207*1aadab7aSMatthias Ringwald printf("%c", key); 208*1aadab7aSMatthias Ringwald } 209*1aadab7aSMatthias Ringwald 210*1aadab7aSMatthias Ringwald // store current as last report 211*1aadab7aSMatthias Ringwald memcpy(last_keys, new_keys, NUM_KEYS); 212*1aadab7aSMatthias Ringwald } 213*1aadab7aSMatthias Ringwald 214*1aadab7aSMatthias Ringwald /** 215*1aadab7aSMatthias Ringwald * @section HOG Boot Mouse Handler 216*1aadab7aSMatthias Ringwald * @text Boot Mouse Input Report contains a report of format 217*1aadab7aSMatthias Ringwald * [ buttons, dx, dy, dz = scroll wheel] 218*1aadab7aSMatthias Ringwald * Decode packet and print on stdout 219*1aadab7aSMatthias Ringwald * 220*1aadab7aSMatthias Ringwald * @param packet_type 221*1aadab7aSMatthias Ringwald * @param channel 222*1aadab7aSMatthias Ringwald * @param packet 223*1aadab7aSMatthias Ringwald * @param size 224*1aadab7aSMatthias Ringwald */ 225*1aadab7aSMatthias Ringwald static void handle_boot_mouse_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 226*1aadab7aSMatthias Ringwald UNUSED(packet_type); 227*1aadab7aSMatthias Ringwald UNUSED(channel); 228*1aadab7aSMatthias Ringwald UNUSED(size); 229*1aadab7aSMatthias Ringwald 230*1aadab7aSMatthias Ringwald if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return; 231*1aadab7aSMatthias Ringwald const uint8_t * data = gatt_event_notification_get_value(packet); 232*1aadab7aSMatthias Ringwald uint8_t buttons = data[0]; 233*1aadab7aSMatthias Ringwald int8_t dx = (int8_t) data[1]; 234*1aadab7aSMatthias Ringwald int8_t dy = (int8_t) data[2]; 235*1aadab7aSMatthias Ringwald int8_t dwheel = (int8_t) data[3]; 236*1aadab7aSMatthias Ringwald printf("Mouse: %i, %i - wheel %i - buttons 0x%02x\n", dx, dy, dwheel, buttons); 237*1aadab7aSMatthias Ringwald } 238*1aadab7aSMatthias Ringwald 239*1aadab7aSMatthias Ringwald /** 240*1aadab7aSMatthias Ringwald * @section Test if advertisement contains HID UUID 241*1aadab7aSMatthias Ringwald * @param packet 242*1aadab7aSMatthias Ringwald * @param size 243*1aadab7aSMatthias Ringwald * @returns true if it does 244*1aadab7aSMatthias Ringwald */ 245*1aadab7aSMatthias Ringwald static bool adv_event_contains_hid_service(const uint8_t * packet){ 246*1aadab7aSMatthias Ringwald const uint8_t * ad_data = gap_event_advertising_report_get_data(packet); 247*1aadab7aSMatthias Ringwald uint16_t ad_len = gap_event_advertising_report_get_data_length(packet); 248*1aadab7aSMatthias Ringwald return ad_data_contains_uuid16(ad_len, ad_data, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE); 249*1aadab7aSMatthias Ringwald } 250*1aadab7aSMatthias Ringwald 251*1aadab7aSMatthias Ringwald /** 252*1aadab7aSMatthias Ringwald * Start scanning 253*1aadab7aSMatthias Ringwald */ 254*1aadab7aSMatthias Ringwald static void hog_start_scan(void){ 255*1aadab7aSMatthias Ringwald printf("Scanning for LE HID devices...\n"); 256*1aadab7aSMatthias Ringwald app_state = W4_HID_DEVICE_FOUND; 257*1aadab7aSMatthias Ringwald // Passive scanning, 100% (scan interval = scan window) 258*1aadab7aSMatthias Ringwald gap_set_scan_parameters(0,48,48); 259*1aadab7aSMatthias Ringwald gap_start_scan(); 260*1aadab7aSMatthias Ringwald } 261*1aadab7aSMatthias Ringwald 262*1aadab7aSMatthias Ringwald /** 263*1aadab7aSMatthias Ringwald * Handle timeout for outgoing connection 264*1aadab7aSMatthias Ringwald * @param ts 265*1aadab7aSMatthias Ringwald */ 266*1aadab7aSMatthias Ringwald static void hog_connection_timeout(btstack_timer_source_t * ts){ 267*1aadab7aSMatthias Ringwald UNUSED(ts); 268*1aadab7aSMatthias Ringwald printf("Timeout - abort connection\n"); 269*1aadab7aSMatthias Ringwald gap_connect_cancel(); 270*1aadab7aSMatthias Ringwald hog_start_scan(); 271*1aadab7aSMatthias Ringwald } 272*1aadab7aSMatthias Ringwald 273*1aadab7aSMatthias Ringwald 274*1aadab7aSMatthias Ringwald /** 275*1aadab7aSMatthias Ringwald * Connect to remote device but set timer for timeout 276*1aadab7aSMatthias Ringwald */ 277*1aadab7aSMatthias Ringwald static void hog_connect() { 278*1aadab7aSMatthias Ringwald // set timer 279*1aadab7aSMatthias Ringwald btstack_run_loop_set_timer(&connection_timer, 10000); 280*1aadab7aSMatthias Ringwald btstack_run_loop_set_timer_handler(&connection_timer, &hog_connection_timeout); 281*1aadab7aSMatthias Ringwald btstack_run_loop_add_timer(&connection_timer); 282*1aadab7aSMatthias Ringwald app_state = W4_CONNECTED; 283*1aadab7aSMatthias Ringwald gap_connect(remote_device.addr, remote_device.addr_type); 284*1aadab7aSMatthias Ringwald } 285*1aadab7aSMatthias Ringwald 286*1aadab7aSMatthias Ringwald /** 287*1aadab7aSMatthias Ringwald * Handle timer event to trigger reconnect 288*1aadab7aSMatthias Ringwald * @param ts 289*1aadab7aSMatthias Ringwald */ 290*1aadab7aSMatthias Ringwald static void hog_reconnect_timeout(btstack_timer_source_t * ts){ 291*1aadab7aSMatthias Ringwald UNUSED(ts); 292*1aadab7aSMatthias Ringwald switch (app_state){ 293*1aadab7aSMatthias Ringwald case W4_TIMEOUT_THEN_RECONNECT: 294*1aadab7aSMatthias Ringwald hog_connect(); 295*1aadab7aSMatthias Ringwald break; 296*1aadab7aSMatthias Ringwald case W4_TIMEOUT_THEN_SCAN: 297*1aadab7aSMatthias Ringwald hog_start_scan(); 298*1aadab7aSMatthias Ringwald break; 299*1aadab7aSMatthias Ringwald default: 300*1aadab7aSMatthias Ringwald break; 301*1aadab7aSMatthias Ringwald } 302*1aadab7aSMatthias Ringwald } 303*1aadab7aSMatthias Ringwald 304*1aadab7aSMatthias Ringwald /** 305*1aadab7aSMatthias Ringwald * Start connecting after boot up: connect to last used device if possible, start scan otherwise 306*1aadab7aSMatthias Ringwald */ 307*1aadab7aSMatthias Ringwald static void hog_start_connect(void){ 308*1aadab7aSMatthias Ringwald // check if we have a bonded device 309*1aadab7aSMatthias Ringwald btstack_tlv_get_instance(&btstack_tlv_singleton_impl, &btstack_tlv_singleton_context); 310*1aadab7aSMatthias Ringwald if (btstack_tlv_singleton_impl){ 311*1aadab7aSMatthias Ringwald int len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, TLV_TAG_HOGD, (uint8_t *) &remote_device, sizeof(remote_device)); 312*1aadab7aSMatthias Ringwald if (len == sizeof(remote_device)){ 313*1aadab7aSMatthias Ringwald printf("Bonded, connect to device with %s address %s ...\n", remote_device.addr_type == 0 ? "public" : "random" , bd_addr_to_str(remote_device.addr)); 314*1aadab7aSMatthias Ringwald hog_connect(); 315*1aadab7aSMatthias Ringwald return; 316*1aadab7aSMatthias Ringwald } 317*1aadab7aSMatthias Ringwald } 318*1aadab7aSMatthias Ringwald // otherwise, scan for HID devices 319*1aadab7aSMatthias Ringwald hog_start_scan(); 320*1aadab7aSMatthias Ringwald } 321*1aadab7aSMatthias Ringwald 322*1aadab7aSMatthias Ringwald /** 323*1aadab7aSMatthias Ringwald * In case of error, disconnect and start scanning again 324*1aadab7aSMatthias Ringwald */ 325*1aadab7aSMatthias Ringwald static void handle_outgoing_connection_error(void){ 326*1aadab7aSMatthias Ringwald printf("Error occurred, disconnect and start over\n"); 327*1aadab7aSMatthias Ringwald gap_disconnect(connection_handle); 328*1aadab7aSMatthias Ringwald hog_start_scan(); 329*1aadab7aSMatthias Ringwald } 330*1aadab7aSMatthias Ringwald 331*1aadab7aSMatthias Ringwald /** 332*1aadab7aSMatthias Ringwald * Handle GATT Client Events dependent on current state 333*1aadab7aSMatthias Ringwald * 334*1aadab7aSMatthias Ringwald * @param packet_type 335*1aadab7aSMatthias Ringwald * @param channel 336*1aadab7aSMatthias Ringwald * @param packet 337*1aadab7aSMatthias Ringwald * @param size 338*1aadab7aSMatthias Ringwald */ 339*1aadab7aSMatthias Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 340*1aadab7aSMatthias Ringwald UNUSED(packet_type); 341*1aadab7aSMatthias Ringwald UNUSED(channel); 342*1aadab7aSMatthias Ringwald UNUSED(size); 343*1aadab7aSMatthias Ringwald gatt_client_characteristic_t characteristic; 344*1aadab7aSMatthias Ringwald static uint8_t boot_protocol_mode = 0; 345*1aadab7aSMatthias Ringwald 346*1aadab7aSMatthias Ringwald switch (app_state) { 347*1aadab7aSMatthias Ringwald case W4_HID_SERVICE_FOUND: 348*1aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 349*1aadab7aSMatthias Ringwald case GATT_EVENT_SERVICE_QUERY_RESULT: 350*1aadab7aSMatthias Ringwald // store service (we expect only one) 351*1aadab7aSMatthias Ringwald gatt_event_service_query_result_get_service(packet, &hid_service); 352*1aadab7aSMatthias Ringwald break; 353*1aadab7aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 354*1aadab7aSMatthias Ringwald if (gatt_event_query_complete_get_att_status(packet) != ATT_ERROR_SUCCESS) { 355*1aadab7aSMatthias Ringwald printf("ATT Error status %x.\n", gatt_event_query_complete_get_att_status(packet)); 356*1aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 357*1aadab7aSMatthias Ringwald break; 358*1aadab7aSMatthias Ringwald } 359*1aadab7aSMatthias Ringwald printf("Find required HID Service Characteristics...\n"); 360*1aadab7aSMatthias Ringwald app_state = W4_HID_CHARACTERISTICS_FOUND; 361*1aadab7aSMatthias Ringwald gatt_client_discover_characteristics_for_service(&handle_gatt_client_event, connection_handle, &hid_service); 362*1aadab7aSMatthias Ringwald break; 363*1aadab7aSMatthias Ringwald default: 364*1aadab7aSMatthias Ringwald break; 365*1aadab7aSMatthias Ringwald } 366*1aadab7aSMatthias Ringwald break; 367*1aadab7aSMatthias Ringwald case W4_HID_CHARACTERISTICS_FOUND: 368*1aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 369*1aadab7aSMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 370*1aadab7aSMatthias Ringwald // get characteristic 371*1aadab7aSMatthias Ringwald gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 372*1aadab7aSMatthias Ringwald switch (characteristic.uuid16){ 373*1aadab7aSMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT: 374*1aadab7aSMatthias Ringwald printf("Found CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT, value handle 0x%04x\n", characteristic.value_handle); 375*1aadab7aSMatthias Ringwald memcpy(&boot_keyboard_input_characteristic, &characteristic, sizeof(gatt_client_characteristic_t)); 376*1aadab7aSMatthias Ringwald break; 377*1aadab7aSMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT: 378*1aadab7aSMatthias Ringwald printf("Found CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT, value handle 0x%04x\n", characteristic.value_handle); 379*1aadab7aSMatthias Ringwald memcpy(&boot_mouse_input_characteristic, &characteristic, sizeof(gatt_client_characteristic_t)); 380*1aadab7aSMatthias Ringwald break; 381*1aadab7aSMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE: 382*1aadab7aSMatthias Ringwald printf("Found CHARACTERISTIC_PROTOCOL_MODE\n"); 383*1aadab7aSMatthias Ringwald memcpy(&protocol_mode_characteristic, &characteristic, sizeof(gatt_client_characteristic_t)); 384*1aadab7aSMatthias Ringwald break; 385*1aadab7aSMatthias Ringwald default: 386*1aadab7aSMatthias Ringwald break; 387*1aadab7aSMatthias Ringwald } 388*1aadab7aSMatthias Ringwald break; 389*1aadab7aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 390*1aadab7aSMatthias Ringwald if (gatt_event_query_complete_get_att_status(packet) != ATT_ERROR_SUCCESS) { 391*1aadab7aSMatthias Ringwald printf("ATT Error status %x.\n", gatt_event_query_complete_get_att_status(packet)); 392*1aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 393*1aadab7aSMatthias Ringwald break; 394*1aadab7aSMatthias Ringwald } 395*1aadab7aSMatthias Ringwald printf("Enable Notifications for Boot Keyboard Input Report..\n"); 396*1aadab7aSMatthias Ringwald app_state = W4_BOOT_KEYBOARD_ENABLED; 397*1aadab7aSMatthias Ringwald gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, connection_handle, &boot_keyboard_input_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 398*1aadab7aSMatthias Ringwald break; 399*1aadab7aSMatthias Ringwald default: 400*1aadab7aSMatthias Ringwald break; 401*1aadab7aSMatthias Ringwald } 402*1aadab7aSMatthias Ringwald break; 403*1aadab7aSMatthias Ringwald case W4_BOOT_KEYBOARD_ENABLED: 404*1aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 405*1aadab7aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 406*1aadab7aSMatthias Ringwald if (gatt_event_query_complete_get_att_status(packet) != ATT_ERROR_SUCCESS) { 407*1aadab7aSMatthias Ringwald printf("ATT Error status %x.\n", gatt_event_query_complete_get_att_status(packet)); 408*1aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 409*1aadab7aSMatthias Ringwald break; 410*1aadab7aSMatthias Ringwald } 411*1aadab7aSMatthias Ringwald // setup listener 412*1aadab7aSMatthias Ringwald gatt_client_listen_for_characteristic_value_updates(&keyboard_notifications, &handle_boot_keyboard_event, connection_handle, &boot_keyboard_input_characteristic); 413*1aadab7aSMatthias Ringwald // 414*1aadab7aSMatthias Ringwald printf("Enable Notifications for Boot Mouse Input Report..\n"); 415*1aadab7aSMatthias Ringwald app_state = W4_BOOT_MOUSE_ENABLED; 416*1aadab7aSMatthias Ringwald gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, connection_handle, &boot_mouse_input_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 417*1aadab7aSMatthias Ringwald break; 418*1aadab7aSMatthias Ringwald default: 419*1aadab7aSMatthias Ringwald break; 420*1aadab7aSMatthias Ringwald } 421*1aadab7aSMatthias Ringwald break; 422*1aadab7aSMatthias Ringwald case W4_BOOT_MOUSE_ENABLED: 423*1aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 424*1aadab7aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 425*1aadab7aSMatthias Ringwald if (gatt_event_query_complete_get_att_status(packet) != ATT_ERROR_SUCCESS) { 426*1aadab7aSMatthias Ringwald printf("ATT Error status %x.\n", gatt_event_query_complete_get_att_status(packet)); 427*1aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 428*1aadab7aSMatthias Ringwald break; 429*1aadab7aSMatthias Ringwald } 430*1aadab7aSMatthias Ringwald // setup listener 431*1aadab7aSMatthias Ringwald gatt_client_listen_for_characteristic_value_updates(&mouse_notifications, &handle_boot_mouse_event, connection_handle, &boot_mouse_input_characteristic); 432*1aadab7aSMatthias Ringwald 433*1aadab7aSMatthias Ringwald // switch to boot mode 434*1aadab7aSMatthias Ringwald printf("Set Protocol Mode to Boot Mode..\n"); 435*1aadab7aSMatthias Ringwald gatt_client_write_value_of_characteristic_without_response(connection_handle, protocol_mode_characteristic.value_handle, 1, &boot_protocol_mode); 436*1aadab7aSMatthias Ringwald 437*1aadab7aSMatthias Ringwald // store device as bonded 438*1aadab7aSMatthias Ringwald if (btstack_tlv_singleton_impl){ 439*1aadab7aSMatthias Ringwald btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, TLV_TAG_HOGD, (const uint8_t *) &remote_device, sizeof(remote_device)); 440*1aadab7aSMatthias Ringwald } 441*1aadab7aSMatthias Ringwald // done 442*1aadab7aSMatthias Ringwald printf("Ready - please start typing or mousing..\n"); 443*1aadab7aSMatthias Ringwald app_state = READY; 444*1aadab7aSMatthias Ringwald break; 445*1aadab7aSMatthias Ringwald default: 446*1aadab7aSMatthias Ringwald break; 447*1aadab7aSMatthias Ringwald } 448*1aadab7aSMatthias Ringwald break; 449*1aadab7aSMatthias Ringwald default: 450*1aadab7aSMatthias Ringwald break; 451*1aadab7aSMatthias Ringwald } 452*1aadab7aSMatthias Ringwald } 453*1aadab7aSMatthias Ringwald 454*1aadab7aSMatthias Ringwald /* LISTING_START(packetHandler): Packet Handler */ 455*1aadab7aSMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 456*1aadab7aSMatthias Ringwald /* LISTING_PAUSE */ 457*1aadab7aSMatthias Ringwald UNUSED(channel); 458*1aadab7aSMatthias Ringwald UNUSED(size); 459*1aadab7aSMatthias Ringwald uint8_t event; 460*1aadab7aSMatthias Ringwald /* LISTING_RESUME */ 461*1aadab7aSMatthias Ringwald switch (packet_type) { 462*1aadab7aSMatthias Ringwald case HCI_EVENT_PACKET: 463*1aadab7aSMatthias Ringwald event = hci_event_packet_get_type(packet); 464*1aadab7aSMatthias Ringwald switch (event) { 465*1aadab7aSMatthias Ringwald case BTSTACK_EVENT_STATE: 466*1aadab7aSMatthias Ringwald if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break; 467*1aadab7aSMatthias Ringwald btstack_assert(app_state == W4_WORKING); 468*1aadab7aSMatthias Ringwald hog_start_connect(); 469*1aadab7aSMatthias Ringwald break; 470*1aadab7aSMatthias Ringwald case GAP_EVENT_ADVERTISING_REPORT: 471*1aadab7aSMatthias Ringwald if (app_state != W4_HID_DEVICE_FOUND) break; 472*1aadab7aSMatthias Ringwald if (adv_event_contains_hid_service(packet) == false) break; 473*1aadab7aSMatthias Ringwald // stop scan 474*1aadab7aSMatthias Ringwald gap_stop_scan(); 475*1aadab7aSMatthias Ringwald // store remote device address and type 476*1aadab7aSMatthias Ringwald gap_event_advertising_report_get_address(packet, remote_device.addr); 477*1aadab7aSMatthias Ringwald remote_device.addr_type = gap_event_advertising_report_get_address_type(packet); 478*1aadab7aSMatthias Ringwald // connect 479*1aadab7aSMatthias Ringwald printf("Found, connect to device with %s address %s ...\n", remote_device.addr_type == 0 ? "public" : "random" , bd_addr_to_str(remote_device.addr)); 480*1aadab7aSMatthias Ringwald hog_connect(); 481*1aadab7aSMatthias Ringwald break; 482*1aadab7aSMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 483*1aadab7aSMatthias Ringwald connection_handle = HCI_CON_HANDLE_INVALID; 484*1aadab7aSMatthias Ringwald switch (app_state){ 485*1aadab7aSMatthias Ringwald case READY: 486*1aadab7aSMatthias Ringwald printf("\nDisconnected, try to reconnect...\n"); 487*1aadab7aSMatthias Ringwald app_state = W4_TIMEOUT_THEN_RECONNECT; 488*1aadab7aSMatthias Ringwald break; 489*1aadab7aSMatthias Ringwald default: 490*1aadab7aSMatthias Ringwald printf("\nDisconnected, start over...\n"); 491*1aadab7aSMatthias Ringwald app_state = W4_TIMEOUT_THEN_SCAN; 492*1aadab7aSMatthias Ringwald break; 493*1aadab7aSMatthias Ringwald } 494*1aadab7aSMatthias Ringwald // set timer 495*1aadab7aSMatthias Ringwald btstack_run_loop_set_timer(&connection_timer, 100); 496*1aadab7aSMatthias Ringwald btstack_run_loop_set_timer_handler(&connection_timer, &hog_reconnect_timeout); 497*1aadab7aSMatthias Ringwald btstack_run_loop_add_timer(&connection_timer); 498*1aadab7aSMatthias Ringwald break; 499*1aadab7aSMatthias Ringwald case HCI_EVENT_LE_META: 500*1aadab7aSMatthias Ringwald // wait for connection complete 501*1aadab7aSMatthias Ringwald if (hci_event_le_meta_get_subevent_code(packet) != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break; 502*1aadab7aSMatthias Ringwald if (app_state != W4_CONNECTED) return; 503*1aadab7aSMatthias Ringwald btstack_run_loop_remove_timer(&connection_timer); 504*1aadab7aSMatthias Ringwald connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet); 505*1aadab7aSMatthias Ringwald // request security 506*1aadab7aSMatthias Ringwald app_state = W4_ENCRYPTED; 507*1aadab7aSMatthias Ringwald sm_request_pairing(connection_handle); 508*1aadab7aSMatthias Ringwald break; 509*1aadab7aSMatthias Ringwald case HCI_EVENT_ENCRYPTION_CHANGE: 510*1aadab7aSMatthias Ringwald if (connection_handle != hci_event_encryption_change_get_connection_handle(packet)) break; 511*1aadab7aSMatthias Ringwald printf("Connection encrypted: %u\n", hci_event_encryption_change_get_encryption_enabled(packet)); 512*1aadab7aSMatthias Ringwald if (hci_event_encryption_change_get_encryption_enabled(packet) == 0){ 513*1aadab7aSMatthias Ringwald printf("Encryption failed -> abort\n"); 514*1aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 515*1aadab7aSMatthias Ringwald break; 516*1aadab7aSMatthias Ringwald } 517*1aadab7aSMatthias Ringwald // continue - query primary services 518*1aadab7aSMatthias Ringwald printf("Search for HID service.\n"); 519*1aadab7aSMatthias Ringwald app_state = W4_HID_SERVICE_FOUND; 520*1aadab7aSMatthias Ringwald gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, connection_handle, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE); 521*1aadab7aSMatthias Ringwald break; 522*1aadab7aSMatthias Ringwald default: 523*1aadab7aSMatthias Ringwald break; 524*1aadab7aSMatthias Ringwald } 525*1aadab7aSMatthias Ringwald break; 526*1aadab7aSMatthias Ringwald default: 527*1aadab7aSMatthias Ringwald break; 528*1aadab7aSMatthias Ringwald } 529*1aadab7aSMatthias Ringwald } 530*1aadab7aSMatthias Ringwald /* LISTING_END */ 531*1aadab7aSMatthias Ringwald 532*1aadab7aSMatthias Ringwald /* @section HCI packet handler 533*1aadab7aSMatthias Ringwald * 534*1aadab7aSMatthias Ringwald * @text The SM packet handler receives Security Manager Events required for pairing. 535*1aadab7aSMatthias Ringwald * It also receives events generated during Identity Resolving 536*1aadab7aSMatthias Ringwald * see Listing SMPacketHandler. 537*1aadab7aSMatthias Ringwald */ 538*1aadab7aSMatthias Ringwald 539*1aadab7aSMatthias Ringwald /* LISTING_START(SMPacketHandler): Scanning and receiving advertisements */ 540*1aadab7aSMatthias Ringwald 541*1aadab7aSMatthias Ringwald static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 542*1aadab7aSMatthias Ringwald UNUSED(channel); 543*1aadab7aSMatthias Ringwald UNUSED(size); 544*1aadab7aSMatthias Ringwald 545*1aadab7aSMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 546*1aadab7aSMatthias Ringwald 547*1aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 548*1aadab7aSMatthias Ringwald case SM_EVENT_JUST_WORKS_REQUEST: 549*1aadab7aSMatthias Ringwald printf("Just works requested\n"); 550*1aadab7aSMatthias Ringwald sm_just_works_confirm(sm_event_just_works_request_get_handle(packet)); 551*1aadab7aSMatthias Ringwald break; 552*1aadab7aSMatthias Ringwald case SM_EVENT_NUMERIC_COMPARISON_REQUEST: 553*1aadab7aSMatthias Ringwald printf("Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet)); 554*1aadab7aSMatthias Ringwald sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet)); 555*1aadab7aSMatthias Ringwald break; 556*1aadab7aSMatthias Ringwald case SM_EVENT_PASSKEY_DISPLAY_NUMBER: 557*1aadab7aSMatthias Ringwald printf("Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet)); 558*1aadab7aSMatthias Ringwald break; 559*1aadab7aSMatthias Ringwald case SM_EVENT_PAIRING_COMPLETE: 560*1aadab7aSMatthias Ringwald switch (sm_event_pairing_complete_get_status(packet)){ 561*1aadab7aSMatthias Ringwald case ERROR_CODE_SUCCESS: 562*1aadab7aSMatthias Ringwald printf("Pairing complete, success\n"); 563*1aadab7aSMatthias Ringwald break; 564*1aadab7aSMatthias Ringwald case ERROR_CODE_CONNECTION_TIMEOUT: 565*1aadab7aSMatthias Ringwald printf("Pairing failed, timeout\n"); 566*1aadab7aSMatthias Ringwald break; 567*1aadab7aSMatthias Ringwald case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION: 568*1aadab7aSMatthias Ringwald printf("Pairing faileed, disconnected\n"); 569*1aadab7aSMatthias Ringwald break; 570*1aadab7aSMatthias Ringwald case ERROR_CODE_AUTHENTICATION_FAILURE: 571*1aadab7aSMatthias Ringwald printf("Pairing failed, reason = %u\n", sm_event_pairing_complete_get_reason(packet)); 572*1aadab7aSMatthias Ringwald break; 573*1aadab7aSMatthias Ringwald default: 574*1aadab7aSMatthias Ringwald break; 575*1aadab7aSMatthias Ringwald } 576*1aadab7aSMatthias Ringwald break; 577*1aadab7aSMatthias Ringwald default: 578*1aadab7aSMatthias Ringwald break; 579*1aadab7aSMatthias Ringwald } 580*1aadab7aSMatthias Ringwald } 581*1aadab7aSMatthias Ringwald /* LISTING_END */ 582*1aadab7aSMatthias Ringwald 583*1aadab7aSMatthias Ringwald int btstack_main(int argc, const char * argv[]); 584*1aadab7aSMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 585*1aadab7aSMatthias Ringwald 586*1aadab7aSMatthias Ringwald (void)argc; 587*1aadab7aSMatthias Ringwald (void)argv; 588*1aadab7aSMatthias Ringwald 589*1aadab7aSMatthias Ringwald /* LISTING_START(HogBootHostSetup): HID-over-GATT Boot Host Setup */ 590*1aadab7aSMatthias Ringwald 591*1aadab7aSMatthias Ringwald // register for events from HCI 592*1aadab7aSMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 593*1aadab7aSMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 594*1aadab7aSMatthias Ringwald 595*1aadab7aSMatthias Ringwald // register for events from Security Manager 596*1aadab7aSMatthias Ringwald sm_event_callback_registration.callback = &sm_packet_handler; 597*1aadab7aSMatthias Ringwald sm_add_event_handler(&sm_event_callback_registration); 598*1aadab7aSMatthias Ringwald 599*1aadab7aSMatthias Ringwald // setup le device db 600*1aadab7aSMatthias Ringwald le_device_db_init(); 601*1aadab7aSMatthias Ringwald 602*1aadab7aSMatthias Ringwald // 603*1aadab7aSMatthias Ringwald l2cap_init(); 604*1aadab7aSMatthias Ringwald sm_init(); 605*1aadab7aSMatthias Ringwald gatt_client_init(); 606*1aadab7aSMatthias Ringwald 607*1aadab7aSMatthias Ringwald /* LISTING_END */ 608*1aadab7aSMatthias Ringwald 609*1aadab7aSMatthias Ringwald // Disable stdout buffering 610*1aadab7aSMatthias Ringwald setbuf(stdout, NULL); 611*1aadab7aSMatthias Ringwald 612*1aadab7aSMatthias Ringwald app_state = W4_WORKING; 613*1aadab7aSMatthias Ringwald 614*1aadab7aSMatthias Ringwald // Turn on the device 615*1aadab7aSMatthias Ringwald hci_power_control(HCI_POWER_ON); 616*1aadab7aSMatthias Ringwald return 0; 617*1aadab7aSMatthias Ringwald } 618*1aadab7aSMatthias Ringwald 619*1aadab7aSMatthias Ringwald /* EXAMPLE_END */ 620