From 59ea5e02f76a37e5021c5f9d02af149e48e7c07c Mon Sep 17 00:00:00 2001 From: tmk Date: Sat, 19 Jul 2014 02:33:23 +0900 Subject: Mkdir rn42 --- keyboard/hhkb_rn42/rn42/main.c | 102 +++++++++++++++ keyboard/hhkb_rn42/rn42/rn42.c | 192 +++++++++++++++++++++++++++ keyboard/hhkb_rn42/rn42/rn42.h | 18 +++ keyboard/hhkb_rn42/rn42/rn42_task.c | 255 ++++++++++++++++++++++++++++++++++++ keyboard/hhkb_rn42/rn42/rn42_task.h | 10 ++ keyboard/hhkb_rn42/rn42/suart.S | 156 ++++++++++++++++++++++ keyboard/hhkb_rn42/rn42/suart.h | 8 ++ 7 files changed, 741 insertions(+) create mode 100644 keyboard/hhkb_rn42/rn42/main.c create mode 100644 keyboard/hhkb_rn42/rn42/rn42.c create mode 100644 keyboard/hhkb_rn42/rn42/rn42.h create mode 100644 keyboard/hhkb_rn42/rn42/rn42_task.c create mode 100644 keyboard/hhkb_rn42/rn42/rn42_task.h create mode 100644 keyboard/hhkb_rn42/rn42/suart.S create mode 100644 keyboard/hhkb_rn42/rn42/suart.h (limited to 'keyboard/hhkb_rn42/rn42') diff --git a/keyboard/hhkb_rn42/rn42/main.c b/keyboard/hhkb_rn42/rn42/main.c new file mode 100644 index 0000000000..a3a37c0747 --- /dev/null +++ b/keyboard/hhkb_rn42/rn42/main.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include "lufa.h" +#include "print.h" +#include "sendchar.h" +#include "rn42.h" +#include "rn42_task.h" +#include "serial.h" +#include "keyboard.h" +#include "keycode.h" +#include "action.h" +#include "action_util.h" +#include "wait.h" +#include "suart.h" +#include "suspend.h" + +static int8_t sendchar_func(uint8_t c) +{ + sendchar(c); // LUFA + xmit(c); // SUART + return 0; +} + +static void SetupHardware(void) +{ + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Disable clock division */ + clock_prescale_set(clock_div_1); + + // Leonardo needs. Without this USB device is not recognized. + USB_Disable(); + + USB_Init(); + + // for Console_Task + USB_Device_EnableSOFEvents(); + print_set_sendchar(sendchar_func); + + // SUART PD0:output, PD1:input + DDRD |= (1<<0); + PORTD |= (1<<0); + DDRD &= ~(1<<1); + PORTD |= (1<<1); +} + +int main(void) __attribute__ ((weak)); +int main(void) +{ + SetupHardware(); + sei(); + + /* wait for USB startup to get ready for debug output */ + uint8_t timeout = 255; // timeout when USB is not available(Bluetooth) + while (timeout-- && USB_DeviceState != DEVICE_STATE_Configured) { + wait_ms(4); +#if defined(INTERRUPT_CONTROL_ENDPOINT) + ; +#else + USB_USBTask(); +#endif + } + print("USB configured.\n"); + + rn42_init(); + rn42_task_init(); + print("RN-42 init\n"); + + /* init modules */ + keyboard_init(); + + if (!rn42_rts()) { + host_set_driver(&rn42_driver); + } else { + host_set_driver(&lufa_driver); + } + +#ifdef SLEEP_LED_ENABLE + sleep_led_init(); +#endif + + print("Keyboard start.\n"); + while (1) { + while (USB_DeviceState == DEVICE_STATE_Suspended) { + suspend_power_down(); + if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) { + USB_Device_SendRemoteWakeup(); + } + } + + keyboard_task(); + +#if !defined(INTERRUPT_CONTROL_ENDPOINT) + USB_USBTask(); +#endif + + rn42_task(); + } +} diff --git a/keyboard/hhkb_rn42/rn42/rn42.c b/keyboard/hhkb_rn42/rn42/rn42.c new file mode 100644 index 0000000000..3fcd64ad6a --- /dev/null +++ b/keyboard/hhkb_rn42/rn42/rn42.c @@ -0,0 +1,192 @@ +#include +#include "host.h" +#include "host_driver.h" +#include "serial.h" +#include "rn42.h" +#include "print.h" +#include "wait.h" + + +/* Host driver */ +static uint8_t keyboard_leds(void); +static void send_keyboard(report_keyboard_t *report); +static void send_mouse(report_mouse_t *report); +static void send_system(uint16_t data); +static void send_consumer(uint16_t data); + +host_driver_t rn42_driver = { + keyboard_leds, + send_keyboard, + send_mouse, + send_system, + send_consumer +}; + + +void rn42_init(void) +{ + // PF7: BT connection control(HiZ: connect, low: disconnect) + // JTAG disable for PORT F. write JTD bit twice within four cycles. + MCUCR |= (1<mods); + serial_send(0x00); + serial_send(report->keys[0]); + serial_send(report->keys[1]); + serial_send(report->keys[2]); + serial_send(report->keys[3]); + serial_send(report->keys[4]); + serial_send(report->keys[5]); +} + +static void send_mouse(report_mouse_t *report) +{ + // wake from deep sleep +/* + PORTD |= (1<<5); // high + wait_ms(5); + PORTD &= ~(1<<5); // low +*/ + + serial_send(0xFD); // Raw report mode + serial_send(5); // length + serial_send(2); // descriptor type + serial_send(report->buttons); + serial_send(report->x); + serial_send(report->y); + serial_send(report->v); +} + +static void send_system(uint16_t data) +{ + // Table 5-6 of RN-BT-DATA-UB + // 81,82,83 scan codes can be used? +} + + +static uint16_t usage2bits(uint16_t usage) +{ + switch (usage) { + case AC_HOME: return 0x01; + case AL_EMAIL: return 0x02; + case AC_SEARCH: return 0x04; + //case AL_KBD_LAYOUT: return 0x08; // Apple virtual keybaord toggle + case AUDIO_VOL_UP: return 0x10; + case AUDIO_VOL_DOWN: return 0x20; + case AUDIO_MUTE: return 0x40; + case TRANSPORT_PLAY_PAUSE: return 0x80; + case TRANSPORT_NEXT_TRACK: return 0x100; + case TRANSPORT_PREV_TRACK: return 0x200; + case TRANSPORT_STOP: return 0x400; + case TRANSPORT_STOP_EJECT: return 0x800; + //case return 0x1000; // Fast forward + //case return 0x2000; // Rewind + //case return 0x4000; // Stop/eject + //case return 0x8000; // Internet browser + }; + return 0; +} + +static void send_consumer(uint16_t data) +{ + uint16_t bits = usage2bits(data); + serial_send(0xFD); // Raw report mode + serial_send(3); // length + serial_send(3); // descriptor type + serial_send(bits&0xFF); + serial_send((bits>>8)&0xFF); +} + + +/* Null driver for config_mode */ +static uint8_t config_keyboard_leds(void); +static void config_send_keyboard(report_keyboard_t *report); +static void config_send_mouse(report_mouse_t *report); +static void config_send_system(uint16_t data); +static void config_send_consumer(uint16_t data); + +host_driver_t rn42_config_driver = { + config_keyboard_leds, + config_send_keyboard, + config_send_mouse, + config_send_system, + config_send_consumer +}; + +static uint8_t config_keyboard_leds(void) { return 0; } +static void config_send_keyboard(report_keyboard_t *report) {} +static void config_send_mouse(report_mouse_t *report) {} +static void config_send_system(uint16_t data) {} +static void config_send_consumer(uint16_t data) {} diff --git a/keyboard/hhkb_rn42/rn42/rn42.h b/keyboard/hhkb_rn42/rn42/rn42.h new file mode 100644 index 0000000000..4189733b49 --- /dev/null +++ b/keyboard/hhkb_rn42/rn42/rn42.h @@ -0,0 +1,18 @@ +#ifndef RN42_H +#define RN42_H + +#include + +host_driver_t rn42_driver; +host_driver_t rn42_config_driver; + +void rn42_init(void); +void rn42_putc(uint8_t c); +bool rn42_autoconnecting(void); +void rn42_autoconnect(void); +void rn42_disconnect(void); +bool rn42_rts(void); +void rn42_cts_hi(void); +void rn42_cts_lo(void); + +#endif diff --git a/keyboard/hhkb_rn42/rn42/rn42_task.c b/keyboard/hhkb_rn42/rn42/rn42_task.c new file mode 100644 index 0000000000..7ec4c1b540 --- /dev/null +++ b/keyboard/hhkb_rn42/rn42/rn42_task.c @@ -0,0 +1,255 @@ +#include +#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< + // 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 ' '; + } +} diff --git a/keyboard/hhkb_rn42/rn42/rn42_task.h b/keyboard/hhkb_rn42/rn42/rn42_task.h new file mode 100644 index 0000000000..8f6c3ab64d --- /dev/null +++ b/keyboard/hhkb_rn42/rn42/rn42_task.h @@ -0,0 +1,10 @@ +#ifndef RN42_TASK_H +#define RN42_TASK_H + +#include +#include "rn42.h" + +void rn42_task_init(void); +void rn42_task(void); + +#endif diff --git a/keyboard/hhkb_rn42/rn42/suart.S b/keyboard/hhkb_rn42/rn42/suart.S new file mode 100644 index 0000000000..9fa5452928 --- /dev/null +++ b/keyboard/hhkb_rn42/rn42/suart.S @@ -0,0 +1,156 @@ +;---------------------------------------------------------------------------; +; Software implemented UART module ; +; (C)ChaN, 2005 (http://elm-chan.org/) ; +;---------------------------------------------------------------------------; +; Bit rate settings: +; +; 1MHz 2MHz 4MHz 6MHz 8MHz 10MHz 12MHz 16MHz 20MHz +; 2.4kbps 138 - - - - - - - - +; 4.8kbps 68 138 - - - - - - - +; 9.6kbps 33 68 138 208 - - - - - +; 19.2kbps - 33 68 102 138 173 208 - - +; 38.4kbps - - 33 50 68 85 102 138 172 +; 57.6kbps - - 21 33 44 56 68 91 114 +; 115.2kbps - - - - 21 27 33 44 56 + +.nolist +#include +.list + +#define BPS 44 /* Bit delay. (see above table) */ +#define BIDIR 0 /* 0:Separated Tx/Rx, 1:Shared Tx/Rx */ + +#define OUT_1 sbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 1 */ +#define OUT_0 cbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 0 */ +#define SKIP_IN_1 sbis _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 1 */ +#define SKIP_IN_0 sbic _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 0 */ + + + +#ifdef SPM_PAGESIZE +.macro _LPMI reg + lpm \reg, Z+ +.endm +.macro _MOVW dh,dl, sh,sl + movw \dl, \sl +.endm +#else +.macro _LPMI reg + lpm + mov \reg, r0 + adiw ZL, 1 +.endm +.macro _MOVW dh,dl, sh,sl + mov \dl, \sl + mov \dh, \sh +.endm +#endif + + + +;---------------------------------------------------------------------------; +; Transmit a byte in serial format of N81 +; +;Prototype: void xmit (uint8_t data); +;Size: 16 words + +.global xmit +.func xmit +xmit: +#if BIDIR + ldi r23, BPS-1 ;Pre-idle time for bidirectional data line +5: dec r23 ; + brne 5b ;/ +#endif + in r0, _SFR_IO_ADDR(SREG) ;Save flags + + com r24 ;C = start bit + ldi r25, 10 ;Bit counter + cli ;Start critical section + +1: ldi r23, BPS-1 ;----- Bit transferring loop +2: dec r23 ;Wait for a bit time + brne 2b ;/ + brcs 3f ;MISO = bit to be sent + OUT_1 ; +3: brcc 4f ; + OUT_0 ;/ +4: lsr r24 ;Get next bit into C + dec r25 ;All bits sent? + brne 1b ; no, coutinue + + out _SFR_IO_ADDR(SREG), r0 ;End of critical section + ret +.endfunc + + + +;---------------------------------------------------------------------------; +; Receive a byte +; +;Prototype: uint8_t rcvr (void); +;Size: 19 words + +.global rcvr +.func rcvr +rcvr: + in r0, _SFR_IO_ADDR(SREG) ;Save flags + + ldi r24, 0x80 ;Receiving shift reg + cli ;Start critical section + +1: SKIP_IN_1 ;Wait for idle + rjmp 1b +2: SKIP_IN_0 ;Wait for start bit + rjmp 2b + ldi r25, BPS/2 ;Wait for half bit time +3: dec r25 + brne 3b + +4: ldi r25, BPS ;----- Bit receiving loop +5: dec r25 ;Wait for a bit time + brne 5b ;/ + lsr r24 ;Next bit + SKIP_IN_0 ;Get a data bit into r24.7 + ori r24, 0x80 + brcc 4b ;All bits received? no, continue + + out _SFR_IO_ADDR(SREG), r0 ;End of critical section + ret +.endfunc + + +; Not wait for start bit. This should be called after detecting start bit. +.global recv +.func recv +recv: + in r0, _SFR_IO_ADDR(SREG) ;Save flags + + ldi r24, 0x80 ;Receiving shift reg + cli ;Start critical section + +;1: SKIP_IN_1 ;Wait for idle +; rjmp 1b +;2: SKIP_IN_0 ;Wait for start bit +; rjmp 2b + ldi r25, BPS/2 ;Wait for half bit time +3: dec r25 + brne 3b + +4: ldi r25, BPS ;----- Bit receiving loop +5: dec r25 ;Wait for a bit time + brne 5b ;/ + lsr r24 ;Next bit + SKIP_IN_0 ;Get a data bit into r24.7 + ori r24, 0x80 + brcc 4b ;All bits received? no, continue + + ldi r25, BPS/2 ;Wait for half bit time +6: dec r25 + brne 6b +7: SKIP_IN_1 ;Wait for stop bit + rjmp 7b + + out _SFR_IO_ADDR(SREG), r0 ;End of critical section + ret +.endfunc diff --git a/keyboard/hhkb_rn42/rn42/suart.h b/keyboard/hhkb_rn42/rn42/suart.h new file mode 100644 index 0000000000..72725b998f --- /dev/null +++ b/keyboard/hhkb_rn42/rn42/suart.h @@ -0,0 +1,8 @@ +#ifndef SUART +#define SUART + +void xmit(uint8_t); +uint8_t rcvr(void); +uint8_t recv(void); + +#endif /* SUART */ -- cgit v1.2.3