]> git.gir.st - tmk_keyboard.git/blob - protocol/iwrap/iwrap.c
Squashed 'tmk_core/' changes from d5c5ac6..8da1898
[tmk_keyboard.git] / protocol / iwrap / iwrap.c
1 /*
2 Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /* host driver for Bulegiga iWRAP */
19 /* Bluegiga BT12
20 * Connections
21 * Hardware UART Software UART BlueTooth
22 * PC=====UART=======AVR=====SUART====iWRAP(BT12)-----------PC
23 *
24 * - Hardware UART for Debug Console to communicate iWRAP
25 * - Software UART for iWRAP control to send keyboard/mouse data
26 */
27
28 #include <stdint.h>
29 #include <string.h>
30 #include <avr/interrupt.h>
31 #include <util/delay.h>
32 #include "keycode.h"
33 #include "suart.h"
34 #include "uart.h"
35 #include "report.h"
36 #include "host_driver.h"
37 #include "iwrap.h"
38 #include "print.h"
39
40
41 /* iWRAP MUX mode utils. 3.10 HID raw mode(iWRAP_HID_Application_Note.pdf) */
42 #define MUX_HEADER(LINK, LENGTH) do { \
43 xmit(0xbf); /* SOF */ \
44 xmit(LINK); /* Link */ \
45 xmit(0x00); /* Flags */ \
46 xmit(LENGTH); /* Length */ \
47 } while (0)
48 #define MUX_FOOTER(LINK) xmit(LINK^0xff)
49
50
51 static uint8_t connected = 0;
52 //static uint8_t channel = 1;
53
54 /* iWRAP buffer */
55 #define MUX_BUF_SIZE 64
56 static char buf[MUX_BUF_SIZE];
57 static uint8_t snd_pos = 0;
58
59 #define MUX_RCV_BUF_SIZE 256
60 static char rcv_buf[MUX_RCV_BUF_SIZE];
61 static uint8_t rcv_head = 0;
62 static uint8_t rcv_tail = 0;
63
64
65 /* receive buffer */
66 static void rcv_enq(char c)
67 {
68 uint8_t next = (rcv_head + 1) % MUX_RCV_BUF_SIZE;
69 if (next != rcv_tail) {
70 rcv_buf[rcv_head] = c;
71 rcv_head = next;
72 }
73 }
74
75 static char rcv_deq(void)
76 {
77 char c = 0;
78 if (rcv_head != rcv_tail) {
79 c = rcv_buf[rcv_tail++];
80 rcv_tail %= MUX_RCV_BUF_SIZE;
81 }
82 return c;
83 }
84
85 /*
86 static char rcv_peek(void)
87 {
88 if (rcv_head == rcv_tail)
89 return 0;
90 return rcv_buf[rcv_tail];
91 }
92 */
93
94 static void rcv_clear(void)
95 {
96 rcv_tail = rcv_head = 0;
97 }
98
99 /* iWRAP response */
100 ISR(PCINT1_vect, ISR_BLOCK) // recv() runs away in case of ISR_NOBLOCK
101 {
102 if ((SUART_IN_PIN & (1<<SUART_IN_BIT)))
103 return;
104
105 static volatile uint8_t mux_state = 0xff;
106 static volatile uint8_t mux_link = 0xff;
107 uint8_t c = recv();
108 switch (mux_state) {
109 case 0xff: // SOF
110 if (c == 0xbf)
111 mux_state--;
112 break;
113 case 0xfe: // Link
114 mux_state--;
115 mux_link = c;
116 break;
117 case 0xfd: // Flags
118 mux_state--;
119 break;
120 case 0xfc: // Length
121 mux_state = c;
122 break;
123 case 0x00:
124 mux_state = 0xff;
125 mux_link = 0xff;
126 break;
127 default:
128 if (mux_state--) {
129 uart_putchar(c);
130 rcv_enq(c);
131 }
132 }
133 }
134
135
136 /*------------------------------------------------------------------*
137 * iWRAP communication
138 *------------------------------------------------------------------*/
139 void iwrap_init(void)
140 {
141 // reset iWRAP if in already MUX mode after AVR software-reset
142 iwrap_send("RESET");
143 iwrap_mux_send("RESET");
144 _delay_ms(3000);
145 iwrap_send("\r\nSET CONTROL MUX 1\r\n");
146 _delay_ms(500);
147 iwrap_check_connection();
148 }
149
150 void iwrap_mux_send(const char *s)
151 {
152 rcv_clear();
153 MUX_HEADER(0xff, strlen((char *)s));
154 iwrap_send(s);
155 MUX_FOOTER(0xff);
156 }
157
158 void iwrap_send(const char *s)
159 {
160 while (*s)
161 xmit(*s++);
162 }
163
164 /* send buffer */
165 void iwrap_buf_add(uint8_t c)
166 {
167 // need space for '\0'
168 if (snd_pos < MUX_BUF_SIZE-1)
169 buf[snd_pos++] = c;
170 }
171
172 void iwrap_buf_del(void)
173 {
174 if (snd_pos)
175 snd_pos--;
176 }
177
178 void iwrap_buf_send(void)
179 {
180 buf[snd_pos] = '\0';
181 snd_pos = 0;
182 iwrap_mux_send(buf);
183 }
184
185 void iwrap_call(void)
186 {
187 char *p;
188
189 iwrap_mux_send("SET BT PAIR");
190 _delay_ms(500);
191
192 p = rcv_buf + rcv_tail;
193 while (!strncmp(p, "SET BT PAIR", 11)) {
194 p += 7;
195 strncpy(p, "CALL", 4);
196 strncpy(p+22, " 11 HID\n\0", 9);
197 print_S(p);
198 iwrap_mux_send(p);
199 // TODO: skip to next line
200 p += 57;
201
202 DEBUG_LED_CONFIG;
203 DEBUG_LED_ON;
204 _delay_ms(500);
205 DEBUG_LED_OFF;
206 _delay_ms(500);
207 DEBUG_LED_ON;
208 _delay_ms(500);
209 DEBUG_LED_OFF;
210 _delay_ms(500);
211 DEBUG_LED_ON;
212 _delay_ms(500);
213 DEBUG_LED_OFF;
214 _delay_ms(500);
215 DEBUG_LED_ON;
216 _delay_ms(500);
217 DEBUG_LED_OFF;
218 _delay_ms(500);
219 DEBUG_LED_ON;
220 _delay_ms(500);
221 DEBUG_LED_OFF;
222 _delay_ms(500);
223 }
224 iwrap_check_connection();
225 }
226
227 void iwrap_kill(void)
228 {
229 char c;
230 iwrap_mux_send("LIST");
231 _delay_ms(500);
232
233 while ((c = rcv_deq()) && c != '\n') ;
234 if (strncmp(rcv_buf + rcv_tail, "LIST ", 5)) {
235 print("no connection to kill.\n");
236 return;
237 }
238 // skip 10 'space' chars
239 for (uint8_t i = 10; i; i--)
240 while ((c = rcv_deq()) && c != ' ') ;
241
242 char *p = rcv_buf + rcv_tail - 5;
243 strncpy(p, "KILL ", 5);
244 strncpy(p + 22, "\n\0", 2);
245 print_S(p);
246 iwrap_mux_send(p);
247 _delay_ms(500);
248
249 iwrap_check_connection();
250 }
251
252 void iwrap_unpair(void)
253 {
254 iwrap_mux_send("SET BT PAIR");
255 _delay_ms(500);
256
257 char *p = rcv_buf + rcv_tail;
258 if (!strncmp(p, "SET BT PAIR", 11)) {
259 strncpy(p+29, "\n\0", 2);
260 print_S(p);
261 iwrap_mux_send(p);
262 }
263 }
264
265 void iwrap_sleep(void)
266 {
267 iwrap_mux_send("SLEEP");
268 }
269
270 void iwrap_sniff(void)
271 {
272 }
273
274 void iwrap_subrate(void)
275 {
276 }
277
278 bool iwrap_failed(void)
279 {
280 if (strncmp(rcv_buf, "SYNTAX ERROR", 12))
281 return true;
282 else
283 return false;
284 }
285
286 uint8_t iwrap_connected(void)
287 {
288 return connected;
289 }
290
291 uint8_t iwrap_check_connection(void)
292 {
293 iwrap_mux_send("LIST");
294 _delay_ms(100);
295
296 if (strncmp(rcv_buf, "LIST ", 5) || !strncmp(rcv_buf, "LIST 0", 6))
297 connected = 0;
298 else
299 connected = 1;
300 return connected;
301 }
302
303
304 /*------------------------------------------------------------------*
305 * Host driver
306 *------------------------------------------------------------------*/
307 static uint8_t keyboard_leds(void);
308 static void send_keyboard(report_keyboard_t *report);
309 static void send_mouse(report_mouse_t *report);
310 static void send_system(uint16_t data);
311 static void send_consumer(uint16_t data);
312
313 static host_driver_t driver = {
314 keyboard_leds,
315 send_keyboard,
316 send_mouse,
317 send_system,
318 send_consumer
319 };
320
321 host_driver_t *iwrap_driver(void)
322 {
323 return &driver;
324 }
325
326 static uint8_t keyboard_leds(void) {
327 return 0;
328 }
329
330 static void send_keyboard(report_keyboard_t *report)
331 {
332 if (!iwrap_connected() && !iwrap_check_connection()) return;
333 MUX_HEADER(0x01, 0x0c);
334 // HID raw mode header
335 xmit(0x9f);
336 xmit(0x0a); // Length
337 xmit(0xa1); // DATA(Input)
338 xmit(0x01); // Report ID
339 xmit(report->mods);
340 xmit(0x00); // reserved byte(always 0)
341 xmit(report->keys[0]);
342 xmit(report->keys[1]);
343 xmit(report->keys[2]);
344 xmit(report->keys[3]);
345 xmit(report->keys[4]);
346 xmit(report->keys[5]);
347 MUX_FOOTER(0x01);
348 }
349
350 static void send_mouse(report_mouse_t *report)
351 {
352 #if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
353 if (!iwrap_connected() && !iwrap_check_connection()) return;
354 MUX_HEADER(0x01, 0x09);
355 // HID raw mode header
356 xmit(0x9f);
357 xmit(0x07); // Length
358 xmit(0xa1); // DATA(Input)
359 xmit(0x02); // Report ID
360 xmit(report->buttons);
361 xmit(report->x);
362 xmit(report->y);
363 xmit(report->v);
364 xmit(report->h);
365 MUX_FOOTER(0x01);
366 #endif
367 }
368
369 static void send_system(uint16_t data)
370 {
371 /* not supported */
372 }
373
374 static void send_consumer(uint16_t data)
375 {
376 #ifdef EXTRAKEY_ENABLE
377 static uint16_t last_data = 0;
378 uint8_t bits1 = 0;
379 uint8_t bits2 = 0;
380 uint8_t bits3 = 0;
381
382 if (!iwrap_connected() && !iwrap_check_connection()) return;
383 if (data == last_data) return;
384 last_data = data;
385
386 // 3.10 HID raw mode(iWRAP_HID_Application_Note.pdf)
387 switch (data) {
388 case AUDIO_VOL_UP:
389 bits1 = 0x01;
390 break;
391 case AUDIO_VOL_DOWN:
392 bits1 = 0x02;
393 break;
394 case AUDIO_MUTE:
395 bits1 = 0x04;
396 break;
397 case TRANSPORT_PLAY_PAUSE:
398 bits1 = 0x08;
399 break;
400 case TRANSPORT_NEXT_TRACK:
401 bits1 = 0x10;
402 break;
403 case TRANSPORT_PREV_TRACK:
404 bits1 = 0x20;
405 break;
406 case TRANSPORT_STOP:
407 bits1 = 0x40;
408 break;
409 case TRANSPORT_EJECT:
410 bits1 = 0x80;
411 break;
412 case AL_EMAIL:
413 bits2 = 0x01;
414 break;
415 case AC_SEARCH:
416 bits2 = 0x02;
417 break;
418 case AC_BOOKMARKS:
419 bits2 = 0x04;
420 break;
421 case AC_HOME:
422 bits2 = 0x08;
423 break;
424 case AC_BACK:
425 bits2 = 0x10;
426 break;
427 case AC_FORWARD:
428 bits2 = 0x20;
429 break;
430 case AC_STOP:
431 bits2 = 0x40;
432 break;
433 case AC_REFRESH:
434 bits2 = 0x80;
435 break;
436 case AL_CC_CONFIG:
437 bits3 = 0x01;
438 break;
439 case AL_CALCULATOR:
440 bits3 = 0x04;
441 break;
442 case AL_LOCK:
443 bits3 = 0x08;
444 break;
445 case AL_LOCAL_BROWSER:
446 bits3 = 0x10;
447 break;
448 case AC_MINIMIZE:
449 bits3 = 0x20;
450 break;
451 case TRANSPORT_RECORD:
452 bits3 = 0x40;
453 break;
454 case TRANSPORT_REWIND:
455 bits3 = 0x80;
456 break;
457 }
458
459 MUX_HEADER(0x01, 0x07);
460 xmit(0x9f);
461 xmit(0x05); // Length
462 xmit(0xa1); // DATA(Input)
463 xmit(0x03); // Report ID
464 xmit(bits1);
465 xmit(bits2);
466 xmit(bits3);
467 MUX_FOOTER(0x01);
468 #endif
469 }
Imprint / Impressum