/* Copyright 2011 Jun Wako <wakojun@gmail.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stdint.h> #include <avr/interrupt.h> #include <avr/io.h> //#include <avr/wdt.h> #include "wd.h" // in order to use watchdog in interrupt mode #include <avr/sleep.h> #include <util/delay.h> #include <avr/power.h> #include "keyboard.h" #include "matrix.h" #include "host.h" #include "action.h" #include "iwrap.h" #ifdef PROTOCOL_VUSB # include "vusb.h" # include "usbdrv.h" #endif #include "uart.h" #include "suart.h" #include "timer.h" #include "debug.h" #include "keycode.h" #include "command.h" static void sleep(uint8_t term); static bool console(void); static bool console_command(uint8_t c); static uint8_t key2asc(uint8_t key); /* static void set_prr(void) { power_adc_disable(); power_spi_disable(); power_twi_disable(); #ifndef TIMER_H //power_timer0_disable(); // used in timer.c #endif power_timer1_disable(); power_timer2_disable(); } */ /* static void pullup_pins(void) { // DDRs are set to 0(input) by default. #ifdef PORTA PORTA = 0xFF; #endif PORTB = 0xFF; PORTC = 0xFF; PORTD = 0xFF; #ifdef PORTE PORTE = 0xFF; #endif #ifdef PORTE PORTF = 0xFF; #endif } */ #ifdef PROTOCOL_VUSB static void disable_vusb(void) { // disable interrupt & disconnect to prevent host from enumerating USB_INTR_ENABLE &= ~(1 << USB_INTR_ENABLE_BIT); usbDeviceDisconnect(); } static void enable_vusb(void) { USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); usbDeviceConnect(); } static void init_vusb(void) { uint8_t i = 0; usbInit(); disable_vusb(); /* fake USB disconnect for > 250 ms */ while(--i){ _delay_ms(1); } enable_vusb(); } #endif void change_driver(host_driver_t *driver) { /* host_clear_keyboard_report(); host_swap_keyboard_report(); host_clear_keyboard_report(); host_send_keyboard_report(); */ clear_keyboard(); _delay_ms(1000); host_set_driver(driver); } static bool sleeping = false; static bool insomniac = false; // TODO: should be false for power saving static uint16_t last_timer = 0; int main(void) { MCUSR = 0; clock_prescale_set(clock_div_1); WD_SET(WD_OFF); // power saving: the result is worse than nothing... why? //pullup_pins(); //set_prr(); #ifdef PROTOCOL_VUSB disable_vusb(); #endif uart_init(115200); keyboard_init(); print("\nSend BREAK for UART Console Commands.\n"); // TODO: move to iWRAP/suart file print("suart init\n"); // suart init // PC4: Tx Output IDLE(Hi) PORTC |= (1<<4); DDRC |= (1<<4); // PC5: Rx Input(pull-up) PORTC |= (1<<5); DDRC &= ~(1<<5); // suart receive interrut(PC5/PCINT13) PCMSK1 = 0b00100000; PCICR = 0b00000010; host_set_driver(iwrap_driver()); print("iwrap_init()\n"); iwrap_init(); iwrap_call(); last_timer = timer_read(); while (true) { #ifdef PROTOCOL_VUSB if (host_get_driver() == vusb_driver()) usbPoll(); #endif keyboard_task(); #ifdef PROTOCOL_VUSB if (host_get_driver() == vusb_driver()) vusb_transfer_keyboard(); #endif // TODO: depricated if (matrix_is_modified() || console()) { last_timer = timer_read(); sleeping = false; } else if (!sleeping && timer_elapsed(last_timer) > 4000) { sleeping = true; iwrap_check_connection(); } // TODO: suspend.h if (host_get_driver() == iwrap_driver()) { if (sleeping && !insomniac) { _delay_ms(1); // wait for UART to send iwrap_sleep(); sleep(WDTO_60MS); } } } } static void sleep(uint8_t term) { WD_SET(WD_IRQ, term); cli(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_bod_disable(); sei(); sleep_cpu(); sleep_disable(); WD_SET(WD_OFF); } static bool console(void) { // Send to Bluetoot module WT12 static bool breaked = false; if (!uart_available()) return false; else { uint8_t c; c = uart_getchar(); uart_putchar(c); switch (c) { case 0x00: // BREAK signal if (!breaked) { print("break(? for help): "); breaked = true; } break; case '\r': uart_putchar('\n'); iwrap_buf_send(); break; case '\b': iwrap_buf_del(); break; default: if (breaked) { print("\n"); console_command(c); breaked = false; } else { iwrap_buf_add(c); } break; } return true; } } bool command_extra(uint8_t code) { return console_command(key2asc(code)); } static bool console_command(uint8_t c) { switch (c) { case 'h': case '?': print("\nCommands for Bluetooth(WT12/iWRAP):\n"); print("r: reset. software reset by watchdog\n"); print("i: insomniac. prevent KB from sleeping\n"); print("c: iwrap_call. CALL for BT connection.\n"); #ifdef PROTOCOL_VUSB print("u: USB mode. switch to USB.\n"); print("w: BT mode. switch to Bluetooth.\n"); #endif print("k: kill first connection.\n"); print("Del: unpair first pairing.\n"); print("\n"); return 0; case 'r': print("reset\n"); WD_AVR_RESET(); return 1; case 'i': insomniac = !insomniac; if (insomniac) print("insomniac\n"); else print("not insomniac\n"); return 1; case 'c': print("iwrap_call()\n"); iwrap_call(); return 1; #ifdef PROTOCOL_VUSB case 'u': print("USB mode\n"); init_vusb(); change_driver(vusb_driver()); //iwrap_kill(); //iwrap_sleep(); // disable suart receive interrut(PC5/PCINT13) PCMSK1 &= ~(0b00100000); PCICR &= ~(0b00000010); return 1; case 'w': print("iWRAP mode\n"); change_driver(iwrap_driver()); disable_vusb(); // enable suart receive interrut(PC5/PCINT13) PCMSK1 |= 0b00100000; PCICR |= 0b00000010; return 1; #endif case 'k': print("kill\n"); iwrap_kill(); return 1; case 0x7F: // DELETE print("unpair\n"); iwrap_unpair(); return 1; } return 0; } // convert keycode into ascii charactor static uint8_t key2asc(uint8_t key) { switch (key) { case KC_A: return 'a'; case KC_B: return 'b'; case KC_C: return 'c'; case KC_D: return 'd'; case KC_E: return 'e'; case KC_F: return 'f'; case KC_G: return 'g'; case KC_H: return 'h'; case KC_I: return 'i'; case KC_J: return 'j'; case KC_K: return 'k'; case KC_L: return 'l'; case KC_M: return 'm'; case KC_N: return 'n'; case KC_O: return 'o'; case KC_P: return 'p'; case KC_Q: return 'q'; case KC_R: return 'r'; case KC_S: return 's'; case KC_T: return 't'; case KC_U: return 'u'; case KC_V: return 'v'; case KC_W: return 'w'; case KC_X: return 'x'; case KC_Y: return 'y'; case KC_Z: return 'z'; case KC_1: return '1'; case KC_2: return '2'; case KC_3: return '3'; case KC_4: return '4'; case KC_5: return '5'; case KC_6: return '6'; case KC_7: return '7'; case KC_8: return '8'; case KC_9: return '9'; case KC_0: return '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 '-'; case KC_EQUAL: return '='; case KC_LBRACKET: return '['; case KC_RBRACKET: return ']'; case KC_BSLASH: return '\\'; case KC_NONUS_HASH: return '\\'; case KC_SCOLON: return ';'; case KC_QUOTE: return '\''; case KC_GRAVE: return '`'; case KC_COMMA: return ','; case KC_DOT: return '.'; case KC_SLASH: return '/'; default: return 0x00; } }