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 231aadab7aSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 241aadab7aSMatthias Ringwald * RINGWALD 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 441aadab7aSMatthias Ringwald /* EXAMPLE_START(hog_boot_host_demo): HID-over-GATT Boot Host Demo 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 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 179cf5ed549SMatthias Ringwald uint16_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 */ 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 */ 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); 2471aadab7aSMatthias Ringwald uint16_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 */ 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 */ 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 */ 277*da076097SMatthias 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 */ 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 */ 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 */ 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 */ 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; 3441aadab7aSMatthias Ringwald static uint8_t boot_protocol_mode = 0; 3451aadab7aSMatthias Ringwald 3461aadab7aSMatthias Ringwald switch (app_state) { 3471aadab7aSMatthias Ringwald case W4_HID_SERVICE_FOUND: 3481aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 3491aadab7aSMatthias Ringwald case GATT_EVENT_SERVICE_QUERY_RESULT: 3501aadab7aSMatthias Ringwald // store service (we expect only one) 3511aadab7aSMatthias Ringwald gatt_event_service_query_result_get_service(packet, &hid_service); 3521aadab7aSMatthias Ringwald break; 3531aadab7aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 3541aadab7aSMatthias Ringwald if (gatt_event_query_complete_get_att_status(packet) != ATT_ERROR_SUCCESS) { 3551aadab7aSMatthias Ringwald printf("ATT Error status %x.\n", gatt_event_query_complete_get_att_status(packet)); 3561aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 3571aadab7aSMatthias Ringwald break; 3581aadab7aSMatthias Ringwald } 3591aadab7aSMatthias Ringwald printf("Find required HID Service Characteristics...\n"); 3601aadab7aSMatthias Ringwald app_state = W4_HID_CHARACTERISTICS_FOUND; 3611aadab7aSMatthias Ringwald gatt_client_discover_characteristics_for_service(&handle_gatt_client_event, connection_handle, &hid_service); 3621aadab7aSMatthias Ringwald break; 3631aadab7aSMatthias Ringwald default: 3641aadab7aSMatthias Ringwald break; 3651aadab7aSMatthias Ringwald } 3661aadab7aSMatthias Ringwald break; 3671aadab7aSMatthias Ringwald case W4_HID_CHARACTERISTICS_FOUND: 3681aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 3691aadab7aSMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 3701aadab7aSMatthias Ringwald // get characteristic 3711aadab7aSMatthias Ringwald gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 3721aadab7aSMatthias Ringwald switch (characteristic.uuid16){ 3731aadab7aSMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT: 3741aadab7aSMatthias Ringwald printf("Found CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT, value handle 0x%04x\n", characteristic.value_handle); 3751aadab7aSMatthias Ringwald memcpy(&boot_keyboard_input_characteristic, &characteristic, sizeof(gatt_client_characteristic_t)); 3761aadab7aSMatthias Ringwald break; 3771aadab7aSMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT: 3781aadab7aSMatthias Ringwald printf("Found CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT, value handle 0x%04x\n", characteristic.value_handle); 3791aadab7aSMatthias Ringwald memcpy(&boot_mouse_input_characteristic, &characteristic, sizeof(gatt_client_characteristic_t)); 3801aadab7aSMatthias Ringwald break; 3811aadab7aSMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE: 3821aadab7aSMatthias Ringwald printf("Found CHARACTERISTIC_PROTOCOL_MODE\n"); 3831aadab7aSMatthias Ringwald memcpy(&protocol_mode_characteristic, &characteristic, sizeof(gatt_client_characteristic_t)); 3841aadab7aSMatthias Ringwald break; 3851aadab7aSMatthias Ringwald default: 3861aadab7aSMatthias Ringwald break; 3871aadab7aSMatthias Ringwald } 3881aadab7aSMatthias Ringwald break; 3891aadab7aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 3901aadab7aSMatthias Ringwald if (gatt_event_query_complete_get_att_status(packet) != ATT_ERROR_SUCCESS) { 3911aadab7aSMatthias Ringwald printf("ATT Error status %x.\n", gatt_event_query_complete_get_att_status(packet)); 3921aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 3931aadab7aSMatthias Ringwald break; 3941aadab7aSMatthias Ringwald } 3951aadab7aSMatthias Ringwald printf("Enable Notifications for Boot Keyboard Input Report..\n"); 3961aadab7aSMatthias Ringwald app_state = W4_BOOT_KEYBOARD_ENABLED; 3971aadab7aSMatthias Ringwald gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, connection_handle, &boot_keyboard_input_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 3981aadab7aSMatthias Ringwald break; 3991aadab7aSMatthias Ringwald default: 4001aadab7aSMatthias Ringwald break; 4011aadab7aSMatthias Ringwald } 4021aadab7aSMatthias Ringwald break; 4031aadab7aSMatthias Ringwald case W4_BOOT_KEYBOARD_ENABLED: 4041aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 4051aadab7aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 4061aadab7aSMatthias Ringwald if (gatt_event_query_complete_get_att_status(packet) != ATT_ERROR_SUCCESS) { 4071aadab7aSMatthias Ringwald printf("ATT Error status %x.\n", gatt_event_query_complete_get_att_status(packet)); 4081aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 4091aadab7aSMatthias Ringwald break; 4101aadab7aSMatthias Ringwald } 4111aadab7aSMatthias Ringwald // setup listener 4121aadab7aSMatthias Ringwald gatt_client_listen_for_characteristic_value_updates(&keyboard_notifications, &handle_boot_keyboard_event, connection_handle, &boot_keyboard_input_characteristic); 4131aadab7aSMatthias Ringwald // 4141aadab7aSMatthias Ringwald printf("Enable Notifications for Boot Mouse Input Report..\n"); 4151aadab7aSMatthias Ringwald app_state = W4_BOOT_MOUSE_ENABLED; 4161aadab7aSMatthias Ringwald gatt_client_write_client_characteristic_configuration(&handle_gatt_client_event, connection_handle, &boot_mouse_input_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 4171aadab7aSMatthias Ringwald break; 4181aadab7aSMatthias Ringwald default: 4191aadab7aSMatthias Ringwald break; 4201aadab7aSMatthias Ringwald } 4211aadab7aSMatthias Ringwald break; 4221aadab7aSMatthias Ringwald case W4_BOOT_MOUSE_ENABLED: 4231aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 4241aadab7aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 4251aadab7aSMatthias Ringwald if (gatt_event_query_complete_get_att_status(packet) != ATT_ERROR_SUCCESS) { 4261aadab7aSMatthias Ringwald printf("ATT Error status %x.\n", gatt_event_query_complete_get_att_status(packet)); 4271aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 4281aadab7aSMatthias Ringwald break; 4291aadab7aSMatthias Ringwald } 4301aadab7aSMatthias Ringwald // setup listener 4311aadab7aSMatthias Ringwald gatt_client_listen_for_characteristic_value_updates(&mouse_notifications, &handle_boot_mouse_event, connection_handle, &boot_mouse_input_characteristic); 4321aadab7aSMatthias Ringwald 4331aadab7aSMatthias Ringwald // switch to boot mode 4341aadab7aSMatthias Ringwald printf("Set Protocol Mode to Boot Mode..\n"); 4351aadab7aSMatthias Ringwald gatt_client_write_value_of_characteristic_without_response(connection_handle, protocol_mode_characteristic.value_handle, 1, &boot_protocol_mode); 4361aadab7aSMatthias Ringwald 4371aadab7aSMatthias Ringwald // store device as bonded 4381aadab7aSMatthias Ringwald if (btstack_tlv_singleton_impl){ 4391aadab7aSMatthias Ringwald btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, TLV_TAG_HOGD, (const uint8_t *) &remote_device, sizeof(remote_device)); 4401aadab7aSMatthias Ringwald } 4411aadab7aSMatthias Ringwald // done 4421aadab7aSMatthias Ringwald printf("Ready - please start typing or mousing..\n"); 4431aadab7aSMatthias Ringwald app_state = READY; 4441aadab7aSMatthias Ringwald break; 4451aadab7aSMatthias Ringwald default: 4461aadab7aSMatthias Ringwald break; 4471aadab7aSMatthias Ringwald } 4481aadab7aSMatthias Ringwald break; 4491aadab7aSMatthias Ringwald default: 4501aadab7aSMatthias Ringwald break; 4511aadab7aSMatthias Ringwald } 4521aadab7aSMatthias Ringwald } 4531aadab7aSMatthias Ringwald 4541aadab7aSMatthias Ringwald /* LISTING_START(packetHandler): Packet Handler */ 4551aadab7aSMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 4561aadab7aSMatthias Ringwald /* LISTING_PAUSE */ 4571aadab7aSMatthias Ringwald UNUSED(channel); 4581aadab7aSMatthias Ringwald UNUSED(size); 4591aadab7aSMatthias Ringwald uint8_t event; 4601aadab7aSMatthias Ringwald /* LISTING_RESUME */ 4611aadab7aSMatthias Ringwald switch (packet_type) { 4621aadab7aSMatthias Ringwald case HCI_EVENT_PACKET: 4631aadab7aSMatthias Ringwald event = hci_event_packet_get_type(packet); 4641aadab7aSMatthias Ringwald switch (event) { 4651aadab7aSMatthias Ringwald case BTSTACK_EVENT_STATE: 4661aadab7aSMatthias Ringwald if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break; 4671aadab7aSMatthias Ringwald btstack_assert(app_state == W4_WORKING); 4681aadab7aSMatthias Ringwald hog_start_connect(); 4691aadab7aSMatthias Ringwald break; 4701aadab7aSMatthias Ringwald case GAP_EVENT_ADVERTISING_REPORT: 4711aadab7aSMatthias Ringwald if (app_state != W4_HID_DEVICE_FOUND) break; 4721aadab7aSMatthias Ringwald if (adv_event_contains_hid_service(packet) == false) break; 4731aadab7aSMatthias Ringwald // stop scan 4741aadab7aSMatthias Ringwald gap_stop_scan(); 4751aadab7aSMatthias Ringwald // store remote device address and type 4761aadab7aSMatthias Ringwald gap_event_advertising_report_get_address(packet, remote_device.addr); 4771aadab7aSMatthias Ringwald remote_device.addr_type = gap_event_advertising_report_get_address_type(packet); 4781aadab7aSMatthias Ringwald // connect 4791aadab7aSMatthias 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)); 4801aadab7aSMatthias Ringwald hog_connect(); 4811aadab7aSMatthias Ringwald break; 4821aadab7aSMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 4831aadab7aSMatthias Ringwald connection_handle = HCI_CON_HANDLE_INVALID; 4841aadab7aSMatthias Ringwald switch (app_state){ 4851aadab7aSMatthias Ringwald case READY: 4861aadab7aSMatthias Ringwald printf("\nDisconnected, try to reconnect...\n"); 4871aadab7aSMatthias Ringwald app_state = W4_TIMEOUT_THEN_RECONNECT; 4881aadab7aSMatthias Ringwald break; 4891aadab7aSMatthias Ringwald default: 4901aadab7aSMatthias Ringwald printf("\nDisconnected, start over...\n"); 4911aadab7aSMatthias Ringwald app_state = W4_TIMEOUT_THEN_SCAN; 4921aadab7aSMatthias Ringwald break; 4931aadab7aSMatthias Ringwald } 4941aadab7aSMatthias Ringwald // set timer 4951aadab7aSMatthias Ringwald btstack_run_loop_set_timer(&connection_timer, 100); 4961aadab7aSMatthias Ringwald btstack_run_loop_set_timer_handler(&connection_timer, &hog_reconnect_timeout); 4971aadab7aSMatthias Ringwald btstack_run_loop_add_timer(&connection_timer); 4981aadab7aSMatthias Ringwald break; 4991aadab7aSMatthias Ringwald case HCI_EVENT_LE_META: 5001aadab7aSMatthias Ringwald // wait for connection complete 5011aadab7aSMatthias Ringwald if (hci_event_le_meta_get_subevent_code(packet) != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break; 5021aadab7aSMatthias Ringwald if (app_state != W4_CONNECTED) return; 5031aadab7aSMatthias Ringwald btstack_run_loop_remove_timer(&connection_timer); 5041aadab7aSMatthias Ringwald connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet); 5051aadab7aSMatthias Ringwald // request security 5061aadab7aSMatthias Ringwald app_state = W4_ENCRYPTED; 5071aadab7aSMatthias Ringwald sm_request_pairing(connection_handle); 5081aadab7aSMatthias Ringwald break; 5091aadab7aSMatthias Ringwald case HCI_EVENT_ENCRYPTION_CHANGE: 5101aadab7aSMatthias Ringwald if (connection_handle != hci_event_encryption_change_get_connection_handle(packet)) break; 5111aadab7aSMatthias Ringwald printf("Connection encrypted: %u\n", hci_event_encryption_change_get_encryption_enabled(packet)); 5121aadab7aSMatthias Ringwald if (hci_event_encryption_change_get_encryption_enabled(packet) == 0){ 5131aadab7aSMatthias Ringwald printf("Encryption failed -> abort\n"); 5141aadab7aSMatthias Ringwald handle_outgoing_connection_error(); 5151aadab7aSMatthias Ringwald break; 5161aadab7aSMatthias Ringwald } 5171aadab7aSMatthias Ringwald // continue - query primary services 5181aadab7aSMatthias Ringwald printf("Search for HID service.\n"); 5191aadab7aSMatthias Ringwald app_state = W4_HID_SERVICE_FOUND; 5201aadab7aSMatthias Ringwald gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, connection_handle, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE); 5211aadab7aSMatthias Ringwald break; 5221aadab7aSMatthias Ringwald default: 5231aadab7aSMatthias Ringwald break; 5241aadab7aSMatthias Ringwald } 5251aadab7aSMatthias Ringwald break; 5261aadab7aSMatthias Ringwald default: 5271aadab7aSMatthias Ringwald break; 5281aadab7aSMatthias Ringwald } 5291aadab7aSMatthias Ringwald } 5301aadab7aSMatthias Ringwald /* LISTING_END */ 5311aadab7aSMatthias Ringwald 5321aadab7aSMatthias Ringwald /* @section HCI packet handler 5331aadab7aSMatthias Ringwald * 5341aadab7aSMatthias Ringwald * @text The SM packet handler receives Security Manager Events required for pairing. 5351aadab7aSMatthias Ringwald * It also receives events generated during Identity Resolving 5361aadab7aSMatthias Ringwald * see Listing SMPacketHandler. 5371aadab7aSMatthias Ringwald */ 5381aadab7aSMatthias Ringwald 5391aadab7aSMatthias Ringwald /* LISTING_START(SMPacketHandler): Scanning and receiving advertisements */ 5401aadab7aSMatthias Ringwald 5411aadab7aSMatthias Ringwald static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 5421aadab7aSMatthias Ringwald UNUSED(channel); 5431aadab7aSMatthias Ringwald UNUSED(size); 5441aadab7aSMatthias Ringwald 5451aadab7aSMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 5461aadab7aSMatthias Ringwald 5471aadab7aSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 5481aadab7aSMatthias Ringwald case SM_EVENT_JUST_WORKS_REQUEST: 5491aadab7aSMatthias Ringwald printf("Just works requested\n"); 5501aadab7aSMatthias Ringwald sm_just_works_confirm(sm_event_just_works_request_get_handle(packet)); 5511aadab7aSMatthias Ringwald break; 5521aadab7aSMatthias Ringwald case SM_EVENT_NUMERIC_COMPARISON_REQUEST: 5531aadab7aSMatthias Ringwald printf("Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet)); 5541aadab7aSMatthias Ringwald sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet)); 5551aadab7aSMatthias Ringwald break; 5561aadab7aSMatthias Ringwald case SM_EVENT_PASSKEY_DISPLAY_NUMBER: 5571aadab7aSMatthias Ringwald printf("Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet)); 5581aadab7aSMatthias Ringwald break; 5591aadab7aSMatthias Ringwald case SM_EVENT_PAIRING_COMPLETE: 5601aadab7aSMatthias Ringwald switch (sm_event_pairing_complete_get_status(packet)){ 5611aadab7aSMatthias Ringwald case ERROR_CODE_SUCCESS: 5621aadab7aSMatthias Ringwald printf("Pairing complete, success\n"); 5631aadab7aSMatthias Ringwald break; 5641aadab7aSMatthias Ringwald case ERROR_CODE_CONNECTION_TIMEOUT: 5651aadab7aSMatthias Ringwald printf("Pairing failed, timeout\n"); 5661aadab7aSMatthias Ringwald break; 5671aadab7aSMatthias Ringwald case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION: 5681aadab7aSMatthias Ringwald printf("Pairing faileed, disconnected\n"); 5691aadab7aSMatthias Ringwald break; 5701aadab7aSMatthias Ringwald case ERROR_CODE_AUTHENTICATION_FAILURE: 5711aadab7aSMatthias Ringwald printf("Pairing failed, reason = %u\n", sm_event_pairing_complete_get_reason(packet)); 5721aadab7aSMatthias Ringwald break; 5731aadab7aSMatthias Ringwald default: 5741aadab7aSMatthias Ringwald break; 5751aadab7aSMatthias Ringwald } 5761aadab7aSMatthias Ringwald break; 5771aadab7aSMatthias Ringwald default: 5781aadab7aSMatthias Ringwald break; 5791aadab7aSMatthias Ringwald } 5801aadab7aSMatthias Ringwald } 5811aadab7aSMatthias Ringwald /* LISTING_END */ 5821aadab7aSMatthias Ringwald 5831aadab7aSMatthias Ringwald int btstack_main(int argc, const char * argv[]); 5841aadab7aSMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 5851aadab7aSMatthias Ringwald 5861aadab7aSMatthias Ringwald (void)argc; 5871aadab7aSMatthias Ringwald (void)argv; 5881aadab7aSMatthias Ringwald 5891aadab7aSMatthias Ringwald /* LISTING_START(HogBootHostSetup): HID-over-GATT Boot Host Setup */ 5901aadab7aSMatthias Ringwald 5911aadab7aSMatthias Ringwald // register for events from HCI 5921aadab7aSMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 5931aadab7aSMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 5941aadab7aSMatthias Ringwald 5951aadab7aSMatthias Ringwald // register for events from Security Manager 5961aadab7aSMatthias Ringwald sm_event_callback_registration.callback = &sm_packet_handler; 5971aadab7aSMatthias Ringwald sm_add_event_handler(&sm_event_callback_registration); 5981aadab7aSMatthias Ringwald 5991aadab7aSMatthias Ringwald // setup le device db 6001aadab7aSMatthias Ringwald le_device_db_init(); 6011aadab7aSMatthias Ringwald 6021aadab7aSMatthias Ringwald // 6031aadab7aSMatthias Ringwald l2cap_init(); 6041aadab7aSMatthias Ringwald sm_init(); 6051aadab7aSMatthias Ringwald gatt_client_init(); 6061aadab7aSMatthias Ringwald 6071aadab7aSMatthias Ringwald /* LISTING_END */ 6081aadab7aSMatthias Ringwald 6091aadab7aSMatthias Ringwald // Disable stdout buffering 6101aadab7aSMatthias Ringwald setbuf(stdout, NULL); 6111aadab7aSMatthias Ringwald 6121aadab7aSMatthias Ringwald app_state = W4_WORKING; 6131aadab7aSMatthias Ringwald 6141aadab7aSMatthias Ringwald // Turn on the device 6151aadab7aSMatthias Ringwald hci_power_control(HCI_POWER_ON); 6161aadab7aSMatthias Ringwald return 0; 6171aadab7aSMatthias Ringwald } 6181aadab7aSMatthias Ringwald 6191aadab7aSMatthias Ringwald /* EXAMPLE_END */ 620