From 5477bf39bfc01468ea8c09f025cf9c5ee3efd1b7 Mon Sep 17 00:00:00 2001 From: Enochen Date: Mon, 9 Jul 2018 21:12:59 -0400 Subject: add hhkb bluetooth functionality (rn42) (#2693) * add hhkb bluetooth functionality (rn42) pretty much straight from tmk some minor changes to make things work * hhkb jp personal keymap * Revert "hhkb jp personal keymap" This reverts commit 886713d8bb98572f03110f285706a8140a083892. --- keyboards/hhkb/rn42/rn42_task.c | 467 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 467 insertions(+) create mode 100644 keyboards/hhkb/rn42/rn42_task.c (limited to 'keyboards/hhkb/rn42/rn42_task.c') diff --git a/keyboards/hhkb/rn42/rn42_task.c b/keyboards/hhkb/rn42/rn42_task.c new file mode 100644 index 0000000000..88ae88c150 --- /dev/null +++ b/keyboards/hhkb/rn42/rn42_task.c @@ -0,0 +1,467 @@ +#include +#include +#include +#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 "debug.h" +#include "timer.h" +#include "wait.h" +#include "command.h" +#include "battery.h" +#include "keycode_config.h" + +extern keymap_config_t keymap_config; + +static bool config_mode = false; +static bool force_usb = false; + +static void status_led(bool on) +{ + if (on) { + DDRE |= (1<<6); + PORTE &= ~(1<<6); + } else { + DDRE |= (1<<6); + PORTE |= (1<<6); + } +} + +void rn42_task_init(void) +{ + battery_init(); +#ifdef NKRO_ENABLE + rn42_nkro_last = keymap_config.nkro; +#endif +} + +void rn42_task(void) +{ + int16_t c; + // Raw mode: interpret output report of LED state + while ((c = rn42_getc()) != -1) { + // LED Out report: 0xFE, 0x02, 0x01, + // To get the report over UART set bit3 with SH, command. + static enum {LED_INIT, LED_FE, LED_02, LED_01} state = LED_INIT; + switch (state) { + case LED_INIT: + if (c == 0xFE) state = LED_FE; + else { + if (0x0 <= c && c <= 0x7f) xprintf("%c", c); + else xprintf(" %02X", c); + } + 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: + dprintf("LED status: %02X\n", c); + rn42_set_leds(c); + state = LED_INIT; + break; + default: + state = LED_INIT; + } + } + + /* Switch between USB and Bluetooth */ + if (!config_mode) { // not switch while config mode + if (!force_usb && !rn42_rts()) { + if (host_get_driver() != &rn42_driver) { + clear_keyboard(); +#ifdef NKRO_ENABLE + rn42_nkro_last = keymap_config.nkro; + keymap_config.nkro = false; +#endif + host_set_driver(&rn42_driver); + } + } else { + if (host_get_driver() != &lufa_driver) { + clear_keyboard(); +#ifdef NKRO_ENABLE + keymap_config.nkro = rn42_nkro_last; +#endif + host_set_driver(&lufa_driver); + } + } + } + + + static uint16_t prev_timer = 0; + uint16_t e = timer_elapsed(prev_timer); + if (e > 1000) { + /* every second */ + prev_timer += e/1000*1000; + + /* Low voltage alert */ + uint8_t bs = battery_status(); + if (bs == LOW_VOLTAGE) { + battery_led(LED_ON); + } else { + battery_led(LED_CHARGER); + } + + /* every minute */ + uint32_t t = timer_read32()/1000; + if (t%60 == 0) { + uint16_t v = battery_voltage(); + uint8_t h = t/3600; + uint8_t m = t%3600/60; + uint8_t s = t%60; + dprintf("%02u:%02u:%02u\t%umV\n", h, m, s, v); + /* TODO: xprintf doesn't work for this. + xprintf("%02u:%02u:%02u\t%umV\n", (t/3600), (t%3600/60), (t%60), v); + */ + } + } + + + /* Connection monitor */ + if (!rn42_rts() && rn42_linked()) { + status_led(true); + } else { + status_led(false); + } +} + + + +/****************************************************************************** + * Command + ******************************************************************************/ +static host_driver_t *prev_driver = &rn42_driver; + +static void enter_command_mode(void) +{ + prev_driver = host_get_driver(); + clear_keyboard(); + host_set_driver(&rn42_config_driver); // null driver; not to send a key to host + rn42_disconnect(); + while (rn42_linked()) ; + + print("Entering config mode ...\n"); + wait_ms(1100); // need 1 sec + SEND_COMMAND("$$$"); + wait_ms(600); // need 1 sec + rn42_print_response(); + const char *s = SEND_COMMAND("v\r\n"); + if (strncmp("v", s, 1) != 0) SEND_COMMAND("+\r\n"); // local echo on +} + +static void exit_command_mode(void) +{ + print("Exiting config mode ...\n"); + SEND_COMMAND("---\r\n"); // exit + + rn42_autoconnect(); + clear_keyboard(); + host_set_driver(prev_driver); +} + +static void init_rn42(void) +{ + // RN-42 configure + if (!config_mode) enter_command_mode(); + SEND_COMMAND("SF,1\r\n"); // factory defaults + SEND_COMMAND("S-,TmkBT\r\n"); + SEND_COMMAND("SS,Keyboard/Mouse\r\n"); + SEND_COMMAND("SM,4\r\n"); // auto connect(DTR) + SEND_COMMAND("SW,8000\r\n"); // Sniff disable + SEND_COMMAND("S~,6\r\n"); // HID profile + SEND_COMMAND("SH,003C\r\n"); // combo device, out-report, 4-reconnect + SEND_COMMAND("SY,FFF4\r\n"); // transmit power -12 + SEND_COMMAND("R,1\r\n"); + if (!config_mode) exit_command_mode(); +} + +#if 0 +// Switching connections +// NOTE: Remote Address doesn't work in the way manual says. +// EEPROM address for link store +#define RN42_LINK0 (uint8_t *)128 +#define RN42_LINK1 (uint8_t *)140 +#define RN42_LINK2 (uint8_t *)152 +#define RN42_LINK3 (uint8_t *)164 +static void store_link(uint8_t *eeaddr) +{ + enter_command_mode(); + SEND_STR("GR\r\n"); // remote address + const char *s = rn42_gets(500); + if (strcmp("GR", s) == 0) s = rn42_gets(500); // ignore local echo + xprintf("%s(%d)\r\n", s, strlen(s)); + if (strlen(s) == 12) { + for (int i = 0; i < 12; i++) { + eeprom_write_byte(eeaddr+i, *(s+i)); + dprintf("%c ", *(s+i)); + } + dprint("\r\n"); + } + exit_command_mode(); +} + +static void restore_link(const uint8_t *eeaddr) +{ + enter_command_mode(); + SEND_COMMAND("SR,Z\r\n"); // remove remote address + SEND_STR("SR,"); // set remote address from EEPROM + for (int i = 0; i < 12; i++) { + uint8_t c = eeprom_read_byte(eeaddr+i); + rn42_putc(c); + dprintf("%c ", c); + } + dprintf("\r\n"); + SEND_COMMAND("\r\n"); + SEND_COMMAND("R,1\r\n"); // reboot + exit_command_mode(); +} + +static const char *get_link(uint8_t * eeaddr) +{ + static char s[13]; + for (int i = 0; i < 12; i++) { + uint8_t c = eeprom_read_byte(eeaddr+i); + s[i] = c; + } + s[12] = '\0'; + return s; +} +#endif + +static void pairing(void) +{ + enter_command_mode(); + SEND_COMMAND("SR,Z\r\n"); // remove remote address + SEND_COMMAND("R,1\r\n"); // reboot + exit_command_mode(); +} + +bool command_extra(uint8_t code) +{ + uint32_t t; + uint16_t b; + switch (code) { + case KC_H: + case KC_SLASH: /* ? */ + print("\n\n----- Bluetooth RN-42 Help -----\n"); + print("i: RN-42 info\n"); + print("b: battery voltage\n"); + print("Del: enter/exit RN-42 config mode\n"); + print("Slck: RN-42 initialize\n"); +#if 0 + print("1-4: restore link\n"); + print("F1-F4: store link\n"); +#endif + print("p: pairing\n"); + + if (config_mode) { + return true; + } else { + print("u: toggle Force USB mode\n"); + return false; // to display default command help + } + case KC_P: + pairing(); + return true; +#if 0 + /* Store link address to EEPROM */ + case KC_F1: + store_link(RN42_LINK0); + return true; + case KC_F2: + store_link(RN42_LINK1); + return true; + case KC_F3: + store_link(RN42_LINK2); + return true; + case KC_F4: + store_link(RN42_LINK3); + return true; + /* Restore link address to EEPROM */ + case KC_1: + restore_link(RN42_LINK0); + return true; + case KC_2: + restore_link(RN42_LINK1); + return true; + case KC_3: + restore_link(RN42_LINK2); + return true; + case KC_4: + restore_link(RN42_LINK3); + return true; +#endif + 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: %s\n", rn42_rts() ? "OFF" : (rn42_linked() ? "CONN" : "ON")); + xprintf("rn42_autoconnecting(): %X\n", rn42_autoconnecting()); + xprintf("config_mode: %X\n", config_mode); + xprintf("USB State: %s\n", + (USB_DeviceState == DEVICE_STATE_Unattached) ? "Unattached" : + (USB_DeviceState == DEVICE_STATE_Powered) ? "Powered" : + (USB_DeviceState == DEVICE_STATE_Default) ? "Default" : + (USB_DeviceState == DEVICE_STATE_Addressed) ? "Addressed" : + (USB_DeviceState == DEVICE_STATE_Configured) ? "Configured" : + (USB_DeviceState == DEVICE_STATE_Suspended) ? "Suspended" : "?"); + xprintf("battery: "); + switch (battery_status()) { + case FULL_CHARGED: xprintf("FULL"); break; + case CHARGING: xprintf("CHARG"); break; + case DISCHARGING: xprintf("DISCHG"); break; + case LOW_VOLTAGE: xprintf("LOW"); break; + default: xprintf("?"); break; + }; + xprintf("\n"); + xprintf("RemoteWakeupEnabled: %X\n", USB_Device_RemoteWakeupEnabled); + xprintf("VBUS: %X\n", USBSTA&(1<' : '.'); + case KC_SLASH: return (shifted ? '?' : '/'); + case KC_DELETE: return '\0'; // Delete to disconnect + default: return ' '; + } +} -- cgit v1.2.3