413 lines
9.8 KiB
C
413 lines
9.8 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 "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;
|
||
|
}
|
||
|
}
|