diff options
Diffstat (limited to 'keyboard/hhkb_rn42/rn42_task.c')
-rw-r--r-- | keyboard/hhkb_rn42/rn42_task.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/keyboard/hhkb_rn42/rn42_task.c b/keyboard/hhkb_rn42/rn42_task.c new file mode 100644 index 0000000000..7ec4c1b540 --- /dev/null +++ b/keyboard/hhkb_rn42/rn42_task.c @@ -0,0 +1,255 @@ +#include <stdint.h> +#include "keycode.h" +#include "serial.h" +#include "host.h" +#include "action.h" +#include "action_util.h" +#include "lufa.h" +#include "rn42_task.h" +#include "print.h" +#include "timer.h" +#include "command.h" + +static bool config_mode = false; +static bool force_usb = false; + +static void battery_adc_init(void) +{ + ADMUX = (1<<REFS1) | (1<<REFS0); // Ref:2.56V band-gap, Input:ADC0(PF0) + ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Prescale:128 16MHz/128=125KHz + ADCSRA |= (1<<ADEN); // enable ADC +} + +static uint16_t battery_adc(void) +{ + volatile uint16_t bat; + ADCSRA |= (1<<ADEN); + + // discard first result + ADCSRA |= (1<<ADSC); + while (ADCSRA & (1<<ADSC)) ; + bat = ADC; + + // discard second result + ADCSRA |= (1<<ADSC); + while (ADCSRA & (1<<ADSC)) ; + bat = ADC; + + ADCSRA |= (1<<ADSC); + while (ADCSRA & (1<<ADSC)) ; + bat = ADC; + + ADCSRA &= ~(1<<ADEN); + return bat; +} + + +void rn42_task_init(void) +{ + battery_adc_init(); +} + +void rn42_task(void) +{ + int16_t c; + if (config_mode) { + // Config mode: print output from RN-42 + while ((c = serial_recv2()) != -1) { + // without flow control it'll fail to receive data when flooded + rn42_cts_hi(); + xprintf("%c", c); + rn42_cts_lo(); + } + } else { + // Raw mode: interpret output report of LED state + while ((c = serial_recv2()) != -1) { + // LED Out report: 0xFE, 0x02, 0x01, <leds> + // To get the report over UART set bit3 with SH, command. + static enum {LED_INIT, LED_FE, LED_02, LED_01} state = LED_INIT; + xprintf("%02X\n", c); + switch (state) { + case LED_INIT: + if (c == 0xFE) state = LED_FE; + else state = LED_INIT; + break; + case LED_FE: + if (c == 0x02) state = LED_02; + else state = LED_INIT; + break; + case LED_02: + if (c == 0x01) state = LED_01; + else state = LED_INIT; + break; + case LED_01: + // TODO: move to rn42.c and make accessible with keyboard_leds() + xprintf("LED status: %02X\n", c); + state = LED_INIT; + break; + default: + state = LED_INIT; + } + } + } + + /* Bluetooth mode when ready */ + if (!config_mode && !force_usb) { + if (!rn42_rts() && host_get_driver() != &rn42_driver) { + clear_keyboard(); + host_set_driver(&rn42_driver); + } else if (rn42_rts() && host_get_driver() != &lufa_driver) { + clear_keyboard(); + host_set_driver(&lufa_driver); + } + } +} + + + +/****************************************************************************** + * Command + ******************************************************************************/ +bool command_extra(uint8_t code) +{ + static host_driver_t *prev_driver = &rn42_driver; + switch (code) { + case KC_H: + case KC_SLASH: /* ? */ + print("\n\n----- Bluetooth RN-42 Help -----\n"); + print("Del: enter/exit config mode(auto_connect/disconnect)\n"); + print("i: RN-42 info\n"); + print("b: battery voltage\n"); + + if (config_mode) { + return true; + } else { + print("u: Force USB mode\n"); + return false; // to display default command help + } + case KC_DELETE: + if (rn42_autoconnecting()) { + prev_driver = host_get_driver(); + clear_keyboard(); + _delay_ms(500); + host_set_driver(&rn42_config_driver); // null driver; not to send a key to host + rn42_disconnect(); + print("\nRN-42: disconnect\n"); + print("Enter config mode\n"); + print("type $$$ to start and + for local echo\n"); + command_state = CONSOLE; + config_mode = true; + } else { + rn42_autoconnect(); + print("\nRN-42: auto_connect\n"); + print("Exit config mode\n"); + command_state = ONESHOT; + config_mode = false; + //clear_keyboard(); + host_set_driver(prev_driver); + } + return true; + case KC_U: + if (config_mode) return false; + if (force_usb) { + print("Auto mode\n"); + force_usb = false; + } else { + print("USB mode\n"); + force_usb = true; + clear_keyboard(); + host_set_driver(&lufa_driver); + } + return true; + case KC_I: + print("\n----- RN-42 info -----\n"); + xprintf("protocol: %s\n", (host_get_driver() == &rn42_driver) ? "RN-42" : "LUFA"); + xprintf("force_usb: %X\n", force_usb); + xprintf("rn42_autoconnecting(): %X\n", rn42_autoconnecting()); + xprintf("rn42_rts(): %X\n", rn42_rts()); + xprintf("config_mode: %X\n", config_mode); + return true; + case KC_B: + // battery monitor + xprintf("BAT: %04X(%08lX)\n", battery_adc(), timer_read32()); + return true; + default: + if (config_mode) + return true; + else + return false; // exec default command + } + return true; +} + +static uint8_t code2asc(uint8_t code); +bool command_console_extra(uint8_t code) +{ + switch (code) { + default: + rn42_putc(code2asc(code)); + return true; + } + return false; +} + +// convert keycode into ascii charactor +static uint8_t code2asc(uint8_t code) +{ + bool shifted = (get_mods() & (MOD_BIT(KC_LSHIFT)|MOD_BIT(KC_RSHIFT))) ? true : false; + switch (code) { + case KC_A: return (shifted ? 'A' : 'a'); + case KC_B: return (shifted ? 'B' : 'b'); + case KC_C: return (shifted ? 'C' : 'c'); + case KC_D: return (shifted ? 'D' : 'd'); + case KC_E: return (shifted ? 'E' : 'e'); + case KC_F: return (shifted ? 'F' : 'f'); + case KC_G: return (shifted ? 'G' : 'g'); + case KC_H: return (shifted ? 'H' : 'h'); + case KC_I: return (shifted ? 'I' : 'i'); + case KC_J: return (shifted ? 'J' : 'j'); + case KC_K: return (shifted ? 'K' : 'k'); + case KC_L: return (shifted ? 'L' : 'l'); + case KC_M: return (shifted ? 'M' : 'm'); + case KC_N: return (shifted ? 'N' : 'n'); + case KC_O: return (shifted ? 'O' : 'o'); + case KC_P: return (shifted ? 'P' : 'p'); + case KC_Q: return (shifted ? 'Q' : 'q'); + case KC_R: return (shifted ? 'R' : 'r'); + case KC_S: return (shifted ? 'S' : 's'); + case KC_T: return (shifted ? 'T' : 't'); + case KC_U: return (shifted ? 'U' : 'u'); + case KC_V: return (shifted ? 'V' : 'v'); + case KC_W: return (shifted ? 'W' : 'w'); + case KC_X: return (shifted ? 'X' : 'x'); + case KC_Y: return (shifted ? 'Y' : 'y'); + case KC_Z: return (shifted ? 'Z' : 'z'); + case KC_1: return (shifted ? '!' : '1'); + case KC_2: return (shifted ? '@' : '2'); + case KC_3: return (shifted ? '#' : '3'); + case KC_4: return (shifted ? '$' : '4'); + case KC_5: return (shifted ? '%' : '5'); + case KC_6: return (shifted ? '^' : '6'); + case KC_7: return (shifted ? '&' : '7'); + case KC_8: return (shifted ? '*' : '8'); + case KC_9: return (shifted ? '(' : '9'); + case KC_0: return (shifted ? ')' : '0'); + case KC_ENTER: return '\n'; + case KC_ESCAPE: return 0x1B; + case KC_BSPACE: return '\b'; + case KC_TAB: return '\t'; + case KC_SPACE: return ' '; + case KC_MINUS: return (shifted ? '_' : '-'); + case KC_EQUAL: return (shifted ? '+' : '='); + case KC_LBRACKET: return (shifted ? '{' : '['); + case KC_RBRACKET: return (shifted ? '}' : ']'); + case KC_BSLASH: return (shifted ? '|' : '\\'); + case KC_NONUS_HASH: return (shifted ? '|' : '\\'); + case KC_SCOLON: return (shifted ? ':' : ';'); + case KC_QUOTE: return (shifted ? '"' : '\''); + case KC_GRAVE: return (shifted ? '~' : '`'); + case KC_COMMA: return (shifted ? '<' : ','); + case KC_DOT: return (shifted ? '>' : '.'); + case KC_SLASH: return (shifted ? '?' : '/'); + case KC_DELETE: return '\0'; // Delete to disconnect + default: return ' '; + } +} |