#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 "command.h" #include "battery.h" 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(); } 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 xprintf("%c", c); } } else { // Raw mode: interpret output report of LED state while ((c = serial_recv2()) != -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 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: dprintf("LED status: %02X\n", c); rn42_set_leds(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); } } 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); } static uint8_t prev_status = UNKNOWN; if (bs != prev_status) { prev_status = bs; switch (bs) { case FULL_CHARGED: xprintf("FULL_CHARGED\n"); break; case CHARGING: xprintf("CHARGING\n"); break; case DISCHARGING: xprintf("DISCHARGING\n"); break; case LOW_VOLTAGE: xprintf("LOW_VOLTAGE\n"); break; default: xprintf("UNKNOWN STATUS\n"); break; }; } /* 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; xprintf("%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_linked()) { status_led(true); } else { status_led(false); } } /****************************************************************************** * Command ******************************************************************************/ bool command_extra(uint8_t code) { uint32_t t; uint16_t b; 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_linked(): %X\n", rn42_linked()); xprintf("rn42_rts(): %X\n", rn42_rts()); xprintf("config_mode: %X\n", config_mode); xprintf("VBUS: %X\n", USBSTA&(1<' : '.'); case KC_SLASH: return (shifted ? '?' : '/'); case KC_DELETE: return '\0'; // Delete to disconnect default: return ' '; } }