xref: /btstack/example/hog_boot_host_demo.c (revision bba48196553c8cb4568b4278b9e099c548e7c432)
11aadab7aSMatthias Ringwald /*
21aadab7aSMatthias Ringwald  * Copyright (C) 2020 BlueKitchen GmbH
31aadab7aSMatthias Ringwald  *
41aadab7aSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
51aadab7aSMatthias Ringwald  * modification, are permitted provided that the following conditions
61aadab7aSMatthias Ringwald  * are met:
71aadab7aSMatthias Ringwald  *
81aadab7aSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
91aadab7aSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
101aadab7aSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
111aadab7aSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
121aadab7aSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
131aadab7aSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
141aadab7aSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
151aadab7aSMatthias Ringwald  *    from this software without specific prior written permission.
161aadab7aSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
171aadab7aSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
181aadab7aSMatthias Ringwald  *    monetary gain.
191aadab7aSMatthias Ringwald  *
201aadab7aSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
211aadab7aSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
221aadab7aSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
251aadab7aSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
261aadab7aSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
271aadab7aSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
281aadab7aSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
291aadab7aSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
301aadab7aSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311aadab7aSMatthias Ringwald  * SUCH DAMAGE.
321aadab7aSMatthias Ringwald  *
331aadab7aSMatthias Ringwald  * Please inquire about commercial licensing options at
341aadab7aSMatthias Ringwald  * [email protected]
351aadab7aSMatthias Ringwald  *
361aadab7aSMatthias Ringwald  */
371aadab7aSMatthias Ringwald 
381aadab7aSMatthias Ringwald #define BTSTACK_FILE__ "hog_boot_host_demo.c"
391aadab7aSMatthias Ringwald 
401aadab7aSMatthias Ringwald /*
411aadab7aSMatthias Ringwald  * hog_boot_host_demo.c
421aadab7aSMatthias Ringwald  */
431aadab7aSMatthias Ringwald 
44ec8ae085SMilanka Ringwald /* EXAMPLE_START(hog_boot_host_demo): HID Boot Host LE
451aadab7aSMatthias Ringwald  *
461aadab7aSMatthias Ringwald  * @text This example implements a minimal HID-over-GATT Boot Host. It scans for LE HID devices, connects to it,
471aadab7aSMatthias Ringwald  * discovers the Characteristics relevant for the HID Service and enables Notifications on them.
481aadab7aSMatthias Ringwald  * It then dumps all Boot Keyboard and Mouse Input Reports
491aadab7aSMatthias Ringwald  */
501aadab7aSMatthias Ringwald 
511aadab7aSMatthias Ringwald #include <inttypes.h>
521aadab7aSMatthias Ringwald #include <stdio.h>
531aadab7aSMatthias Ringwald #include <btstack_tlv.h>
541aadab7aSMatthias Ringwald 
551aadab7aSMatthias Ringwald #include "btstack_config.h"
561aadab7aSMatthias Ringwald #include "btstack.h"
571aadab7aSMatthias Ringwald 
581aadab7aSMatthias Ringwald // TAG to store remote device address and type in TLV
591aadab7aSMatthias Ringwald #define TLV_TAG_HOGD ((((uint32_t) 'H') << 24 ) | (((uint32_t) 'O') << 16) | (((uint32_t) 'G') << 8) | 'D')
601aadab7aSMatthias Ringwald 
611aadab7aSMatthias Ringwald typedef struct {
621aadab7aSMatthias Ringwald     bd_addr_t addr;
631aadab7aSMatthias Ringwald     bd_addr_type_t addr_type;
641aadab7aSMatthias Ringwald } le_device_addr_t;
651aadab7aSMatthias Ringwald 
661aadab7aSMatthias Ringwald static enum {
671aadab7aSMatthias Ringwald     W4_WORKING,
681aadab7aSMatthias Ringwald     W4_HID_DEVICE_FOUND,
691aadab7aSMatthias Ringwald     W4_CONNECTED,
701aadab7aSMatthias Ringwald     W4_ENCRYPTED,
711aadab7aSMatthias Ringwald     W4_HID_SERVICE_FOUND,
721aadab7aSMatthias Ringwald     W4_HID_CHARACTERISTICS_FOUND,
731aadab7aSMatthias Ringwald     W4_BOOT_KEYBOARD_ENABLED,
741aadab7aSMatthias Ringwald     W4_BOOT_MOUSE_ENABLED,
751aadab7aSMatthias Ringwald     READY,
761aadab7aSMatthias Ringwald     W4_TIMEOUT_THEN_SCAN,
771aadab7aSMatthias Ringwald     W4_TIMEOUT_THEN_RECONNECT,
781aadab7aSMatthias Ringwald } app_state;
791aadab7aSMatthias Ringwald 
801aadab7aSMatthias Ringwald static le_device_addr_t remote_device;
811aadab7aSMatthias Ringwald static hci_con_handle_t connection_handle;
821aadab7aSMatthias Ringwald 
831aadab7aSMatthias Ringwald // used for GATT queries
841aadab7aSMatthias Ringwald static gatt_client_service_t       hid_service;
851aadab7aSMatthias Ringwald static gatt_client_characteristic_t protocol_mode_characteristic;
861aadab7aSMatthias Ringwald static gatt_client_characteristic_t boot_keyboard_input_characteristic;
871aadab7aSMatthias Ringwald static gatt_client_characteristic_t boot_mouse_input_characteristic;
881aadab7aSMatthias Ringwald static gatt_client_notification_t   keyboard_notifications;
891aadab7aSMatthias Ringwald static gatt_client_notification_t   mouse_notifications;
901aadab7aSMatthias Ringwald 
911aadab7aSMatthias Ringwald // used to implement connection timeout and reconnect timer
921aadab7aSMatthias Ringwald static btstack_timer_source_t connection_timer;
931aadab7aSMatthias Ringwald 
941aadab7aSMatthias Ringwald // register for events from HCI/GAP and SM
951aadab7aSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
961aadab7aSMatthias Ringwald static btstack_packet_callback_registration_t sm_event_callback_registration;
971aadab7aSMatthias Ringwald 
981aadab7aSMatthias Ringwald // used to store remote device in TLV
991aadab7aSMatthias Ringwald static const btstack_tlv_t * btstack_tlv_singleton_impl;
1001aadab7aSMatthias Ringwald static void *                btstack_tlv_singleton_context;
1011aadab7aSMatthias Ringwald 
1021aadab7aSMatthias Ringwald // Simplified US Keyboard with Shift modifier
1031aadab7aSMatthias Ringwald 
1041aadab7aSMatthias Ringwald #define CHAR_ILLEGAL     0xff
1051aadab7aSMatthias Ringwald #define CHAR_RETURN     '\n'
1061aadab7aSMatthias Ringwald #define CHAR_ESCAPE      27
1071aadab7aSMatthias Ringwald #define CHAR_TAB         '\t'
1081aadab7aSMatthias Ringwald #define CHAR_BACKSPACE   0x7f
1091aadab7aSMatthias Ringwald 
1101aadab7aSMatthias Ringwald /**
1111aadab7aSMatthias Ringwald  * English (US)
1121aadab7aSMatthias Ringwald  */
1131aadab7aSMatthias Ringwald static const uint8_t keytable_us_none [] = {
1141aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /*   0-3 */
1151aadab7aSMatthias Ringwald         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',                   /*  4-13 */
1161aadab7aSMatthias Ringwald         'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',                   /* 14-23 */
1171aadab7aSMatthias Ringwald         'u', 'v', 'w', 'x', 'y', 'z',                                       /* 24-29 */
1181aadab7aSMatthias Ringwald         '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',                   /* 30-39 */
1191aadab7aSMatthias Ringwald         CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ',            /* 40-44 */
1201aadab7aSMatthias Ringwald         '-', '=', '[', ']', '\\', CHAR_ILLEGAL, ';', '\'', 0x60, ',',       /* 45-54 */
1211aadab7aSMatthias Ringwald         '.', '/', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,   /* 55-60 */
1221aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 61-64 */
1231aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 65-68 */
1241aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 69-72 */
1251aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 73-76 */
1261aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 77-80 */
1271aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 81-84 */
1281aadab7aSMatthias Ringwald         '*', '-', '+', '\n', '1', '2', '3', '4', '5',                       /* 85-97 */
1291aadab7aSMatthias Ringwald         '6', '7', '8', '9', '0', '.', 0xa7,                                 /* 97-100 */
1301aadab7aSMatthias Ringwald };
1311aadab7aSMatthias Ringwald 
1321aadab7aSMatthias Ringwald static const uint8_t keytable_us_shift[] = {
1331aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /*  0-3  */
1341aadab7aSMatthias Ringwald         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',                   /*  4-13 */
1351aadab7aSMatthias Ringwald         'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',                   /* 14-23 */
1361aadab7aSMatthias Ringwald         'U', 'V', 'W', 'X', 'Y', 'Z',                                       /* 24-29 */
1371aadab7aSMatthias Ringwald         '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',                   /* 30-39 */
1381aadab7aSMatthias Ringwald         CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ',            /* 40-44 */
1391aadab7aSMatthias Ringwald         '_', '+', '{', '}', '|', CHAR_ILLEGAL, ':', '"', 0x7E, '<',         /* 45-54 */
1401aadab7aSMatthias Ringwald         '>', '?', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,   /* 55-60 */
1411aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 61-64 */
1421aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 65-68 */
1431aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 69-72 */
1441aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 73-76 */
1451aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 77-80 */
1461aadab7aSMatthias Ringwald         CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL,             /* 81-84 */
1471aadab7aSMatthias Ringwald         '*', '-', '+', '\n', '1', '2', '3', '4', '5',                       /* 85-97 */
1481aadab7aSMatthias Ringwald         '6', '7', '8', '9', '0', '.', 0xb1,                                 /* 97-100 */
1491aadab7aSMatthias Ringwald };
1501aadab7aSMatthias Ringwald 
1511aadab7aSMatthias Ringwald /**
1521aadab7aSMatthias Ringwald  * @section HOG Boot Keyboard Handler
1531aadab7aSMatthias Ringwald  * @text Boot Keyboard Input Report contains a report of format
154cf5ed549SMatthias Ringwald  * [ modifier, reserved, 6 x usage for key 1..6 from keyboard usage]
1551aadab7aSMatthias Ringwald  * Track new usages, map key usage to actual character and simulate terminal
1561aadab7aSMatthias Ringwald  */
1571aadab7aSMatthias Ringwald 
1581aadab7aSMatthias Ringwald /* last_keys stores keyboard report to detect new key down events */
1591aadab7aSMatthias Ringwald #define NUM_KEYS 6
1601aadab7aSMatthias Ringwald static uint8_t last_keys[NUM_KEYS];
1611aadab7aSMatthias Ringwald 
handle_boot_keyboard_event(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)1621aadab7aSMatthias Ringwald static void handle_boot_keyboard_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
1631aadab7aSMatthias Ringwald     UNUSED(packet_type);
1641aadab7aSMatthias Ringwald     UNUSED(channel);
1651aadab7aSMatthias Ringwald     UNUSED(size);
1661aadab7aSMatthias Ringwald 
1671aadab7aSMatthias Ringwald     if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return;
1681aadab7aSMatthias Ringwald     const uint8_t * data = gatt_event_notification_get_value(packet);
1691aadab7aSMatthias Ringwald 
1701aadab7aSMatthias Ringwald     uint8_t new_keys[NUM_KEYS];
1711aadab7aSMatthias Ringwald     memset(new_keys, 0, sizeof(new_keys));
1721aadab7aSMatthias Ringwald     int new_keys_count = 0;
1731aadab7aSMatthias Ringwald 
174555559d5SMatthias Ringwald     bool shift = (data[0] & 0x22) != 0;
1751aadab7aSMatthias Ringwald 
1761aadab7aSMatthias Ringwald     uint8_t key_index;
1771aadab7aSMatthias Ringwald     for (key_index = 0; key_index < NUM_KEYS; key_index++){
1781aadab7aSMatthias Ringwald 
1790801ef92SMatthias Ringwald         uint8_t usage = data[2 + key_index];
1801aadab7aSMatthias Ringwald         if (usage == 0) continue;
1811aadab7aSMatthias Ringwald         if (usage >= sizeof(keytable_us_none)) continue;
1821aadab7aSMatthias Ringwald 
1831aadab7aSMatthias Ringwald         // store new keys
1841aadab7aSMatthias Ringwald         new_keys[new_keys_count++] = usage;
1851aadab7aSMatthias Ringwald 
1861aadab7aSMatthias Ringwald         // check if usage was used last time (and ignore in that case)
1871aadab7aSMatthias Ringwald         int i;
1881aadab7aSMatthias Ringwald         for (i=0;i<NUM_KEYS;i++){
1891aadab7aSMatthias Ringwald             if (usage == last_keys[i]){
1901aadab7aSMatthias Ringwald                 usage = 0;
1911aadab7aSMatthias Ringwald             }
1921aadab7aSMatthias Ringwald         }
1931aadab7aSMatthias Ringwald         if (usage == 0) continue;
1941aadab7aSMatthias Ringwald 
1951aadab7aSMatthias Ringwald         // lookup character based on usage + shift modifier
1961aadab7aSMatthias Ringwald         uint8_t key;
1971aadab7aSMatthias Ringwald         if (shift){
1981aadab7aSMatthias Ringwald             key = keytable_us_shift[usage];
1991aadab7aSMatthias Ringwald         } else {
2001aadab7aSMatthias Ringwald             key = keytable_us_none[usage];
2011aadab7aSMatthias Ringwald         }
2021aadab7aSMatthias Ringwald         if (key == CHAR_ILLEGAL) continue;
2031aadab7aSMatthias Ringwald         if (key == CHAR_BACKSPACE){
2041aadab7aSMatthias Ringwald             printf("\b \b");    // go back one char, print space, go back one char again
2051aadab7aSMatthias Ringwald             continue;
2061aadab7aSMatthias Ringwald         }
2071aadab7aSMatthias Ringwald         printf("%c", key);
2081aadab7aSMatthias Ringwald     }
2091aadab7aSMatthias Ringwald 
2101aadab7aSMatthias Ringwald     // store current as last report
2111aadab7aSMatthias Ringwald     memcpy(last_keys, new_keys, NUM_KEYS);
2121aadab7aSMatthias Ringwald }
2131aadab7aSMatthias Ringwald 
2141aadab7aSMatthias Ringwald /**
2151aadab7aSMatthias Ringwald  * @section HOG Boot Mouse Handler
2161aadab7aSMatthias Ringwald  * @text Boot Mouse Input Report contains a report of format
2171aadab7aSMatthias Ringwald  * [ buttons, dx, dy, dz = scroll wheel]
2181aadab7aSMatthias Ringwald  * Decode packet and print on stdout
2191aadab7aSMatthias Ringwald  *
2201aadab7aSMatthias Ringwald  * @param packet_type
2211aadab7aSMatthias Ringwald  * @param channel
2221aadab7aSMatthias Ringwald  * @param packet
2231aadab7aSMatthias Ringwald  * @param size
2241aadab7aSMatthias Ringwald  */
handle_boot_mouse_event(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)2251aadab7aSMatthias Ringwald static void handle_boot_mouse_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
2261aadab7aSMatthias Ringwald     UNUSED(packet_type);
2271aadab7aSMatthias Ringwald     UNUSED(channel);
2281aadab7aSMatthias Ringwald     UNUSED(size);
2291aadab7aSMatthias Ringwald 
2301aadab7aSMatthias Ringwald     if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION) return;
2311aadab7aSMatthias Ringwald     const uint8_t * data = gatt_event_notification_get_value(packet);
2321aadab7aSMatthias Ringwald     uint8_t buttons =          data[0];
2331aadab7aSMatthias Ringwald     int8_t dx       = (int8_t) data[1];
2341aadab7aSMatthias Ringwald     int8_t dy       = (int8_t) data[2];
2351aadab7aSMatthias Ringwald     int8_t dwheel   = (int8_t) data[3];
2361aadab7aSMatthias Ringwald     printf("Mouse: %i, %i - wheel %i - buttons 0x%02x\n", dx, dy, dwheel, buttons);
2371aadab7aSMatthias Ringwald }
2381aadab7aSMatthias Ringwald 
2391aadab7aSMatthias Ringwald /**
2401aadab7aSMatthias Ringwald  * @section Test if advertisement contains HID UUID
2411aadab7aSMatthias Ringwald  * @param packet
2421aadab7aSMatthias Ringwald  * @param size
2431aadab7aSMatthias Ringwald  * @returns true if it does
2441aadab7aSMatthias Ringwald  */
adv_event_contains_hid_service(const uint8_t * packet)2451aadab7aSMatthias Ringwald static bool adv_event_contains_hid_service(const uint8_t * packet){
2461aadab7aSMatthias Ringwald     const uint8_t * ad_data = gap_event_advertising_report_get_data(packet);
2470801ef92SMatthias Ringwald     uint8_t ad_len = gap_event_advertising_report_get_data_length(packet);
2481aadab7aSMatthias Ringwald     return ad_data_contains_uuid16(ad_len, ad_data, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE);
2491aadab7aSMatthias Ringwald }
2501aadab7aSMatthias Ringwald 
2511aadab7aSMatthias Ringwald /**
2521aadab7aSMatthias Ringwald  * Start scanning
2531aadab7aSMatthias Ringwald  */
hog_start_scan(void)2541aadab7aSMatthias Ringwald static void hog_start_scan(void){
2551aadab7aSMatthias Ringwald     printf("Scanning for LE HID devices...\n");
2561aadab7aSMatthias Ringwald     app_state = W4_HID_DEVICE_FOUND;
2571aadab7aSMatthias Ringwald     // Passive scanning, 100% (scan interval = scan window)
2581aadab7aSMatthias Ringwald     gap_set_scan_parameters(0,48,48);
2591aadab7aSMatthias Ringwald     gap_start_scan();
2601aadab7aSMatthias Ringwald }
2611aadab7aSMatthias Ringwald 
2621aadab7aSMatthias Ringwald /**
2631aadab7aSMatthias Ringwald  * Handle timeout for outgoing connection
2641aadab7aSMatthias Ringwald  * @param ts
2651aadab7aSMatthias Ringwald  */
hog_connection_timeout(btstack_timer_source_t * ts)2661aadab7aSMatthias Ringwald static void hog_connection_timeout(btstack_timer_source_t * ts){
2671aadab7aSMatthias Ringwald     UNUSED(ts);
2681aadab7aSMatthias Ringwald     printf("Timeout - abort connection\n");
2691aadab7aSMatthias Ringwald     gap_connect_cancel();
2701aadab7aSMatthias Ringwald     hog_start_scan();
2711aadab7aSMatthias Ringwald }
2721aadab7aSMatthias Ringwald 
2731aadab7aSMatthias Ringwald 
2741aadab7aSMatthias Ringwald /**
2751aadab7aSMatthias Ringwald  * Connect to remote device but set timer for timeout
2761aadab7aSMatthias Ringwald  */
hog_connect(void)277da076097SMatthias Ringwald static void hog_connect(void) {
2781aadab7aSMatthias Ringwald     // set timer
2791aadab7aSMatthias Ringwald     btstack_run_loop_set_timer(&connection_timer, 10000);
2801aadab7aSMatthias Ringwald     btstack_run_loop_set_timer_handler(&connection_timer, &hog_connection_timeout);
2811aadab7aSMatthias Ringwald     btstack_run_loop_add_timer(&connection_timer);
2821aadab7aSMatthias Ringwald     app_state = W4_CONNECTED;
2831aadab7aSMatthias Ringwald     gap_connect(remote_device.addr, remote_device.addr_type);
2841aadab7aSMatthias Ringwald }
2851aadab7aSMatthias Ringwald 
2861aadab7aSMatthias Ringwald /**
2871aadab7aSMatthias Ringwald  * Handle timer event to trigger reconnect
2881aadab7aSMatthias Ringwald  * @param ts
2891aadab7aSMatthias Ringwald  */
hog_reconnect_timeout(btstack_timer_source_t * ts)2901aadab7aSMatthias Ringwald static void hog_reconnect_timeout(btstack_timer_source_t * ts){
2911aadab7aSMatthias Ringwald     UNUSED(ts);
2921aadab7aSMatthias Ringwald     switch (app_state){
2931aadab7aSMatthias Ringwald         case W4_TIMEOUT_THEN_RECONNECT:
2941aadab7aSMatthias Ringwald             hog_connect();
2951aadab7aSMatthias Ringwald             break;
2961aadab7aSMatthias Ringwald         case W4_TIMEOUT_THEN_SCAN:
2971aadab7aSMatthias Ringwald             hog_start_scan();
2981aadab7aSMatthias Ringwald             break;
2991aadab7aSMatthias Ringwald         default:
3001aadab7aSMatthias Ringwald             break;
3011aadab7aSMatthias Ringwald     }
3021aadab7aSMatthias Ringwald }
3031aadab7aSMatthias Ringwald 
3041aadab7aSMatthias Ringwald /**
3051aadab7aSMatthias Ringwald  * Start connecting after boot up: connect to last used device if possible, start scan otherwise
3061aadab7aSMatthias Ringwald  */
hog_start_connect(void)3071aadab7aSMatthias Ringwald static void hog_start_connect(void){
3081aadab7aSMatthias Ringwald     // check if we have a bonded device
3091aadab7aSMatthias Ringwald     btstack_tlv_get_instance(&btstack_tlv_singleton_impl, &btstack_tlv_singleton_context);
3101aadab7aSMatthias Ringwald     if (btstack_tlv_singleton_impl){
3111aadab7aSMatthias Ringwald         int len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, TLV_TAG_HOGD, (uint8_t *) &remote_device, sizeof(remote_device));
3121aadab7aSMatthias Ringwald         if (len == sizeof(remote_device)){
3131aadab7aSMatthias 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));
3141aadab7aSMatthias Ringwald             hog_connect();
3151aadab7aSMatthias Ringwald             return;
3161aadab7aSMatthias Ringwald         }
3171aadab7aSMatthias Ringwald     }
3181aadab7aSMatthias Ringwald     // otherwise, scan for HID devices
3191aadab7aSMatthias Ringwald     hog_start_scan();
3201aadab7aSMatthias Ringwald }
3211aadab7aSMatthias Ringwald 
3221aadab7aSMatthias Ringwald /**
3231aadab7aSMatthias Ringwald  * In case of error, disconnect and start scanning again
3241aadab7aSMatthias Ringwald  */
handle_outgoing_connection_error(void)3251aadab7aSMatthias Ringwald static void handle_outgoing_connection_error(void){
3261aadab7aSMatthias Ringwald     printf("Error occurred, disconnect and start over\n");
3271aadab7aSMatthias Ringwald     gap_disconnect(connection_handle);
3281aadab7aSMatthias Ringwald     hog_start_scan();
3291aadab7aSMatthias Ringwald }
3301aadab7aSMatthias Ringwald 
3311aadab7aSMatthias Ringwald /**
3321aadab7aSMatthias Ringwald  * Handle GATT Client Events dependent on current state
3331aadab7aSMatthias Ringwald  *
3341aadab7aSMatthias Ringwald  * @param packet_type
3351aadab7aSMatthias Ringwald  * @param channel
3361aadab7aSMatthias Ringwald  * @param packet
3371aadab7aSMatthias Ringwald  * @param size
3381aadab7aSMatthias Ringwald  */
handle_gatt_client_event(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)3391aadab7aSMatthias Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
3401aadab7aSMatthias Ringwald     UNUSED(packet_type);
3411aadab7aSMatthias Ringwald     UNUSED(channel);
3421aadab7aSMatthias Ringwald     UNUSED(size);
3431aadab7aSMatthias Ringwald     gatt_client_characteristic_t characteristic;
3446058cb0dSMatthias Ringwald     uint8_t att_status;
3451aadab7aSMatthias Ringwald     static uint8_t boot_protocol_mode = 0;
3461aadab7aSMatthias Ringwald 
3471aadab7aSMatthias Ringwald     switch (app_state) {
3481aadab7aSMatthias Ringwald         case W4_HID_SERVICE_FOUND:
3491aadab7aSMatthias Ringwald             switch (hci_event_packet_get_type(packet)) {
3501aadab7aSMatthias Ringwald                 case GATT_EVENT_SERVICE_QUERY_RESULT:
3511aadab7aSMatthias Ringwald                     // store service (we expect only one)
3521aadab7aSMatthias Ringwald                     gatt_event_service_query_result_get_service(packet, &hid_service);
3531aadab7aSMatthias Ringwald                     break;
3541aadab7aSMatthias Ringwald                 case GATT_EVENT_QUERY_COMPLETE:
3556058cb0dSMatthias Ringwald                     att_status = gatt_event_query_complete_get_att_status(packet);
3566058cb0dSMatthias Ringwald                     if (att_status != ATT_ERROR_SUCCESS) {
357fcd55a0bSMilanka Ringwald                         printf("Query failed, ATT Error 0x%02x.\n", att_status);
3581aadab7aSMatthias Ringwald                         handle_outgoing_connection_error();
3591aadab7aSMatthias Ringwald                         break;
3601aadab7aSMatthias Ringwald                     }
3611aadab7aSMatthias Ringwald                     printf("Find required HID Service Characteristics...\n");
3621aadab7aSMatthias Ringwald                     app_state = W4_HID_CHARACTERISTICS_FOUND;
3631aadab7aSMatthias Ringwald                     gatt_client_discover_characteristics_for_service(&handle_gatt_client_event, connection_handle, &hid_service);
3641aadab7aSMatthias Ringwald                     break;
3651aadab7aSMatthias Ringwald                 default:
3661aadab7aSMatthias Ringwald                     break;
3671aadab7aSMatthias Ringwald             }
3681aadab7aSMatthias Ringwald             break;
3691aadab7aSMatthias Ringwald         case W4_HID_CHARACTERISTICS_FOUND:
3701aadab7aSMatthias Ringwald             switch (hci_event_packet_get_type(packet)){
3711aadab7aSMatthias Ringwald                 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
3721aadab7aSMatthias Ringwald                     // get characteristic
3731aadab7aSMatthias Ringwald                     gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
3741aadab7aSMatthias Ringwald                     switch (characteristic.uuid16){
3751aadab7aSMatthias Ringwald                         case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT:
3761aadab7aSMatthias Ringwald                             printf("Found CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT, value handle 0x%04x\n", characteristic.value_handle);
3771aadab7aSMatthias Ringwald                             memcpy(&boot_keyboard_input_characteristic, &characteristic, sizeof(gatt_client_characteristic_t));
3781aadab7aSMatthias Ringwald                             break;
3791aadab7aSMatthias Ringwald                         case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT:
3801aadab7aSMatthias Ringwald                             printf("Found CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT, value handle 0x%04x\n", characteristic.value_handle);
3811aadab7aSMatthias Ringwald                             memcpy(&boot_mouse_input_characteristic, &characteristic, sizeof(gatt_client_characteristic_t));
3821aadab7aSMatthias Ringwald                             break;
3831aadab7aSMatthias Ringwald                         case ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE:
3841aadab7aSMatthias Ringwald                             printf("Found CHARACTERISTIC_PROTOCOL_MODE\n");
3851aadab7aSMatthias Ringwald                             memcpy(&protocol_mode_characteristic, &characteristic, sizeof(gatt_client_characteristic_t));
3861aadab7aSMatthias Ringwald                             break;
3871aadab7aSMatthias Ringwald                         default:
3881aadab7aSMatthias Ringwald                             break;
3891aadab7aSMatthias Ringwald                     }
3901aadab7aSMatthias Ringwald                     break;
3911aadab7aSMatthias Ringwald                 case GATT_EVENT_QUERY_COMPLETE:
3926058cb0dSMatthias Ringwald                     att_status = gatt_event_query_complete_get_att_status(packet);
3936058cb0dSMatthias Ringwald                     if (att_status != ATT_ERROR_SUCCESS) {
394fcd55a0bSMilanka Ringwald                         printf("Query failed, ATT Error 0x%02x.\n", att_status);
3951aadab7aSMatthias Ringwald                         handle_outgoing_connection_error();
3961aadab7aSMatthias Ringwald                         break;
3971aadab7aSMatthias Ringwald                     }
3981aadab7aSMatthias Ringwald                     printf("Enable Notifications for Boot Keyboard Input Report..\n");
3991aadab7aSMatthias Ringwald                     app_state = W4_BOOT_KEYBOARD_ENABLED;
4001aadab7aSMatthias Ringwald                     gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, connection_handle, &boot_keyboard_input_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
4011aadab7aSMatthias Ringwald                     break;
4021aadab7aSMatthias Ringwald                 default:
4031aadab7aSMatthias Ringwald                     break;
4041aadab7aSMatthias Ringwald             }
4051aadab7aSMatthias Ringwald             break;
4061aadab7aSMatthias Ringwald         case W4_BOOT_KEYBOARD_ENABLED:
4071aadab7aSMatthias Ringwald             switch (hci_event_packet_get_type(packet)){
4081aadab7aSMatthias Ringwald                 case GATT_EVENT_QUERY_COMPLETE:
4096058cb0dSMatthias Ringwald                     att_status = gatt_event_query_complete_get_att_status(packet);
4106058cb0dSMatthias Ringwald                     if (att_status != ATT_ERROR_SUCCESS) {
411fcd55a0bSMilanka Ringwald                         printf("Query failed, ATT Error 0x%02x.\n", att_status);
4121aadab7aSMatthias Ringwald                         handle_outgoing_connection_error();
4131aadab7aSMatthias Ringwald                         break;
4141aadab7aSMatthias Ringwald                     }
4151aadab7aSMatthias Ringwald                     // setup listener
4161aadab7aSMatthias Ringwald                     gatt_client_listen_for_characteristic_value_updates(&keyboard_notifications, &handle_boot_keyboard_event, connection_handle, &boot_keyboard_input_characteristic);
4171aadab7aSMatthias Ringwald                     //
4181aadab7aSMatthias Ringwald                     printf("Enable Notifications for Boot Mouse Input Report..\n");
4191aadab7aSMatthias Ringwald                     app_state = W4_BOOT_MOUSE_ENABLED;
4201aadab7aSMatthias Ringwald                     gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, connection_handle, &boot_mouse_input_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
4211aadab7aSMatthias Ringwald                     break;
4221aadab7aSMatthias Ringwald                 default:
4231aadab7aSMatthias Ringwald                     break;
4241aadab7aSMatthias Ringwald             }
4251aadab7aSMatthias Ringwald             break;
4261aadab7aSMatthias Ringwald         case W4_BOOT_MOUSE_ENABLED:
4271aadab7aSMatthias Ringwald             switch (hci_event_packet_get_type(packet)) {
4281aadab7aSMatthias Ringwald                 case GATT_EVENT_QUERY_COMPLETE:
4296058cb0dSMatthias Ringwald                     att_status = gatt_event_query_complete_get_att_status(packet);
4306058cb0dSMatthias Ringwald                     if (att_status != ATT_ERROR_SUCCESS) {
431fcd55a0bSMilanka Ringwald                         printf("Query failed, ATT Error 0x%02x.\n", att_status);
4321aadab7aSMatthias Ringwald                         handle_outgoing_connection_error();
4331aadab7aSMatthias Ringwald                         break;
4341aadab7aSMatthias Ringwald                     }
4351aadab7aSMatthias Ringwald                     // setup listener
4361aadab7aSMatthias Ringwald                     gatt_client_listen_for_characteristic_value_updates(&mouse_notifications, &handle_boot_mouse_event, connection_handle, &boot_mouse_input_characteristic);
4371aadab7aSMatthias Ringwald 
4381aadab7aSMatthias Ringwald                     // switch to boot mode
4391aadab7aSMatthias Ringwald                     printf("Set Protocol Mode to Boot Mode..\n");
4401aadab7aSMatthias Ringwald                     gatt_client_write_value_of_characteristic_without_response(connection_handle, protocol_mode_characteristic.value_handle, 1, &boot_protocol_mode);
4411aadab7aSMatthias Ringwald 
4421aadab7aSMatthias Ringwald                     // store device as bonded
4431aadab7aSMatthias Ringwald                     if (btstack_tlv_singleton_impl){
4441aadab7aSMatthias Ringwald                         btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, TLV_TAG_HOGD, (const uint8_t *) &remote_device, sizeof(remote_device));
4451aadab7aSMatthias Ringwald                     }
4461aadab7aSMatthias Ringwald                     // done
4471aadab7aSMatthias Ringwald                     printf("Ready - please start typing or mousing..\n");
4481aadab7aSMatthias Ringwald                     app_state = READY;
4491aadab7aSMatthias Ringwald                     break;
4501aadab7aSMatthias Ringwald                 default:
4511aadab7aSMatthias Ringwald                     break;
4521aadab7aSMatthias Ringwald             }
4531aadab7aSMatthias Ringwald             break;
4541aadab7aSMatthias Ringwald         default:
4551aadab7aSMatthias Ringwald             break;
4561aadab7aSMatthias Ringwald     }
4571aadab7aSMatthias Ringwald }
4581aadab7aSMatthias Ringwald 
4591aadab7aSMatthias Ringwald /* LISTING_START(packetHandler): Packet Handler */
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)4601aadab7aSMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
4611aadab7aSMatthias Ringwald     /* LISTING_PAUSE */
4621aadab7aSMatthias Ringwald     UNUSED(channel);
4631aadab7aSMatthias Ringwald     UNUSED(size);
4641aadab7aSMatthias Ringwald     uint8_t   event;
4651aadab7aSMatthias Ringwald     /* LISTING_RESUME */
4661aadab7aSMatthias Ringwald     switch (packet_type) {
4671aadab7aSMatthias Ringwald         case HCI_EVENT_PACKET:
4681aadab7aSMatthias Ringwald             event = hci_event_packet_get_type(packet);
4691aadab7aSMatthias Ringwald             switch (event) {
4701aadab7aSMatthias Ringwald                 case BTSTACK_EVENT_STATE:
4711aadab7aSMatthias Ringwald                     if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break;
4721aadab7aSMatthias Ringwald                     btstack_assert(app_state == W4_WORKING);
4731aadab7aSMatthias Ringwald                     hog_start_connect();
4741aadab7aSMatthias Ringwald                     break;
4751aadab7aSMatthias Ringwald                 case GAP_EVENT_ADVERTISING_REPORT:
4761aadab7aSMatthias Ringwald                     if (app_state != W4_HID_DEVICE_FOUND) break;
4771aadab7aSMatthias Ringwald                     if (adv_event_contains_hid_service(packet) == false) break;
4781aadab7aSMatthias Ringwald                     // stop scan
4791aadab7aSMatthias Ringwald                     gap_stop_scan();
4801aadab7aSMatthias Ringwald                     // store remote device address and type
4811aadab7aSMatthias Ringwald                     gap_event_advertising_report_get_address(packet, remote_device.addr);
4821aadab7aSMatthias Ringwald                     remote_device.addr_type = gap_event_advertising_report_get_address_type(packet);
4831aadab7aSMatthias Ringwald                     // connect
4841aadab7aSMatthias 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));
4851aadab7aSMatthias Ringwald                     hog_connect();
4861aadab7aSMatthias Ringwald                     break;
4871aadab7aSMatthias Ringwald                 case HCI_EVENT_DISCONNECTION_COMPLETE:
4882901a9b7SMilanka Ringwald                     if (app_state != READY) break;
4892901a9b7SMilanka Ringwald 
4901aadab7aSMatthias Ringwald                     connection_handle = HCI_CON_HANDLE_INVALID;
4911aadab7aSMatthias Ringwald                     switch (app_state){
4921aadab7aSMatthias Ringwald                         case READY:
4931aadab7aSMatthias Ringwald                             printf("\nDisconnected, try to reconnect...\n");
4941aadab7aSMatthias Ringwald                             app_state = W4_TIMEOUT_THEN_RECONNECT;
4951aadab7aSMatthias Ringwald                             break;
4961aadab7aSMatthias Ringwald                         default:
4971aadab7aSMatthias Ringwald                             printf("\nDisconnected, start over...\n");
4981aadab7aSMatthias Ringwald                             app_state = W4_TIMEOUT_THEN_SCAN;
4991aadab7aSMatthias Ringwald                             break;
5001aadab7aSMatthias Ringwald                     }
5011aadab7aSMatthias Ringwald                     // set timer
5021aadab7aSMatthias Ringwald                     btstack_run_loop_set_timer(&connection_timer, 100);
5031aadab7aSMatthias Ringwald                     btstack_run_loop_set_timer_handler(&connection_timer, &hog_reconnect_timeout);
5041aadab7aSMatthias Ringwald                     btstack_run_loop_add_timer(&connection_timer);
5051aadab7aSMatthias Ringwald                     break;
506*bba48196SMatthias Ringwald                 case HCI_EVENT_META_GAP:
5071aadab7aSMatthias Ringwald                     // wait for connection complete
508*bba48196SMatthias Ringwald                     if (hci_event_gap_meta_get_subevent_code(packet) != GAP_SUBEVENT_LE_CONNECTION_COMPLETE) break;
5091aadab7aSMatthias Ringwald                     if (app_state != W4_CONNECTED) return;
5101aadab7aSMatthias Ringwald                     btstack_run_loop_remove_timer(&connection_timer);
511*bba48196SMatthias Ringwald                     connection_handle = gap_subevent_le_connection_complete_get_connection_handle(packet);
5121aadab7aSMatthias Ringwald                     // request security
5131aadab7aSMatthias Ringwald                     app_state = W4_ENCRYPTED;
5141aadab7aSMatthias Ringwald                     sm_request_pairing(connection_handle);
5151aadab7aSMatthias Ringwald                     break;
5161aadab7aSMatthias Ringwald                 default:
5171aadab7aSMatthias Ringwald                     break;
5181aadab7aSMatthias Ringwald             }
5191aadab7aSMatthias Ringwald             break;
5201aadab7aSMatthias Ringwald         default:
5211aadab7aSMatthias Ringwald             break;
5221aadab7aSMatthias Ringwald     }
5231aadab7aSMatthias Ringwald }
5241aadab7aSMatthias Ringwald /* LISTING_END */
5251aadab7aSMatthias Ringwald 
5261aadab7aSMatthias Ringwald /* @section HCI packet handler
5271aadab7aSMatthias Ringwald  *
5281aadab7aSMatthias Ringwald  * @text The SM packet handler receives Security Manager Events required for pairing.
5291aadab7aSMatthias Ringwald  * It also receives events generated during Identity Resolving
5301aadab7aSMatthias Ringwald  * see Listing SMPacketHandler.
5311aadab7aSMatthias Ringwald  */
5321aadab7aSMatthias Ringwald 
5331aadab7aSMatthias Ringwald /* LISTING_START(SMPacketHandler): Scanning and receiving advertisements */
5341aadab7aSMatthias Ringwald 
sm_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)5351aadab7aSMatthias Ringwald static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
5361aadab7aSMatthias Ringwald     UNUSED(channel);
5371aadab7aSMatthias Ringwald     UNUSED(size);
5381aadab7aSMatthias Ringwald 
5391aadab7aSMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
5401aadab7aSMatthias Ringwald 
5413f6e1c81SMatthias Ringwald     bool connect_to_service = false;
5423f6e1c81SMatthias Ringwald 
5431aadab7aSMatthias Ringwald     switch (hci_event_packet_get_type(packet)) {
5441aadab7aSMatthias Ringwald         case SM_EVENT_JUST_WORKS_REQUEST:
5451aadab7aSMatthias Ringwald             printf("Just works requested\n");
5461aadab7aSMatthias Ringwald             sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
5471aadab7aSMatthias Ringwald             break;
5481aadab7aSMatthias Ringwald         case SM_EVENT_NUMERIC_COMPARISON_REQUEST:
5491aadab7aSMatthias Ringwald             printf("Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet));
5501aadab7aSMatthias Ringwald             sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet));
5511aadab7aSMatthias Ringwald             break;
5521aadab7aSMatthias Ringwald         case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
5531aadab7aSMatthias Ringwald             printf("Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet));
5541aadab7aSMatthias Ringwald             break;
5551aadab7aSMatthias Ringwald         case SM_EVENT_PAIRING_COMPLETE:
5561aadab7aSMatthias Ringwald             switch (sm_event_pairing_complete_get_status(packet)){
5571aadab7aSMatthias Ringwald                 case ERROR_CODE_SUCCESS:
5581aadab7aSMatthias Ringwald                     printf("Pairing complete, success\n");
5593f6e1c81SMatthias Ringwald                     connect_to_service = true;
5601aadab7aSMatthias Ringwald                     break;
5611aadab7aSMatthias Ringwald                 case ERROR_CODE_CONNECTION_TIMEOUT:
5621aadab7aSMatthias Ringwald                     printf("Pairing failed, timeout\n");
5631aadab7aSMatthias Ringwald                     break;
5641aadab7aSMatthias Ringwald                 case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION:
56578404023SMatthias Ringwald                     printf("Pairing failed, disconnected\n");
5661aadab7aSMatthias Ringwald                     break;
5671aadab7aSMatthias Ringwald                 case ERROR_CODE_AUTHENTICATION_FAILURE:
5681aadab7aSMatthias Ringwald                     printf("Pairing failed, reason = %u\n", sm_event_pairing_complete_get_reason(packet));
5691aadab7aSMatthias Ringwald                     break;
5701aadab7aSMatthias Ringwald                 default:
5711aadab7aSMatthias Ringwald                     break;
5721aadab7aSMatthias Ringwald             }
5731aadab7aSMatthias Ringwald             break;
5743f6e1c81SMatthias Ringwald         case SM_EVENT_REENCRYPTION_COMPLETE:
5753f6e1c81SMatthias Ringwald             printf("Re-encryption complete, success\n");
5763f6e1c81SMatthias Ringwald             connect_to_service = true;
5773f6e1c81SMatthias Ringwald             break;
5781aadab7aSMatthias Ringwald         default:
5791aadab7aSMatthias Ringwald             break;
5801aadab7aSMatthias Ringwald     }
5813f6e1c81SMatthias Ringwald 
5823f6e1c81SMatthias Ringwald     if (connect_to_service){
5833f6e1c81SMatthias Ringwald         // continue - query primary services
5843f6e1c81SMatthias Ringwald         printf("Search for HID service.\n");
5853f6e1c81SMatthias Ringwald         app_state = W4_HID_SERVICE_FOUND;
5863f6e1c81SMatthias Ringwald         gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, connection_handle, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE);
5873f6e1c81SMatthias Ringwald     }
5881aadab7aSMatthias Ringwald }
5891aadab7aSMatthias Ringwald /* LISTING_END */
5901aadab7aSMatthias Ringwald 
5911aadab7aSMatthias Ringwald int btstack_main(int argc, const char * argv[]);
btstack_main(int argc,const char * argv[])5921aadab7aSMatthias Ringwald int btstack_main(int argc, const char * argv[]){
5931aadab7aSMatthias Ringwald 
5941aadab7aSMatthias Ringwald     (void)argc;
5951aadab7aSMatthias Ringwald     (void)argv;
5961aadab7aSMatthias Ringwald 
5971aadab7aSMatthias Ringwald     /* LISTING_START(HogBootHostSetup): HID-over-GATT Boot Host Setup */
5981aadab7aSMatthias Ringwald 
5993f6e1c81SMatthias Ringwald     l2cap_init();
6003f6e1c81SMatthias Ringwald 
6013f6e1c81SMatthias Ringwald     // setup SM: Display only
6023f6e1c81SMatthias Ringwald     sm_init();
6033f6e1c81SMatthias Ringwald     sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY);
6043f6e1c81SMatthias Ringwald     sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION | SM_AUTHREQ_BONDING);
6053f6e1c81SMatthias Ringwald 
6063f6e1c81SMatthias Ringwald     //
6073f6e1c81SMatthias Ringwald     gatt_client_init();
6083f6e1c81SMatthias Ringwald 
6091aadab7aSMatthias Ringwald     // register for events from HCI
6101aadab7aSMatthias Ringwald     hci_event_callback_registration.callback = &packet_handler;
6111aadab7aSMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
6121aadab7aSMatthias Ringwald 
6131aadab7aSMatthias Ringwald     // register for events from Security Manager
6141aadab7aSMatthias Ringwald     sm_event_callback_registration.callback = &sm_packet_handler;
6151aadab7aSMatthias Ringwald     sm_add_event_handler(&sm_event_callback_registration);
6161aadab7aSMatthias Ringwald 
6171aadab7aSMatthias Ringwald     /* LISTING_END */
6181aadab7aSMatthias Ringwald 
6191aadab7aSMatthias Ringwald     // Disable stdout buffering
6200801ef92SMatthias Ringwald 	setvbuf(stdin, NULL, _IONBF, 0);
6211aadab7aSMatthias Ringwald 
6221aadab7aSMatthias Ringwald     app_state = W4_WORKING;
6231aadab7aSMatthias Ringwald 
6241aadab7aSMatthias Ringwald     // Turn on the device
6251aadab7aSMatthias Ringwald     hci_power_control(HCI_POWER_ON);
6261aadab7aSMatthias Ringwald     return 0;
6271aadab7aSMatthias Ringwald }
6281aadab7aSMatthias Ringwald 
6291aadab7aSMatthias Ringwald /* EXAMPLE_END */
630