]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - keyboard/hhkb/rn42/rn42_task.c
lufa: Update makefile for new LUFA
[max/tmk_keyboard.git] / keyboard / hhkb / rn42 / rn42_task.c
1 #include <stdint.h>
2 #include <string.h>
3 #include <avr/pgmspace.h>
4 #include <avr/eeprom.h>
5 #include "keycode.h"
6 #include "serial.h"
7 #include "host.h"
8 #include "action.h"
9 #include "action_util.h"
10 #include "lufa.h"
11 #include "rn42_task.h"
12 #include "print.h"
13 #include "debug.h"
14 #include "timer.h"
15 #include "wait.h"
16 #include "command.h"
17 #include "battery.h"
18
19 static bool config_mode = false;
20 static bool force_usb = false;
21
22 static void status_led(bool on)
23 {
24     if (on) {
25         DDRE  |=  (1<<6);
26         PORTE &= ~(1<<6);
27     } else {
28         DDRE  |=  (1<<6);
29         PORTE |=  (1<<6);
30     }
31 }
32
33 void rn42_task_init(void)
34 {
35     battery_init();
36 #ifdef NKRO_ENABLE
37     rn42_nkro_last = keyboard_nkro;
38 #endif
39 }
40
41 void rn42_task(void)
42 {
43     int16_t c;
44     // Raw mode: interpret output report of LED state
45     while ((c = rn42_getc()) != -1) {
46         // LED Out report: 0xFE, 0x02, 0x01, <leds>
47         // To get the report over UART set bit3 with SH, command.
48         static enum {LED_INIT, LED_FE, LED_02, LED_01} state = LED_INIT;
49         switch (state) {
50             case LED_INIT:
51                 if (c == 0xFE) state = LED_FE;
52                 else {
53                     if (0x0 <= c && c <= 0x7f) xprintf("%c", c);
54                     else xprintf(" %02X", c);
55                 }
56                 break;
57             case LED_FE:
58                 if (c == 0x02) state = LED_02;
59                 else           state = LED_INIT;
60                 break;
61             case LED_02:
62                 if (c == 0x01) state = LED_01;
63                 else           state = LED_INIT;
64                 break;
65             case LED_01:
66                 dprintf("LED status: %02X\n", c);
67                 rn42_set_leds(c);
68                 state = LED_INIT;
69                 break;
70             default:
71                 state = LED_INIT;
72         }
73     }
74
75     /* Switch between USB and Bluetooth */
76     if (!config_mode) { // not switch while config mode
77         if (!force_usb && !rn42_rts()) {
78             if (host_get_driver() != &rn42_driver) {
79                 clear_keyboard();
80 #ifdef NKRO_ENABLE
81                 rn42_nkro_last = keyboard_nkro;
82                 keyboard_nkro = false;
83 #endif
84                 host_set_driver(&rn42_driver);
85             }
86         } else {
87             if (host_get_driver() != &lufa_driver) {
88                 clear_keyboard();
89 #ifdef NKRO_ENABLE
90                 keyboard_nkro = rn42_nkro_last;
91 #endif
92                 host_set_driver(&lufa_driver);
93             }
94         }
95     }
96
97
98     static uint16_t prev_timer = 0;
99     uint16_t e = timer_elapsed(prev_timer);
100     if (e > 1000) {
101         /* every second */
102         prev_timer += e/1000*1000;
103
104         /* Low voltage alert */
105         uint8_t bs = battery_status();
106         if (bs == LOW_VOLTAGE) {
107             battery_led(LED_ON);
108         } else {
109             battery_led(LED_CHARGER);
110         }
111
112         /* every minute */
113         uint32_t t = timer_read32()/1000;
114         if (t%60 == 0) {
115             uint16_t v = battery_voltage();
116             uint8_t h = t/3600;
117             uint8_t m = t%3600/60;
118             uint8_t s = t%60;
119             dprintf("%02u:%02u:%02u\t%umV\n", h, m, s, v);
120             /* TODO: xprintf doesn't work for this.
121             xprintf("%02u:%02u:%02u\t%umV\n", (t/3600), (t%3600/60), (t%60), v);
122             */
123         }
124     }
125
126
127     /* Connection monitor */
128     if (!rn42_rts() && rn42_linked()) {
129         status_led(true);
130     } else {
131         status_led(false);
132     }
133 }
134
135
136
137 /******************************************************************************
138  * Command
139  ******************************************************************************/
140 static host_driver_t *prev_driver = &rn42_driver;
141
142 static void enter_command_mode(void)
143 {
144     prev_driver = host_get_driver();
145     clear_keyboard();
146     host_set_driver(&rn42_config_driver);   // null driver; not to send a key to host
147     rn42_disconnect();
148     while (rn42_linked()) ;
149
150     print("Entering config mode ...\n");
151     wait_ms(1100);          // need 1 sec
152     SEND_COMMAND("$$$");
153     wait_ms(600);           // need 1 sec
154     rn42_print_response();
155     const char *s = SEND_COMMAND("v\r\n");
156     if (strncmp("v", s, 1) != 0) SEND_COMMAND("+\r\n"); // local echo on
157 }
158
159 static void exit_command_mode(void)
160 {
161     print("Exiting config mode ...\n");
162     SEND_COMMAND("---\r\n");    // exit
163
164     rn42_autoconnect();
165     clear_keyboard();
166     host_set_driver(prev_driver);
167 }
168
169 static void init_rn42(void)
170 {
171     // RN-42 configure
172     if (!config_mode) enter_command_mode();
173     SEND_COMMAND("SF,1\r\n");  // factory defaults
174     SEND_COMMAND("S-,TmkBT\r\n");
175     SEND_COMMAND("SS,Keyboard/Mouse\r\n");
176     SEND_COMMAND("SM,4\r\n");  // auto connect(DTR)
177     SEND_COMMAND("SW,8000\r\n");   // Sniff disable
178     SEND_COMMAND("S~,6\r\n");   // HID profile
179     SEND_COMMAND("SH,003C\r\n");   // combo device, out-report, 4-reconnect
180     SEND_COMMAND("SY,FFF4\r\n");   // transmit power -12
181     SEND_COMMAND("R,1\r\n");
182     if (!config_mode) exit_command_mode();
183 }
184
185 #if 0
186 // Switching connections
187 // NOTE: Remote Address doesn't work in the way manual says.
188 // EEPROM address for link store
189 #define RN42_LINK0  (uint8_t *)128
190 #define RN42_LINK1  (uint8_t *)140
191 #define RN42_LINK2  (uint8_t *)152
192 #define RN42_LINK3  (uint8_t *)164
193 static void store_link(uint8_t *eeaddr)
194 {
195     enter_command_mode();
196     SEND_STR("GR\r\n"); // remote address
197     const char *s = rn42_gets(500);
198     if (strcmp("GR", s) == 0) s = rn42_gets(500);   // ignore local echo
199     xprintf("%s(%d)\r\n", s, strlen(s));
200     if (strlen(s) == 12) {
201         for (int i = 0; i < 12; i++) {
202             eeprom_write_byte(eeaddr+i, *(s+i));
203             dprintf("%c ", *(s+i));
204         }
205         dprint("\r\n");
206     }
207     exit_command_mode();
208 }
209
210 static void restore_link(const uint8_t *eeaddr)
211 {
212     enter_command_mode();
213     SEND_COMMAND("SR,Z\r\n");   // remove remote address
214     SEND_STR("SR,");            // set remote address from EEPROM
215     for (int i = 0; i < 12; i++) {
216         uint8_t c = eeprom_read_byte(eeaddr+i);
217         rn42_putc(c);
218         dprintf("%c ", c);
219     }
220     dprintf("\r\n");
221     SEND_COMMAND("\r\n");
222     SEND_COMMAND("R,1\r\n");    // reboot
223     exit_command_mode();
224 }
225
226 static const char *get_link(uint8_t * eeaddr)
227 {
228     static char s[13];
229     for (int i = 0; i < 12; i++) {
230         uint8_t c = eeprom_read_byte(eeaddr+i);
231         s[i] = c;
232     }
233     s[12] = '\0';
234     return s;
235 }
236 #endif
237
238 static void pairing(void)
239 {
240     enter_command_mode();
241     SEND_COMMAND("SR,Z\r\n");   // remove remote address
242     SEND_COMMAND("R,1\r\n");    // reboot
243     exit_command_mode();
244 }
245
246 bool command_extra(uint8_t code)
247 {
248     uint32_t t;
249     uint16_t b;
250     switch (code) {
251         case KC_H:
252         case KC_SLASH: /* ? */
253             print("\n\n----- Bluetooth RN-42 Help -----\n");
254             print("i:       RN-42 info\n");
255             print("b:       battery voltage\n");
256             print("Del:     enter/exit RN-42 config mode\n");
257             print("Slck:    RN-42 initialize\n");
258 #if 0
259             print("1-4:     restore link\n");
260             print("F1-F4:   store link\n");
261 #endif
262             print("p:       pairing\n");
263
264             if (config_mode) {
265                 return true;
266             } else {
267                 print("u:       toggle Force USB mode\n");
268                 return false;   // to display default command help
269             }
270         case KC_P:
271             pairing();
272             return true;
273 #if 0
274         /* Store link address to EEPROM */
275         case KC_F1:
276             store_link(RN42_LINK0);
277             return true;
278         case KC_F2:
279             store_link(RN42_LINK1);
280             return true;
281         case KC_F3:
282             store_link(RN42_LINK2);
283             return true;
284         case KC_F4:
285             store_link(RN42_LINK3);
286             return true;
287         /* Restore link address to EEPROM */
288         case KC_1:
289             restore_link(RN42_LINK0);
290             return true;
291         case KC_2:
292             restore_link(RN42_LINK1);
293             return true;
294         case KC_3:
295             restore_link(RN42_LINK2);
296             return true;
297         case KC_4:
298             restore_link(RN42_LINK3);
299             return true;
300 #endif
301         case KC_I:
302             print("\n----- RN-42 info -----\n");
303             xprintf("protocol: %s\n", (host_get_driver() == &rn42_driver) ? "RN-42" : "LUFA");
304             xprintf("force_usb: %X\n", force_usb);
305             xprintf("rn42: %s\n", rn42_rts() ? "OFF" : (rn42_linked() ? "CONN" : "ON"));
306             xprintf("rn42_autoconnecting(): %X\n", rn42_autoconnecting());
307             xprintf("config_mode: %X\n", config_mode);
308             xprintf("USB State: %s\n",
309                     (USB_DeviceState == DEVICE_STATE_Unattached) ? "Unattached" :
310                     (USB_DeviceState == DEVICE_STATE_Powered) ? "Powered" :
311                     (USB_DeviceState == DEVICE_STATE_Default) ? "Default" :
312                     (USB_DeviceState == DEVICE_STATE_Addressed) ? "Addressed" :
313                     (USB_DeviceState == DEVICE_STATE_Configured) ? "Configured" :
314                     (USB_DeviceState == DEVICE_STATE_Suspended) ? "Suspended" : "?");
315             xprintf("battery: ");
316             switch (battery_status()) {
317                 case FULL_CHARGED:  xprintf("FULL"); break;
318                 case CHARGING:      xprintf("CHARG"); break;
319                 case DISCHARGING:   xprintf("DISCHG"); break;
320                 case LOW_VOLTAGE:   xprintf("LOW"); break;
321                 default:            xprintf("?"); break;
322             };
323             xprintf("\n");
324             xprintf("RemoteWakeupEnabled: %X\n", USB_Device_RemoteWakeupEnabled);
325             xprintf("VBUS: %X\n", USBSTA&(1<<VBUS));
326             t = timer_read32()/1000;
327             uint8_t d = t/3600/24;
328             uint8_t h = t/3600;
329             uint8_t m = t%3600/60;
330             uint8_t s = t%60;
331             xprintf("uptime: %02u %02u:%02u:%02u\n", d, h, m, s);
332 #if 0
333             xprintf("LINK0: %s\r\n", get_link(RN42_LINK0));
334             xprintf("LINK1: %s\r\n", get_link(RN42_LINK1));
335             xprintf("LINK2: %s\r\n", get_link(RN42_LINK2));
336             xprintf("LINK3: %s\r\n", get_link(RN42_LINK3));
337 #endif
338             return true;
339         case KC_B:
340             // battery monitor
341             t = timer_read32()/1000;
342             b = battery_voltage();
343             xprintf("BAT: %umV\t", b);
344             xprintf("%02u:",   t/3600);
345             xprintf("%02u:",   t%3600/60);
346             xprintf("%02u\n",  t%60);
347             return true;
348         case KC_U:
349             if (config_mode) return false;
350             if (force_usb) {
351                 print("Auto mode\n");
352                 force_usb = false;
353             } else {
354                 print("USB mode\n");
355                 force_usb = true;
356             }
357             return true;
358         case KC_DELETE:
359             /* RN-42 Command mode */
360             if (rn42_autoconnecting()) {
361                 enter_command_mode();
362
363                 command_state = CONSOLE;
364                 config_mode = true;
365             } else {
366                 exit_command_mode();
367
368                 command_state = ONESHOT;
369                 config_mode = false;
370             }
371             return true;
372         case KC_SCROLLLOCK:
373             init_rn42();
374             return true;
375 #ifdef NKRO_ENABLE
376         case KC_N:
377             if (host_get_driver() != &lufa_driver) {
378                 // ignored unless USB mode
379                 return true;
380             }
381             return false;
382 #endif
383         default:
384             if (config_mode)
385                 return true;
386             else
387                 return false;   // yield to default command
388     }
389     return true;
390 }
391
392 /*
393  * RN-42 Command mode
394  * sends charactors to the module
395  */
396 static uint8_t code2asc(uint8_t code);
397 bool command_console_extra(uint8_t code)
398 {
399     rn42_putc(code2asc(code));
400     return true;
401 }
402
403 // convert keycode into ascii charactor
404 static uint8_t code2asc(uint8_t code)
405 {
406     bool shifted = (get_mods() & (MOD_BIT(KC_LSHIFT)|MOD_BIT(KC_RSHIFT))) ? true : false;
407     switch (code) {
408         case KC_A: return (shifted ? 'A' : 'a');
409         case KC_B: return (shifted ? 'B' : 'b');
410         case KC_C: return (shifted ? 'C' : 'c');
411         case KC_D: return (shifted ? 'D' : 'd');
412         case KC_E: return (shifted ? 'E' : 'e');
413         case KC_F: return (shifted ? 'F' : 'f');
414         case KC_G: return (shifted ? 'G' : 'g');
415         case KC_H: return (shifted ? 'H' : 'h');
416         case KC_I: return (shifted ? 'I' : 'i');
417         case KC_J: return (shifted ? 'J' : 'j');
418         case KC_K: return (shifted ? 'K' : 'k');
419         case KC_L: return (shifted ? 'L' : 'l');
420         case KC_M: return (shifted ? 'M' : 'm');
421         case KC_N: return (shifted ? 'N' : 'n');
422         case KC_O: return (shifted ? 'O' : 'o');
423         case KC_P: return (shifted ? 'P' : 'p');
424         case KC_Q: return (shifted ? 'Q' : 'q');
425         case KC_R: return (shifted ? 'R' : 'r');
426         case KC_S: return (shifted ? 'S' : 's');
427         case KC_T: return (shifted ? 'T' : 't');
428         case KC_U: return (shifted ? 'U' : 'u');
429         case KC_V: return (shifted ? 'V' : 'v');
430         case KC_W: return (shifted ? 'W' : 'w');
431         case KC_X: return (shifted ? 'X' : 'x');
432         case KC_Y: return (shifted ? 'Y' : 'y');
433         case KC_Z: return (shifted ? 'Z' : 'z');
434         case KC_1: return (shifted ? '!' : '1');
435         case KC_2: return (shifted ? '@' : '2');
436         case KC_3: return (shifted ? '#' : '3');
437         case KC_4: return (shifted ? '$' : '4');
438         case KC_5: return (shifted ? '%' : '5');
439         case KC_6: return (shifted ? '^' : '6');
440         case KC_7: return (shifted ? '&' : '7');
441         case KC_8: return (shifted ? '*' : '8');
442         case KC_9: return (shifted ? '(' : '9');
443         case KC_0: return (shifted ? ')' : '0');
444         case KC_ENTER: return '\n';
445         case KC_ESCAPE: return 0x1B;
446         case KC_BSPACE: return '\b';
447         case KC_TAB: return '\t';
448         case KC_SPACE: return ' ';
449         case KC_MINUS: return (shifted ? '_' : '-');
450         case KC_EQUAL: return (shifted ? '+' : '=');
451         case KC_LBRACKET: return (shifted ? '{' : '[');
452         case KC_RBRACKET: return (shifted ? '}' : ']');
453         case KC_BSLASH: return (shifted ? '|' : '\\');
454         case KC_NONUS_HASH: return (shifted ? '|' : '\\');
455         case KC_SCOLON: return (shifted ? ':' : ';');
456         case KC_QUOTE: return (shifted ? '"' : '\'');
457         case KC_GRAVE: return (shifted ? '~' : '`');
458         case KC_COMMA: return (shifted ? '<' : ',');
459         case KC_DOT: return (shifted ? '>' : '.');
460         case KC_SLASH: return (shifted ? '?' : '/');
461         case KC_DELETE: return '\0';    // Delete to disconnect
462         default: return ' ';
463     }
464 }