1*a4bfc4feSMatthias Ringwald /* 2*a4bfc4feSMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3*a4bfc4feSMatthias Ringwald * 4*a4bfc4feSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*a4bfc4feSMatthias Ringwald * modification, are permitted provided that the following conditions 6*a4bfc4feSMatthias Ringwald * are met: 7*a4bfc4feSMatthias Ringwald * 8*a4bfc4feSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*a4bfc4feSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*a4bfc4feSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*a4bfc4feSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*a4bfc4feSMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*a4bfc4feSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*a4bfc4feSMatthias Ringwald * contributors may be used to endorse or promote products derived 15*a4bfc4feSMatthias Ringwald * from this software without specific prior written permission. 16*a4bfc4feSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*a4bfc4feSMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*a4bfc4feSMatthias Ringwald * monetary gain. 19*a4bfc4feSMatthias Ringwald * 20*a4bfc4feSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*a4bfc4feSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*a4bfc4feSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*a4bfc4feSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*a4bfc4feSMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*a4bfc4feSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*a4bfc4feSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*a4bfc4feSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*a4bfc4feSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*a4bfc4feSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*a4bfc4feSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*a4bfc4feSMatthias Ringwald * SUCH DAMAGE. 32*a4bfc4feSMatthias Ringwald * 33*a4bfc4feSMatthias Ringwald * Please inquire about commercial licensing options at 34*a4bfc4feSMatthias Ringwald * [email protected] 35*a4bfc4feSMatthias Ringwald * 36*a4bfc4feSMatthias Ringwald */ 37*a4bfc4feSMatthias Ringwald 38*a4bfc4feSMatthias Ringwald #define __BTSTACK_FILE__ "hog_keyboard_demo.c" 39*a4bfc4feSMatthias Ringwald 40*a4bfc4feSMatthias Ringwald // ***************************************************************************** 41*a4bfc4feSMatthias Ringwald /* EXAMPLE_START(hog_keyboard_demo): HID-over-GATT Keyboard 42*a4bfc4feSMatthias Ringwald */ 43*a4bfc4feSMatthias Ringwald // ***************************************************************************** 44*a4bfc4feSMatthias Ringwald 45*a4bfc4feSMatthias Ringwald #include <stdint.h> 46*a4bfc4feSMatthias Ringwald #include <stdio.h> 47*a4bfc4feSMatthias Ringwald #include <stdlib.h> 48*a4bfc4feSMatthias Ringwald #include <string.h> 49*a4bfc4feSMatthias Ringwald #include <inttypes.h> 50*a4bfc4feSMatthias Ringwald 51*a4bfc4feSMatthias Ringwald #include "hog_keyboard_demo.h" 52*a4bfc4feSMatthias Ringwald 53*a4bfc4feSMatthias Ringwald #include "btstack.h" 54*a4bfc4feSMatthias Ringwald 55*a4bfc4feSMatthias Ringwald #include "ble/gatt-service/battery_service_server.h" 56*a4bfc4feSMatthias Ringwald #include "ble/gatt-service/device_information_service_server.h" 57*a4bfc4feSMatthias Ringwald #include "ble/gatt-service/hids_device.h" 58*a4bfc4feSMatthias Ringwald 59*a4bfc4feSMatthias Ringwald // from USB HID Specification 1.1, Appendix B.1 60*a4bfc4feSMatthias Ringwald const uint8_t hid_descriptor_keyboard_boot_mode[] = { 61*a4bfc4feSMatthias Ringwald 62*a4bfc4feSMatthias Ringwald 0x05, 0x01, // Usage Page (Generic Desktop) 63*a4bfc4feSMatthias Ringwald 0x09, 0x06, // Usage (Keyboard) 64*a4bfc4feSMatthias Ringwald 0xa1, 0x01, // Collection (Application) 65*a4bfc4feSMatthias Ringwald 66*a4bfc4feSMatthias Ringwald // Modifier byte 67*a4bfc4feSMatthias Ringwald 68*a4bfc4feSMatthias Ringwald 0x75, 0x01, // Report Size (1) 69*a4bfc4feSMatthias Ringwald 0x95, 0x08, // Report Count (8) 70*a4bfc4feSMatthias Ringwald 0x05, 0x07, // Usage Page (Key codes) 71*a4bfc4feSMatthias Ringwald 0x19, 0xe0, // Usage Minimum (Keyboard LeftControl) 72*a4bfc4feSMatthias Ringwald 0x29, 0xe7, // Usage Maxium (Keyboard Right GUI) 73*a4bfc4feSMatthias Ringwald 0x15, 0x00, // Logical Minimum (0) 74*a4bfc4feSMatthias Ringwald 0x25, 0x01, // Logical Maximum (1) 75*a4bfc4feSMatthias Ringwald 0x81, 0x02, // Input (Data, Variable, Absolute) 76*a4bfc4feSMatthias Ringwald 77*a4bfc4feSMatthias Ringwald // Reserved byte 78*a4bfc4feSMatthias Ringwald 79*a4bfc4feSMatthias Ringwald 0x75, 0x01, // Report Size (1) 80*a4bfc4feSMatthias Ringwald 0x95, 0x08, // Report Count (8) 81*a4bfc4feSMatthias Ringwald 0x81, 0x03, // Input (Constant, Variable, Absolute) 82*a4bfc4feSMatthias Ringwald 83*a4bfc4feSMatthias Ringwald // LED report + padding 84*a4bfc4feSMatthias Ringwald 85*a4bfc4feSMatthias Ringwald 0x95, 0x05, // Report Count (5) 86*a4bfc4feSMatthias Ringwald 0x75, 0x01, // Report Size (1) 87*a4bfc4feSMatthias Ringwald 0x05, 0x08, // Usage Page (LEDs) 88*a4bfc4feSMatthias Ringwald 0x19, 0x01, // Usage Minimum (Num Lock) 89*a4bfc4feSMatthias Ringwald 0x29, 0x05, // Usage Maxium (Kana) 90*a4bfc4feSMatthias Ringwald 0x91, 0x02, // Output (Data, Variable, Absolute) 91*a4bfc4feSMatthias Ringwald 92*a4bfc4feSMatthias Ringwald 0x95, 0x01, // Report Count (1) 93*a4bfc4feSMatthias Ringwald 0x75, 0x03, // Report Size (3) 94*a4bfc4feSMatthias Ringwald 0x91, 0x03, // Output (Constant, Variable, Absolute) 95*a4bfc4feSMatthias Ringwald 96*a4bfc4feSMatthias Ringwald // Keycodes 97*a4bfc4feSMatthias Ringwald 98*a4bfc4feSMatthias Ringwald 0x95, 0x06, // Report Count (6) 99*a4bfc4feSMatthias Ringwald 0x75, 0x08, // Report Size (8) 100*a4bfc4feSMatthias Ringwald 0x15, 0x00, // Logical Minimum (0) 101*a4bfc4feSMatthias Ringwald 0x25, 0xff, // Logical Maximum (1) 102*a4bfc4feSMatthias Ringwald 0x05, 0x07, // Usage Page (Key codes) 103*a4bfc4feSMatthias Ringwald 0x19, 0x00, // Usage Minimum (Reserved (no event indicated)) 104*a4bfc4feSMatthias Ringwald 0x29, 0xff, // Usage Maxium (Reserved) 105*a4bfc4feSMatthias Ringwald 0x81, 0x00, // Input (Data, Array) 106*a4bfc4feSMatthias Ringwald 107*a4bfc4feSMatthias Ringwald 0xc0, // End collection 108*a4bfc4feSMatthias Ringwald }; 109*a4bfc4feSMatthias Ringwald 110*a4bfc4feSMatthias Ringwald 111*a4bfc4feSMatthias Ringwald 112*a4bfc4feSMatthias Ringwald // 113*a4bfc4feSMatthias Ringwald #define CHAR_ILLEGAL 0xff 114*a4bfc4feSMatthias Ringwald #define CHAR_RETURN '\n' 115*a4bfc4feSMatthias Ringwald #define CHAR_ESCAPE 27 116*a4bfc4feSMatthias Ringwald #define CHAR_TAB '\t' 117*a4bfc4feSMatthias Ringwald #define CHAR_BACKSPACE 0x7f 118*a4bfc4feSMatthias Ringwald 119*a4bfc4feSMatthias Ringwald // Simplified US Keyboard with Shift modifier 120*a4bfc4feSMatthias Ringwald 121*a4bfc4feSMatthias Ringwald /** 122*a4bfc4feSMatthias Ringwald * English (US) 123*a4bfc4feSMatthias Ringwald */ 124*a4bfc4feSMatthias Ringwald static const uint8_t keytable_us_none [] = { 125*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 0-3 */ 126*a4bfc4feSMatthias Ringwald 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 4-13 */ 127*a4bfc4feSMatthias Ringwald 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 14-23 */ 128*a4bfc4feSMatthias Ringwald 'u', 'v', 'w', 'x', 'y', 'z', /* 24-29 */ 129*a4bfc4feSMatthias Ringwald '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', /* 30-39 */ 130*a4bfc4feSMatthias Ringwald CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', /* 40-44 */ 131*a4bfc4feSMatthias Ringwald '-', '=', '[', ']', '\\', CHAR_ILLEGAL, ';', '\'', 0x60, ',', /* 45-54 */ 132*a4bfc4feSMatthias Ringwald '.', '/', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 55-60 */ 133*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 61-64 */ 134*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 65-68 */ 135*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 69-72 */ 136*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 73-76 */ 137*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 77-80 */ 138*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 81-84 */ 139*a4bfc4feSMatthias Ringwald '*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */ 140*a4bfc4feSMatthias Ringwald '6', '7', '8', '9', '0', '.', 0xa7, /* 97-100 */ 141*a4bfc4feSMatthias Ringwald }; 142*a4bfc4feSMatthias Ringwald 143*a4bfc4feSMatthias Ringwald static const uint8_t keytable_us_shift[] = { 144*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 0-3 */ 145*a4bfc4feSMatthias Ringwald 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 4-13 */ 146*a4bfc4feSMatthias Ringwald 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 14-23 */ 147*a4bfc4feSMatthias Ringwald 'U', 'V', 'W', 'X', 'Y', 'Z', /* 24-29 */ 148*a4bfc4feSMatthias Ringwald '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', /* 30-39 */ 149*a4bfc4feSMatthias Ringwald CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', /* 40-44 */ 150*a4bfc4feSMatthias Ringwald '_', '+', '{', '}', '|', CHAR_ILLEGAL, ':', '"', 0x7E, '<', /* 45-54 */ 151*a4bfc4feSMatthias Ringwald '>', '?', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 55-60 */ 152*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 61-64 */ 153*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 65-68 */ 154*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 69-72 */ 155*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 73-76 */ 156*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 77-80 */ 157*a4bfc4feSMatthias Ringwald CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 81-84 */ 158*a4bfc4feSMatthias Ringwald '*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */ 159*a4bfc4feSMatthias Ringwald '6', '7', '8', '9', '0', '.', 0xb1, /* 97-100 */ 160*a4bfc4feSMatthias Ringwald }; 161*a4bfc4feSMatthias Ringwald 162*a4bfc4feSMatthias Ringwald // static btstack_timer_source_t heartbeat; 163*a4bfc4feSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 164*a4bfc4feSMatthias Ringwald static btstack_packet_callback_registration_t sm_event_callback_registration; 165*a4bfc4feSMatthias Ringwald static uint8_t battery = 100; 166*a4bfc4feSMatthias Ringwald static hci_con_handle_t con_handle; 167*a4bfc4feSMatthias Ringwald 168*a4bfc4feSMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 169*a4bfc4feSMatthias Ringwald 170*a4bfc4feSMatthias Ringwald const uint8_t adv_data[] = { 171*a4bfc4feSMatthias Ringwald // Flags general discoverable, BR/EDR not supported 172*a4bfc4feSMatthias Ringwald 0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, 173*a4bfc4feSMatthias Ringwald // Name 174*a4bfc4feSMatthias Ringwald 0x0d, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'H', 'I', 'D', ' ', 'K', 'e', 'y', 'b', 'o', 'a', 'r', 'd', 175*a4bfc4feSMatthias Ringwald // 16-bit Service UUIDs 176*a4bfc4feSMatthias Ringwald 0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE & 0xff, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE >> 8, 177*a4bfc4feSMatthias Ringwald }; 178*a4bfc4feSMatthias Ringwald const uint8_t adv_data_len = sizeof(adv_data); 179*a4bfc4feSMatthias Ringwald 180*a4bfc4feSMatthias Ringwald static void le_keyboard_setup(void){ 181*a4bfc4feSMatthias Ringwald 182*a4bfc4feSMatthias Ringwald // register for HCI events 183*a4bfc4feSMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 184*a4bfc4feSMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 185*a4bfc4feSMatthias Ringwald 186*a4bfc4feSMatthias Ringwald l2cap_init(); 187*a4bfc4feSMatthias Ringwald 188*a4bfc4feSMatthias Ringwald // setup le device db 189*a4bfc4feSMatthias Ringwald le_device_db_init(); 190*a4bfc4feSMatthias Ringwald 191*a4bfc4feSMatthias Ringwald // setup SM: Display only 192*a4bfc4feSMatthias Ringwald sm_init(); 193*a4bfc4feSMatthias Ringwald sm_event_callback_registration.callback = &packet_handler; 194*a4bfc4feSMatthias Ringwald sm_add_event_handler(&sm_event_callback_registration); 195*a4bfc4feSMatthias Ringwald sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY); 196*a4bfc4feSMatthias Ringwald sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION | SM_AUTHREQ_BONDING); 197*a4bfc4feSMatthias Ringwald 198*a4bfc4feSMatthias Ringwald // setup ATT server 199*a4bfc4feSMatthias Ringwald att_server_init(profile_data, NULL, NULL); 200*a4bfc4feSMatthias Ringwald 201*a4bfc4feSMatthias Ringwald // setup battery service 202*a4bfc4feSMatthias Ringwald battery_service_server_init(battery); 203*a4bfc4feSMatthias Ringwald 204*a4bfc4feSMatthias Ringwald // setup device information service 205*a4bfc4feSMatthias Ringwald device_information_service_server_init(); 206*a4bfc4feSMatthias Ringwald 207*a4bfc4feSMatthias Ringwald // setup HID Device service 208*a4bfc4feSMatthias Ringwald hids_device_init(0, hid_descriptor_keyboard_boot_mode, sizeof(hid_descriptor_keyboard_boot_mode)); 209*a4bfc4feSMatthias Ringwald hids_device_register_packet_handler(packet_handler); 210*a4bfc4feSMatthias Ringwald 211*a4bfc4feSMatthias Ringwald // setup advertisements 212*a4bfc4feSMatthias Ringwald uint16_t adv_int_min = 0x0030; 213*a4bfc4feSMatthias Ringwald uint16_t adv_int_max = 0x0030; 214*a4bfc4feSMatthias Ringwald uint8_t adv_type = 0; 215*a4bfc4feSMatthias Ringwald bd_addr_t null_addr; 216*a4bfc4feSMatthias Ringwald memset(null_addr, 0, 6); 217*a4bfc4feSMatthias Ringwald gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); 218*a4bfc4feSMatthias Ringwald gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data); 219*a4bfc4feSMatthias Ringwald gap_advertisements_enable(1); 220*a4bfc4feSMatthias Ringwald } 221*a4bfc4feSMatthias Ringwald 222*a4bfc4feSMatthias Ringwald // HID Keyboard lookup 223*a4bfc4feSMatthias Ringwald static int lookup_keycode(uint8_t character, const uint8_t * table, int size, uint8_t * keycode){ 224*a4bfc4feSMatthias Ringwald int i; 225*a4bfc4feSMatthias Ringwald for (i=0;i<size;i++){ 226*a4bfc4feSMatthias Ringwald if (table[i] != character) continue; 227*a4bfc4feSMatthias Ringwald *keycode = i; 228*a4bfc4feSMatthias Ringwald return 1; 229*a4bfc4feSMatthias Ringwald } 230*a4bfc4feSMatthias Ringwald return 0; 231*a4bfc4feSMatthias Ringwald } 232*a4bfc4feSMatthias Ringwald 233*a4bfc4feSMatthias Ringwald static int keycode_and_modifer_us_for_character(uint8_t character, uint8_t * keycode, uint8_t * modifier){ 234*a4bfc4feSMatthias Ringwald int found; 235*a4bfc4feSMatthias Ringwald found = lookup_keycode(character, keytable_us_none, sizeof(keytable_us_none), keycode); 236*a4bfc4feSMatthias Ringwald if (found) { 237*a4bfc4feSMatthias Ringwald *modifier = 0; // none 238*a4bfc4feSMatthias Ringwald return 1; 239*a4bfc4feSMatthias Ringwald } 240*a4bfc4feSMatthias Ringwald found = lookup_keycode(character, keytable_us_shift, sizeof(keytable_us_shift), keycode); 241*a4bfc4feSMatthias Ringwald if (found) { 242*a4bfc4feSMatthias Ringwald *modifier = 2; // shift 243*a4bfc4feSMatthias Ringwald return 1; 244*a4bfc4feSMatthias Ringwald } 245*a4bfc4feSMatthias Ringwald return 0; 246*a4bfc4feSMatthias Ringwald } 247*a4bfc4feSMatthias Ringwald 248*a4bfc4feSMatthias Ringwald // HID Report sending 249*a4bfc4feSMatthias Ringwald 250*a4bfc4feSMatthias Ringwald static void send_report(int modifier, int keycode){ 251*a4bfc4feSMatthias Ringwald uint8_t report[] = { /* 0xa1, */ modifier, 0, 0, keycode, 0, 0, 0, 0, 0}; 252*a4bfc4feSMatthias Ringwald hids_device_send_input_report(con_handle, report, sizeof(report)); 253*a4bfc4feSMatthias Ringwald } 254*a4bfc4feSMatthias Ringwald 255*a4bfc4feSMatthias Ringwald // Demo Application 256*a4bfc4feSMatthias Ringwald 257*a4bfc4feSMatthias Ringwald #ifdef HAVE_BTSTACK_STDIN 258*a4bfc4feSMatthias Ringwald 259*a4bfc4feSMatthias Ringwald // On systems with STDIN, we can directly type on the console 260*a4bfc4feSMatthias Ringwald static enum { 261*a4bfc4feSMatthias Ringwald W4_INPUT, 262*a4bfc4feSMatthias Ringwald W4_CAN_SEND_FROM_BUFFER, 263*a4bfc4feSMatthias Ringwald W4_CAN_SEND_KEY_UP, 264*a4bfc4feSMatthias Ringwald } state; 265*a4bfc4feSMatthias Ringwald 266*a4bfc4feSMatthias Ringwald // Buffer for 20 characters 267*a4bfc4feSMatthias Ringwald static uint8_t ascii_input_storage[20]; 268*a4bfc4feSMatthias Ringwald static btstack_ring_buffer_t ascii_input_buffer; 269*a4bfc4feSMatthias Ringwald 270*a4bfc4feSMatthias Ringwald static void typing_can_send_now(void){ 271*a4bfc4feSMatthias Ringwald switch (state){ 272*a4bfc4feSMatthias Ringwald case W4_CAN_SEND_FROM_BUFFER: 273*a4bfc4feSMatthias Ringwald while (1){ 274*a4bfc4feSMatthias Ringwald uint8_t c; 275*a4bfc4feSMatthias Ringwald uint32_t num_bytes_read; 276*a4bfc4feSMatthias Ringwald 277*a4bfc4feSMatthias Ringwald btstack_ring_buffer_read(&ascii_input_buffer, &c, 1, &num_bytes_read); 278*a4bfc4feSMatthias Ringwald if (num_bytes_read == 0){ 279*a4bfc4feSMatthias Ringwald state = W4_INPUT; 280*a4bfc4feSMatthias Ringwald break; 281*a4bfc4feSMatthias Ringwald } 282*a4bfc4feSMatthias Ringwald 283*a4bfc4feSMatthias Ringwald uint8_t modifier; 284*a4bfc4feSMatthias Ringwald uint8_t keycode; 285*a4bfc4feSMatthias Ringwald int found = keycode_and_modifer_us_for_character(c, &keycode, &modifier); 286*a4bfc4feSMatthias Ringwald if (!found) continue; 287*a4bfc4feSMatthias Ringwald 288*a4bfc4feSMatthias Ringwald send_report(modifier, keycode); 289*a4bfc4feSMatthias Ringwald state = W4_CAN_SEND_KEY_UP; 290*a4bfc4feSMatthias Ringwald hids_device_request_can_send_now_event(con_handle); 291*a4bfc4feSMatthias Ringwald break; 292*a4bfc4feSMatthias Ringwald } 293*a4bfc4feSMatthias Ringwald break; 294*a4bfc4feSMatthias Ringwald case W4_CAN_SEND_KEY_UP: 295*a4bfc4feSMatthias Ringwald send_report(0, 0); 296*a4bfc4feSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&ascii_input_buffer)){ 297*a4bfc4feSMatthias Ringwald state = W4_CAN_SEND_FROM_BUFFER; 298*a4bfc4feSMatthias Ringwald hids_device_request_can_send_now_event(con_handle); 299*a4bfc4feSMatthias Ringwald } else { 300*a4bfc4feSMatthias Ringwald state = W4_INPUT; 301*a4bfc4feSMatthias Ringwald } 302*a4bfc4feSMatthias Ringwald break; 303*a4bfc4feSMatthias Ringwald default: 304*a4bfc4feSMatthias Ringwald break; 305*a4bfc4feSMatthias Ringwald } 306*a4bfc4feSMatthias Ringwald } 307*a4bfc4feSMatthias Ringwald 308*a4bfc4feSMatthias Ringwald static void stdin_process(char character){ 309*a4bfc4feSMatthias Ringwald uint8_t c = character; 310*a4bfc4feSMatthias Ringwald btstack_ring_buffer_write(&ascii_input_buffer, &c, 1); 311*a4bfc4feSMatthias Ringwald // start sending 312*a4bfc4feSMatthias Ringwald if (state == W4_INPUT){ 313*a4bfc4feSMatthias Ringwald state = W4_CAN_SEND_FROM_BUFFER; 314*a4bfc4feSMatthias Ringwald hids_device_request_can_send_now_event(con_handle); 315*a4bfc4feSMatthias Ringwald } 316*a4bfc4feSMatthias Ringwald } 317*a4bfc4feSMatthias Ringwald 318*a4bfc4feSMatthias Ringwald #else 319*a4bfc4feSMatthias Ringwald 320*a4bfc4feSMatthias Ringwald // On embedded systems, send constant demo text with fixed period 321*a4bfc4feSMatthias Ringwald 322*a4bfc4feSMatthias Ringwald #define TYPING_PERIOD_MS 50 323*a4bfc4feSMatthias Ringwald static const char * demo_text = "\n\nHello World!\n\nThis is the BTstack HID Keyboard Demo running on an Embedded Device.\n\n"; 324*a4bfc4feSMatthias Ringwald 325*a4bfc4feSMatthias Ringwald static int demo_pos; 326*a4bfc4feSMatthias Ringwald static btstack_timer_source_t typing_timer; 327*a4bfc4feSMatthias Ringwald 328*a4bfc4feSMatthias Ringwald static int send_keycode; 329*a4bfc4feSMatthias Ringwald static int send_modifier; 330*a4bfc4feSMatthias Ringwald static int send_keyup; 331*a4bfc4feSMatthias Ringwald 332*a4bfc4feSMatthias Ringwald static void send_key(int modifier, int keycode){ 333*a4bfc4feSMatthias Ringwald send_keycode = keycode; 334*a4bfc4feSMatthias Ringwald send_modifier = modifier; 335*a4bfc4feSMatthias Ringwald hids_device_request_can_send_now_event(con_handle); 336*a4bfc4feSMatthias Ringwald } 337*a4bfc4feSMatthias Ringwald 338*a4bfc4feSMatthias Ringwald static void typing_can_send_now(void){ 339*a4bfc4feSMatthias Ringwald send_report(send_modifier, send_keycode); 340*a4bfc4feSMatthias Ringwald } 341*a4bfc4feSMatthias Ringwald 342*a4bfc4feSMatthias Ringwald static void typing_timer_handler(btstack_timer_source_t * ts){ 343*a4bfc4feSMatthias Ringwald 344*a4bfc4feSMatthias Ringwald if (send_keyup){ 345*a4bfc4feSMatthias Ringwald // just send key up 346*a4bfc4feSMatthias Ringwald send_keyup = 0; 347*a4bfc4feSMatthias Ringwald send_key(0, 0); 348*a4bfc4feSMatthias Ringwald } else { 349*a4bfc4feSMatthias Ringwald // get next character 350*a4bfc4feSMatthias Ringwald uint8_t character = demo_text[demo_pos++]; 351*a4bfc4feSMatthias Ringwald if (demo_text[demo_pos] == 0){ 352*a4bfc4feSMatthias Ringwald demo_pos = 0; 353*a4bfc4feSMatthias Ringwald } 354*a4bfc4feSMatthias Ringwald 355*a4bfc4feSMatthias Ringwald // get keycode and send 356*a4bfc4feSMatthias Ringwald uint8_t modifier; 357*a4bfc4feSMatthias Ringwald uint8_t keycode; 358*a4bfc4feSMatthias Ringwald int found = keycode_and_modifer_us_for_character(character, &keycode, &modifier); 359*a4bfc4feSMatthias Ringwald if (found){ 360*a4bfc4feSMatthias Ringwald printf("%c\n", character); 361*a4bfc4feSMatthias Ringwald send_key(modifier, keycode); 362*a4bfc4feSMatthias Ringwald send_keyup = 1; 363*a4bfc4feSMatthias Ringwald } 364*a4bfc4feSMatthias Ringwald } 365*a4bfc4feSMatthias Ringwald 366*a4bfc4feSMatthias Ringwald // set next timer 367*a4bfc4feSMatthias Ringwald btstack_run_loop_set_timer(ts, TYPING_PERIOD_MS); 368*a4bfc4feSMatthias Ringwald btstack_run_loop_add_timer(ts); 369*a4bfc4feSMatthias Ringwald } 370*a4bfc4feSMatthias Ringwald 371*a4bfc4feSMatthias Ringwald static void hid_embedded_start_typing(void){ 372*a4bfc4feSMatthias Ringwald printf("Start typing..\n"); 373*a4bfc4feSMatthias Ringwald 374*a4bfc4feSMatthias Ringwald demo_pos = 0; 375*a4bfc4feSMatthias Ringwald // set one-shot timer 376*a4bfc4feSMatthias Ringwald typing_timer.process = &typing_timer_handler; 377*a4bfc4feSMatthias Ringwald btstack_run_loop_set_timer(&typing_timer, TYPING_PERIOD_MS); 378*a4bfc4feSMatthias Ringwald btstack_run_loop_add_timer(&typing_timer); 379*a4bfc4feSMatthias Ringwald } 380*a4bfc4feSMatthias Ringwald 381*a4bfc4feSMatthias Ringwald #endif 382*a4bfc4feSMatthias Ringwald 383*a4bfc4feSMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 384*a4bfc4feSMatthias Ringwald UNUSED(channel); 385*a4bfc4feSMatthias Ringwald UNUSED(size); 386*a4bfc4feSMatthias Ringwald 387*a4bfc4feSMatthias Ringwald switch (packet_type) { 388*a4bfc4feSMatthias Ringwald case HCI_EVENT_PACKET: 389*a4bfc4feSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 390*a4bfc4feSMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 391*a4bfc4feSMatthias Ringwald printf("Disconnected\n"); 392*a4bfc4feSMatthias Ringwald break; 393*a4bfc4feSMatthias Ringwald case SM_EVENT_JUST_WORKS_REQUEST: 394*a4bfc4feSMatthias Ringwald printf("Just Works requested\n"); 395*a4bfc4feSMatthias Ringwald sm_just_works_confirm(sm_event_just_works_request_get_handle(packet)); 396*a4bfc4feSMatthias Ringwald break; 397*a4bfc4feSMatthias Ringwald case SM_EVENT_NUMERIC_COMPARISON_REQUEST: 398*a4bfc4feSMatthias Ringwald printf("Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet)); 399*a4bfc4feSMatthias Ringwald sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet)); 400*a4bfc4feSMatthias Ringwald break; 401*a4bfc4feSMatthias Ringwald case SM_EVENT_PASSKEY_DISPLAY_NUMBER: 402*a4bfc4feSMatthias Ringwald printf("Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet)); 403*a4bfc4feSMatthias Ringwald break; 404*a4bfc4feSMatthias Ringwald case HCI_EVENT_HIDS_META: 405*a4bfc4feSMatthias Ringwald switch (hci_event_hids_meta_get_subevent_code(packet)){ 406*a4bfc4feSMatthias Ringwald case HIDS_SUBEVENT_INPUT_REPORT_ENABLE: 407*a4bfc4feSMatthias Ringwald con_handle = hids_subevent_input_report_enable_get_con_handle(packet); 408*a4bfc4feSMatthias Ringwald printf("Report Characteristic Subscribed %u\n", hids_subevent_input_report_enable_get_enable(packet)); 409*a4bfc4feSMatthias Ringwald #ifndef HAVE_BTSTACK_STDIN 410*a4bfc4feSMatthias Ringwald hid_embedded_start_typing(); 411*a4bfc4feSMatthias Ringwald #endif 412*a4bfc4feSMatthias Ringwald break; 413*a4bfc4feSMatthias Ringwald case HIDS_SUBEVENT_BOOT_KEYBOARD_INPUT_REPORT_ENABLE: 414*a4bfc4feSMatthias Ringwald con_handle = hids_subevent_input_report_enable_get_con_handle(packet); 415*a4bfc4feSMatthias Ringwald printf("Boot Keyboard Characteristic Subscribed %u\n", hids_subevent_boot_keyboard_input_report_enable_get_enable(packet)); 416*a4bfc4feSMatthias Ringwald break; 417*a4bfc4feSMatthias Ringwald case HIDS_SUBEVENT_PROTOCOL_MODE: 418*a4bfc4feSMatthias Ringwald printf("Protocol Mode: %s mode\n", hids_subevent_protocol_mode_get_protocol_mode(packet) ? "Report" : "Boot"); 419*a4bfc4feSMatthias Ringwald break; 420*a4bfc4feSMatthias Ringwald case HIDS_SUBEVENT_CAN_SEND_NOW: 421*a4bfc4feSMatthias Ringwald typing_can_send_now(); 422*a4bfc4feSMatthias Ringwald break; 423*a4bfc4feSMatthias Ringwald default: 424*a4bfc4feSMatthias Ringwald break; 425*a4bfc4feSMatthias Ringwald } 426*a4bfc4feSMatthias Ringwald } 427*a4bfc4feSMatthias Ringwald break; 428*a4bfc4feSMatthias Ringwald } 429*a4bfc4feSMatthias Ringwald } 430*a4bfc4feSMatthias Ringwald 431*a4bfc4feSMatthias Ringwald int btstack_main(void); 432*a4bfc4feSMatthias Ringwald int btstack_main(void) 433*a4bfc4feSMatthias Ringwald { 434*a4bfc4feSMatthias Ringwald le_keyboard_setup(); 435*a4bfc4feSMatthias Ringwald 436*a4bfc4feSMatthias Ringwald #ifdef HAVE_BTSTACK_STDIN 437*a4bfc4feSMatthias Ringwald btstack_ring_buffer_init(&ascii_input_buffer, ascii_input_storage, sizeof(ascii_input_storage)); 438*a4bfc4feSMatthias Ringwald btstack_stdin_setup(stdin_process); 439*a4bfc4feSMatthias Ringwald #endif 440*a4bfc4feSMatthias Ringwald 441*a4bfc4feSMatthias Ringwald // turn on! 442*a4bfc4feSMatthias Ringwald hci_power_control(HCI_POWER_ON); 443*a4bfc4feSMatthias Ringwald 444*a4bfc4feSMatthias Ringwald return 0; 445*a4bfc4feSMatthias Ringwald } 446