xref: /btstack/example/hog_boot_host_demo.c (revision 1aadab7a3b8d0c79dbe1777da79fbc5d8e370975)
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