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
doLCD(void)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
clearLine(int line)169 void clearLine(int line){
170 halLcdClearImage(130, FONT_HEIGHT, 0, line*FONT_HEIGHT);
171 }
172
printLine(char * text)173 void printLine(char *text){
174 printf("LCD: %s\n\r", text);
175 halLcdPrintLine(text, row++, 0);
176 }
177
178 // put 'lineBuffer' on screen
showLine(void)179 void showLine(void){
180 clearLine(row);
181 halLcdPrintLine(lineBuffer, row, 0);
182 printf("LCD: %s\n\r", lineBuffer);
183 }
184
hid_process_packet(unsigned char * hid_report,uint16_t * buffer,uint8_t max_keys)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
l2cap_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)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
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)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
main(void)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