2 Copyright 2011 Jun Wako <wakojun@gmail.com>
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.
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.
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/>.
18 /* host driver for Bulegiga iWRAP */
21 * Hardware UART Software UART BlueTooth
22 * PC=====UART=======AVR=====SUART====iWRAP(BT12)-----------PC
24 * - Hardware UART for Debug Console to communicate iWRAP
25 * - Software UART for iWRAP control to send keyboard/mouse data
30 #include <avr/interrupt.h>
31 #include <util/delay.h>
32 #include "usb_keycodes.h"
36 #include "host_driver.h"
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 */ \
48 #define MUX_FOOTER(LINK) xmit(LINK^0xff)
51 static uint8_t connected = 0;
52 //static uint8_t channel = 1;
55 #define MUX_BUF_SIZE 64
56 static char buf[MUX_BUF_SIZE];
57 static uint8_t snd_pos = 0;
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;
66 static void rcv_enq(char c)
68 uint8_t next = (rcv_head + 1) % MUX_RCV_BUF_SIZE;
69 if (next != rcv_tail) {
70 rcv_buf[rcv_head] = c;
75 static char rcv_deq(void)
78 if (rcv_head != rcv_tail) {
79 c = rcv_buf[rcv_tail++];
80 rcv_tail %= MUX_RCV_BUF_SIZE;
86 static char rcv_peek(void)
88 if (rcv_head == rcv_tail)
90 return rcv_buf[rcv_tail];
94 static void rcv_clear(void)
96 rcv_tail = rcv_head = 0;
100 ISR(PCINT1_vect, ISR_BLOCK) // recv() runs away in case of ISR_NOBLOCK
102 if ((SUART_IN_PIN & (1<<SUART_IN_BIT)))
105 static volatile uint8_t mux_state = 0xff;
106 static volatile uint8_t mux_link = 0xff;
136 /*------------------------------------------------------------------*
137 * iWRAP communication
138 *------------------------------------------------------------------*/
139 void iwrap_init(void)
141 // reset iWRAP if in already MUX mode after AVR software-reset
143 iwrap_mux_send("RESET");
145 iwrap_send("\r\nSET CONTROL MUX 1\r\n");
147 iwrap_check_connection();
150 void iwrap_mux_send(const char *s)
153 MUX_HEADER(0xff, strlen((char *)s));
158 void iwrap_send(const char *s)
165 void iwrap_buf_add(uint8_t c)
167 // need space for '\0'
168 if (snd_pos < MUX_BUF_SIZE-1)
172 void iwrap_buf_del(void)
178 void iwrap_buf_send(void)
185 void iwrap_call(void)
189 iwrap_mux_send("SET BT PAIR");
192 p = rcv_buf + rcv_tail;
193 while (!strncmp(p, "SET BT PAIR", 11)) {
195 strncpy(p, "CALL", 4);
196 strncpy(p+22, " 11 HID\n\0", 9);
199 // TODO: skip to next line
224 iwrap_check_connection();
227 void iwrap_kill(void)
230 iwrap_mux_send("LIST");
233 while ((c = rcv_deq()) && c != '\n') ;
234 if (strncmp(rcv_buf + rcv_tail, "LIST ", 5)) {
235 print("no connection to kill.\n");
238 // skip 10 'space' chars
239 for (uint8_t i = 10; i; i--)
240 while ((c = rcv_deq()) && c != ' ') ;
242 char *p = rcv_buf + rcv_tail - 5;
243 strncpy(p, "KILL ", 5);
244 strncpy(p + 22, "\n\0", 2);
249 iwrap_check_connection();
252 void iwrap_unpair(void)
254 iwrap_mux_send("SET BT PAIR");
257 char *p = rcv_buf + rcv_tail;
258 if (!strncmp(p, "SET BT PAIR", 11)) {
259 strncpy(p+29, "\n\0", 2);
265 void iwrap_sleep(void)
267 iwrap_mux_send("SLEEP");
270 void iwrap_sniff(void)
274 void iwrap_subrate(void)
278 bool iwrap_failed(void)
280 if (strncmp(rcv_buf, "SYNTAX ERROR", 12))
286 uint8_t iwrap_connected(void)
291 uint8_t iwrap_check_connection(void)
293 iwrap_mux_send("LIST");
296 if (strncmp(rcv_buf, "LIST ", 5) || !strncmp(rcv_buf, "LIST 0", 6))
304 /*------------------------------------------------------------------*
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);
313 static host_driver_t driver = {
321 host_driver_t *iwrap_driver(void)
326 static uint8_t keyboard_leds(void) {
330 static void send_keyboard(report_keyboard_t *report)
332 if (!iwrap_connected() && !iwrap_check_connection()) return;
333 MUX_HEADER(0x01, 0x0c);
334 // HID raw mode header
336 xmit(0x0a); // Length
337 xmit(0xa1); // keyboard report
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]);
350 static void send_mouse(report_mouse_t *report)
352 #if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
353 if (!iwrap_connected() && !iwrap_check_connection()) return;
354 MUX_HEADER(0x01, 0x07);
355 // HID raw mode header
357 xmit(0x05); // Length
358 xmit(0xa1); // mouse report
360 xmit(report->buttons);
367 static void send_system(uint16_t data)
372 static void send_consumer(uint16_t data)
374 #ifdef EXTRAKEY_ENABLE
375 static uint16_t last_data = 0;
380 if (!iwrap_connected() && !iwrap_check_connection()) return;
381 if (data == last_data) return;
384 // 3.10 HID raw mode(iWRAP_HID_Application_Note.pdf)
395 case TRANSPORT_PLAY_PAUSE:
398 case TRANSPORT_NEXT_TRACK:
401 case TRANSPORT_PREV_TRACK:
407 case TRANSPORT_EJECT:
443 case AL_LOCAL_BROWSER:
449 case TRANSPORT_RECORD:
452 case TRANSPORT_REWIND:
457 MUX_HEADER(0x01, 0x07);
459 xmit(0x05); // Length
460 xmit(0xa1); // consumer report