375 lines
9.2 KiB
C
375 lines
9.2 KiB
C
/*
|
|
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 "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 uint8_t 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();
|
|
_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
|
|
if (matrix_is_modified() || console()) {
|
|
last_timer = timer_read();
|
|
sleeping = false;
|
|
} else if (!sleeping && timer_elapsed(last_timer) > 4000) {
|
|
sleeping = true;
|
|
iwrap_check_connection();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
ISR(WDT_vect)
|
|
{
|
|
// wake up
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
uint8_t command_extra()
|
|
{
|
|
return console_command(key2asc(host_get_first_key()));
|
|
}
|
|
|
|
static uint8_t 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;
|
|
}
|
|
}
|