xref: /btstack/port/archive/msp-exp430f5438-cc2564b/example/hid_demo.c (revision d39264f239eb026fd486651e238a9ef65f8504ab)
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