|  |  |  | /*
 | 
					
						
							|  |  |  | 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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |