1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 // ***************************************************************************** 39 // 40 // keyboard_demo 41 // 42 // ***************************************************************************** 43 44 #include <stdint.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 48 #include "btstack_chipset_cc256x.h" 49 #include "hal_adc.h" 50 #include "hal_board.h" 51 #include "hal_compat.h" 52 #include "hal_lcd.h" 53 #include "hal_usb.h" 54 #include "UserExperienceGraphics.h" 55 #include <msp430x54x.h> 56 57 #include "btstack_run_loop.h" 58 #include "hci_cmd.h" 59 #include "btstack_memory.h" 60 #include "hci.h" 61 #include "l2cap.h" 62 #include "btstack_link_key_db_memory,h" 63 64 #define INQUIRY_INTERVAL 15 65 66 #define FONT_HEIGHT 12 // Each character has 13 lines 67 #define FONT_WIDTH 8 68 69 static int row = 0; 70 71 extern int dumpCmds; 72 73 const char *hexMap = "0123456789ABCDEF"; 74 75 static char lineBuffer[20]; 76 static uint8_t num_chars = 0; 77 static bd_addr_t keyboard; 78 static int haveKeyboard = 0; 79 80 typedef enum { 81 boot = 1, 82 inquiry, 83 w4_inquiry_cmd_complete, 84 w4_l2cap_hii_connect, 85 connected 86 } state_t; 87 88 static state_t state = 0; 89 90 static btstack_packet_callback_registration_t hci_event_callback_registration; 91 92 #define KEYCODE_RETURN '\n' 93 #define KEYCODE_ESCAPE 27 94 #define KEYCODE_TAB '\t' 95 #define KEYCODE_BACKSPACE 0x7f 96 #define KEYCODE_ILLEGAL 0xffff 97 #define KEYCODE_CAPSLOCK KEYCODE_ILLEGAL 98 99 #define MOD_SHIFT 0x22 100 101 /** 102 * English (US) 103 */ 104 static uint16_t keytable_us_none [] = { 105 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 0-3 */ 106 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 4 - 13 */ 107 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 14 - 23 */ 108 'u', 'v', 'w', 'x', 'y', 'z', /* 24 - 29 */ 109 '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', /* 30 - 39 */ 110 KEYCODE_RETURN, KEYCODE_ESCAPE, KEYCODE_BACKSPACE, KEYCODE_TAB, ' ', /* 40 - 44 */ 111 '-', '=', '[', ']', '\\', KEYCODE_ILLEGAL, ';', '\'', 0x60, ',', /* 45 - 54 */ 112 '.', '/', KEYCODE_CAPSLOCK, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 55 - 60 */ 113 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 61-64 */ 114 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 65-68 */ 115 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 69-72 */ 116 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 73-76 */ 117 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 77-80 */ 118 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 81-84 */ 119 '*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */ 120 '6', '7', '8', '9', '0', '.', 0xa7, /* 97-100 */ 121 }; 122 123 static uint16_t keytable_us_shift[] = { 124 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 0-3 */ 125 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 4 - 13 */ 126 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 14 - 23 */ 127 'U', 'V', 'W', 'X', 'Y', 'Z', /* 24 - 29 */ 128 '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', /* 30 - 39 */ 129 KEYCODE_RETURN, KEYCODE_ESCAPE, KEYCODE_BACKSPACE, KEYCODE_TAB, ' ', /* 40 - 44 */ 130 '_', '+', '{', '}', '|', KEYCODE_ILLEGAL, ':', '"', 0x7E, '<', /* 45 - 54 */ 131 '>', '?', KEYCODE_CAPSLOCK, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 55 - 60 */ 132 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 61-64 */ 133 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 65-68 */ 134 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 69-72 */ 135 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 73-76 */ 136 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 77-80 */ 137 KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, KEYCODE_ILLEGAL, /* 81-84 */ 138 '*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */ 139 '6', '7', '8', '9', '0', '.', 0xb1, /* 97-100 */ 140 }; 141 142 // decode hid packet into buffer - return number of valid keys events 143 #define NUM_KEYS 6 144 uint8_t last_keyboard_state[NUM_KEYS]; 145 uint16_t input[NUM_KEYS]; 146 static char last_state_init = 0; 147 uint16_t last_key; 148 uint16_t last_mod; 149 uint16_t last_char; 150 uint8_t last_key_new; 151 152 void doLCD(void){ 153 //Initialize LCD and backlight 154 // 138 x 110, 4-level grayscale pixels. 155 halLcdInit(); 156 // halLcdBackLightInit(); 157 // halLcdSetBackLight(0); // 8 for normal 158 halLcdSetContrast(100); 159 halLcdClearScreen(); 160 halLcdImage(TI_TINY_BUG, 4, 32, 104, 12 ); 161 162 halLcdPrintLine("BTstack on ", 0, 0); 163 halLcdPrintLine("TI MSP430", 1, 0); 164 halLcdPrintLine("Keyboard", 2, 0); 165 halLcdPrintLine("Init...", 3, 0); 166 row = 4; 167 } 168 169 void clearLine(int line){ 170 halLcdClearImage(130, FONT_HEIGHT, 0, line*FONT_HEIGHT); 171 } 172 173 void printLine(char *text){ 174 printf("LCD: %s\n\r", text); 175 halLcdPrintLine(text, row++, 0); 176 } 177 178 // put 'lineBuffer' on screen 179 void showLine(void){ 180 clearLine(row); 181 halLcdPrintLine(lineBuffer, row, 0); 182 printf("LCD: %s\n\r", lineBuffer); 183 } 184 185 unsigned char hid_process_packet(unsigned char *hid_report, uint16_t *buffer, uint8_t max_keys){ 186 187 // check for key report 188 if (hid_report[0] != 0xa1 || hid_report[1] != 0x01) { 189 return 0; 190 } 191 192 u_char modifier = hid_report[2]; 193 u_char result = 0; 194 u_char i; 195 u_char j; 196 197 if (!last_state_init) 198 { 199 for (i=0;i<NUM_KEYS;i++){ 200 last_keyboard_state[i] = 0; 201 } 202 last_state_init = 1; 203 } 204 205 for (i=0; i< NUM_KEYS && result < max_keys; i++){ 206 // find key in last state 207 uint8_t new_event = hid_report[4+i]; 208 if (new_event){ 209 for (j=0; j<NUM_KEYS; j++){ 210 if (new_event == last_keyboard_state[j]){ 211 new_event = 0; 212 break; 213 } 214 } 215 if (!new_event) continue; 216 buffer[result++] = new_event; 217 last_key = new_event; 218 last_mod = modifier; 219 } 220 } 221 222 // store keyboard state 223 for (i=0;i<NUM_KEYS;i++){ 224 last_keyboard_state[i] = hid_report[4+i]; 225 } 226 return result; 227 } 228 229 230 231 static void l2cap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 232 233 if (packet_type == HCI_EVENT_PACKET && hci_event_packet_get_type(packet) == L2CAP_EVENT_CHANNEL_OPENED){ 234 if (packet[2]) { 235 printf("Connection failed\n\r"); 236 return; 237 } 238 printf("Connected\n\r"); 239 num_chars = 0; 240 lineBuffer[num_chars++] = 'T'; 241 lineBuffer[num_chars++] = 'y'; 242 lineBuffer[num_chars++] = 'p'; 243 lineBuffer[num_chars++] = 'e'; 244 lineBuffer[num_chars++] = ' '; 245 lineBuffer[num_chars] = 0; 246 showLine(); 247 } 248 if (packet_type == L2CAP_DATA_PACKET){ 249 // handle input 250 // printf("HID report, size %u\n\r", size); 251 uint8_t count = hid_process_packet(packet, (uint16_t *) &input[0], NUM_KEYS); 252 if (!count) return; 253 254 uint8_t new_char; 255 // handle shift 256 if (last_mod & MOD_SHIFT) { 257 new_char = keytable_us_shift[input[0]]; 258 } else { 259 new_char = keytable_us_none[input[0]]; 260 } 261 // add to buffer 262 if (new_char == KEYCODE_BACKSPACE){ 263 if (num_chars <= 5) return; 264 --num_chars; 265 lineBuffer[num_chars] = 0; 266 showLine(); 267 return; 268 } 269 // 17 chars fit into one line 270 lineBuffer[num_chars] = new_char; 271 lineBuffer[num_chars+1] = 0; 272 if(num_chars < 16) num_chars++; 273 showLine(); 274 } 275 } 276 277 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 278 int i,j; 279 switch (packet_type) { 280 case HCI_EVENT_PACKET: 281 switch (hci_event_packet_get_type(packet)) { 282 283 case BTSTACK_EVENT_STATE: 284 // bt stack activated, get started - set local name 285 if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ 286 printLine("Inquiry"); 287 state = inquiry; 288 gap_inquiry_start(INQUIRY_INTERVAL); 289 break; 290 } 291 break; 292 293 case HCI_EVENT_INQUIRY_RESULT: 294 295 // ignore further results 296 if (haveKeyboard) break; 297 298 // ignore none keyboards 299 if ((packet[12] & 0x40) != 0x40 || packet[13] != 0x25) break; 300 301 // flip addr 302 reverse_bd_addr(&packet[3], keyboard); 303 304 // show 305 printf("Keyboard:\n\r"); 306 307 // addr 308 j=0; 309 for (i=0;i<6;i++){ 310 lineBuffer[j++] = hexMap[ keyboard[i] >> 4 ]; 311 lineBuffer[j++] = hexMap[ keyboard[i] & 0x0f ]; 312 if (i<5) lineBuffer[j++] = ':'; 313 } 314 lineBuffer[j++] = 0; 315 printLine(lineBuffer); 316 317 haveKeyboard = 1; 318 hci_send_cmd(&hci_inquiry_cancel); 319 state = w4_inquiry_cmd_complete; 320 break; 321 322 case HCI_EVENT_INQUIRY_COMPLETE: 323 printLine("No keyboard found :("); 324 break; 325 326 case HCI_EVENT_LINK_KEY_REQUEST: 327 // deny link key request 328 hci_send_cmd(&hci_link_key_request_negative_reply, &keyboard); 329 break; 330 331 case HCI_EVENT_PIN_CODE_REQUEST: 332 // inform about pin code request 333 printLine( "Enter 0000"); 334 hci_send_cmd(&hci_pin_code_request_reply, &keyboard, 4, "0000"); 335 break; 336 337 case HCI_EVENT_COMMAND_COMPLETE: 338 if (hci_event_command_complete_get_command_opcode(packet) == HCI_OPCODE_HCI_INQUIRY_CANCEL){ 339 // inq successfully cancelled 340 // printLine("Connecting"); 341 l2cap_create_channel(l2cap_packet_handler, keyboard, PSM_HID_INTERRUPT, 150); 342 break; 343 } 344 } 345 } 346 } 347 348 static hci_transport_config_uart_t config = { 349 HCI_TRANSPORT_CONFIG_UART, 350 115200, 351 1000000, // main baudrate 352 1, // flow control 353 NULL, 354 }; 355 356 int main(void){ 357 358 // stop watchdog timer 359 WDTCTL = WDTPW + WDTHOLD; 360 361 //Initialize clock and peripherals 362 halBoardInit(); 363 halBoardStartXT1(); 364 halBoardSetSystemClock(SYSCLK_16MHZ); 365 366 // Debug UART 367 halUsbInit(); 368 369 // show off 370 doLCD(); 371 372 // init LEDs 373 LED_PORT_OUT |= LED_1 | LED_2; 374 LED_PORT_DIR |= LED_1 | LED_2; 375 376 /// GET STARTED /// 377 btstack_memory_init(); 378 btstack_run_loop_init(btstack_run_loop_embedded_get_instance()); 379 380 // init HCI 381 const hci_transport_t * transport = hci_transport_h4_instance(btstack_uart_block_embedded_instance()); 382 btstack_link_key_db_t * link_key_db = btstack_link_key_db_memory_instance(); 383 hci_init(transport, &config); 384 hci_set_link_key_db(link_key_db); 385 hci_set_chipset(btstack_chipset_cc256x_instance()); 386 387 // register for HCI events 388 hci_event_callback_registration.callback = &packet_handler; 389 hci_add_event_handler(&hci_event_callback_registration); 390 391 // init L2CAP 392 l2cap_init(); 393 394 // ready - enable irq used in h4 task 395 __enable_interrupt(); 396 397 // turn on! 398 hci_power_control(HCI_POWER_ON); 399 400 return 0; 401 } 402 403