static void matrix_make(uint8_t code); | static void matrix_make(uint8_t code); | ||||
static void matrix_break(uint8_t code); | static void matrix_break(uint8_t code); | ||||
static void matrix_clear(void); | |||||
/* | /* | ||||
matrix[ROW(code)] &= ~(1<<COL(code)); | matrix[ROW(code)] &= ~(1<<COL(code)); | ||||
} | } | ||||
inline | |||||
static void matrix_clear(void) | |||||
void matrix_clear(void) | |||||
{ | { | ||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | ||||
} | } |
CONSOLE_ENABLE ?= yes # Console for debug(+400) | CONSOLE_ENABLE ?= yes # Console for debug(+400) | ||||
COMMAND_ENABLE ?= yes # Commands for debug and configuration | COMMAND_ENABLE ?= yes # Commands for debug and configuration | ||||
#SLEEP_LED_ENABLE ?= yes # Breathing sleep LED during USB suspend | #SLEEP_LED_ENABLE ?= yes # Breathing sleep LED during USB suspend | ||||
#NKRO_ENABLE ?= yes # USB Nkey Rollover - not yet supported in LUFA | |||||
#NKRO_ENABLE ?= yes # USB Nkey Rollover | |||||
#KEYMAP_SECTION_ENABLE ?= yes # fixed address keymap for keymap editor | #KEYMAP_SECTION_ENABLE ?= yes # fixed address keymap for keymap editor | ||||
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. | # CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. | ||||
F_USB ?= $(F_CPU) | F_USB ?= $(F_CPU) | ||||
# Interrupt driven control endpoint task(+60) | |||||
# Interrupt driven control endpoint task | |||||
# Not work with suart debug | |||||
#OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT | #OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT | ||||
# This improves response of keyboard when wakeup | |||||
OPT_DEFS += -DSUSPEND_MODE_STANDBY | |||||
# Boot Section Size in *bytes* | # Boot Section Size in *bytes* | ||||
# Teensy halfKay 512 | # Teensy halfKay 512 | ||||
EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) | EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) | ||||
CONSOLE_ENABLE ?= yes # Console for debug(+400) | CONSOLE_ENABLE ?= yes # Console for debug(+400) | ||||
COMMAND_ENABLE ?= yes # Commands for debug and configuration | COMMAND_ENABLE ?= yes # Commands for debug and configuration | ||||
NKRO_ENABLE ?= yes # USB Nkey Rollover - not yet supported in LUFA | |||||
NKRO_ENABLE ?= yes # USB Nkey Rollover | |||||
# PS/2 Options | # PS/2 Options |
TARGET = ps2_usb_rev2_unimap | TARGET = ps2_usb_rev2_unimap | ||||
UNIMAP_ENABLE = yes | UNIMAP_ENABLE = yes | ||||
KEYMAP_SECTION_ENABLE = yes | KEYMAP_SECTION_ENABLE = yes | ||||
#LUFA_DEBUG_SUART = yes | |||||
include Makefile.rev2 | include Makefile.rev2 |
#define PS2_INT_VECT INT1_vect | #define PS2_INT_VECT INT1_vect | ||||
#endif | #endif | ||||
#ifdef LUFA_DEBUG_SUART | |||||
# define SUART_OUT_DDR DDRD | |||||
# define SUART_OUT_PORT PORTD | |||||
# define SUART_OUT_BIT 4 | |||||
# define SUART_IN_DDR DDRD | |||||
# define SUART_IN_PIN PIND | |||||
# define SUART_IN_BIT 4 | |||||
#endif | |||||
#endif | #endif |
#include "util.h" | #include "util.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
#include "ps2.h" | #include "ps2.h" | ||||
#include "host.h" | |||||
#include "led.h" | |||||
#include "matrix.h" | #include "matrix.h" | ||||
static void matrix_make(uint8_t code); | static void matrix_make(uint8_t code); | ||||
static void matrix_break(uint8_t code); | static void matrix_break(uint8_t code); | ||||
static void matrix_clear(void); | |||||
#ifdef MATRIX_HAS_GHOST | |||||
static bool matrix_has_ghost_in_row(uint8_t row); | |||||
#endif | |||||
/* | /* | ||||
static bool is_modified = false; | static bool is_modified = false; | ||||
inline | |||||
uint8_t matrix_rows(void) | |||||
{ | |||||
return MATRIX_ROWS; | |||||
} | |||||
inline | |||||
uint8_t matrix_cols(void) | |||||
{ | |||||
return MATRIX_COLS; | |||||
} | |||||
void matrix_init(void) | void matrix_init(void) | ||||
{ | { | ||||
debug_enable = true; | debug_enable = true; | ||||
print("Overrun\n"); | print("Overrun\n"); | ||||
state = INIT; | state = INIT; | ||||
break; | break; | ||||
case 0xAA: // Self-test passed | |||||
case 0xFC: // Self-test failed | |||||
printf("BAT %s\n", (code == 0xAA) ? "OK" : "NG"); | |||||
led_set(host_keyboard_leds()); | |||||
state = INIT; | |||||
break; | |||||
default: // normal key make | default: // normal key make | ||||
if (code < 0x80) { | if (code < 0x80) { | ||||
matrix_make(code); | matrix_make(code); | ||||
return 1; | return 1; | ||||
} | } | ||||
bool matrix_is_modified(void) | |||||
{ | |||||
return is_modified; | |||||
} | |||||
inline | |||||
bool matrix_has_ghost(void) | |||||
{ | |||||
#ifdef MATRIX_HAS_GHOST | |||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | |||||
if (matrix_has_ghost_in_row(i)) | |||||
return true; | |||||
} | |||||
#endif | |||||
return false; | |||||
} | |||||
inline | inline | ||||
bool matrix_is_on(uint8_t row, uint8_t col) | bool matrix_is_on(uint8_t row, uint8_t col) | ||||
{ | { | ||||
return matrix[row]; | return matrix[row]; | ||||
} | } | ||||
void matrix_print(void) | |||||
{ | |||||
print("\nr/c 01234567\n"); | |||||
for (uint8_t row = 0; row < matrix_rows(); row++) { | |||||
phex(row); print(": "); | |||||
pbin_reverse(matrix_get_row(row)); | |||||
#ifdef MATRIX_HAS_GHOST | |||||
if (matrix_has_ghost_in_row(row)) { | |||||
print(" <ghost"); | |||||
} | |||||
#endif | |||||
print("\n"); | |||||
} | |||||
} | |||||
uint8_t matrix_key_count(void) | uint8_t matrix_key_count(void) | ||||
{ | { | ||||
uint8_t count = 0; | uint8_t count = 0; | ||||
return count; | return count; | ||||
} | } | ||||
#ifdef MATRIX_HAS_GHOST | |||||
inline | |||||
static bool matrix_has_ghost_in_row(uint8_t row) | |||||
{ | |||||
// no ghost exists in case less than 2 keys on | |||||
if (((matrix[row] - 1) & matrix[row]) == 0) | |||||
return false; | |||||
// ghost exists in case same state as other row | |||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) { | |||||
if (i != row && (matrix[i] & matrix[row]) == matrix[row]) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
#endif | |||||
inline | inline | ||||
static void matrix_make(uint8_t code) | static void matrix_make(uint8_t code) | ||||
} | } | ||||
} | } | ||||
inline | |||||
static void matrix_clear(void) | |||||
void matrix_clear(void) | |||||
{ | { | ||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | ||||
} | } |
CONSOLE_ENABLE = yes # Console for debug(+400) | CONSOLE_ENABLE = yes # Console for debug(+400) | ||||
COMMAND_ENABLE = yes # Commands for debug and configuration | COMMAND_ENABLE = yes # Commands for debug and configuration | ||||
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | #SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | ||||
#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA | |||||
#NKRO_ENABLE = yes # USB Nkey Rollover | |||||
# | # |
CONSOLE_ENABLE = yes # Console for debug(+400) | CONSOLE_ENABLE = yes # Console for debug(+400) | ||||
COMMAND_ENABLE = yes # Commands for debug and configuration | COMMAND_ENABLE = yes # Commands for debug and configuration | ||||
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | #SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | ||||
#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA | |||||
#NKRO_ENABLE = yes # USB Nkey Rollover | |||||
EXTRAKEY_ENABLE = yes # Audio control and System control(+450) | EXTRAKEY_ENABLE = yes # Audio control and System control(+450) | ||||
CONSOLE_ENABLE = yes # Console for debug(+400) | CONSOLE_ENABLE = yes # Console for debug(+400) | ||||
COMMAND_ENABLE = yes # Commands for debug and configuration | COMMAND_ENABLE = yes # Commands for debug and configuration | ||||
NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA | |||||
NKRO_ENABLE = yes # USB Nkey Rollover | |||||
# XT/2 Options | # XT/2 Options |
static void matrix_make(uint8_t code); | static void matrix_make(uint8_t code); | ||||
static void matrix_break(uint8_t code); | static void matrix_break(uint8_t code); | ||||
static void matrix_clear(void); | |||||
#ifdef MATRIX_HAS_GHOST | #ifdef MATRIX_HAS_GHOST | ||||
static bool matrix_has_ghost_in_row(uint8_t row); | static bool matrix_has_ghost_in_row(uint8_t row); | ||||
#endif | #endif | ||||
} | } | ||||
} | } | ||||
inline | |||||
static void matrix_clear(void) | |||||
void matrix_clear(void) | |||||
{ | { | ||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | ||||
} | } |
CONSOLE_ENABLE = yes # Console for debug(+400) | CONSOLE_ENABLE = yes # Console for debug(+400) | ||||
COMMAND_ENABLE = yes # Commands for debug and configuration | COMMAND_ENABLE = yes # Commands for debug and configuration | ||||
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | #SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | ||||
#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA | |||||
#NKRO_ENABLE = yes # USB Nkey Rollover | |||||
#ACTIONMAP_ENABLE = yes # Use 16bit action codes in keymap instead of 8bit keycodes | #ACTIONMAP_ENABLE = yes # Use 16bit action codes in keymap instead of 8bit keycodes | ||||
CONSOLE_ENABLE = yes # Console for debug(+400) | CONSOLE_ENABLE = yes # Console for debug(+400) | ||||
COMMAND_ENABLE = yes # Commands for debug and configuration | COMMAND_ENABLE = yes # Commands for debug and configuration | ||||
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | #SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | ||||
NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA | |||||
NKRO_ENABLE = yes # USB Nkey Rollover | |||||
# Optimize size but this may cause error "relocation truncated to fit" | # Optimize size but this may cause error "relocation truncated to fit" |
CONSOLE_ENABLE = yes # Console for debug(+400) | CONSOLE_ENABLE = yes # Console for debug(+400) | ||||
#COMMAND_ENABLE = yes # Commands for debug and configuration | #COMMAND_ENABLE = yes # Commands for debug and configuration | ||||
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | #SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | ||||
#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA | |||||
#NKRO_ENABLE = yes # USB Nkey Rollover | |||||
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | #PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | ||||
#PS2_USE_BUSYWAIT = yes # uses primitive reference code | #PS2_USE_BUSYWAIT = yes # uses primitive reference code |
#include "keymap.h" | #include "keymap.h" | ||||
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||||
const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||||
{{KC_A}}, | {{KC_A}}, | ||||
}; | }; | ||||
/* | /* | ||||
* Fn action definition | * Fn action definition | ||||
*/ | */ | ||||
static const action_t PROGMEM fn_actions[] = { | |||||
const action_t PROGMEM fn_actions[] = { | |||||
}; | }; |
COMMON_DIR = common | COMMON_DIR = common | ||||
SRC += $(COMMON_DIR)/host.c \ | SRC += $(COMMON_DIR)/host.c \ | ||||
$(COMMON_DIR)/keyboard.c \ | $(COMMON_DIR)/keyboard.c \ | ||||
$(COMMON_DIR)/matrix.c \ | |||||
$(COMMON_DIR)/action.c \ | $(COMMON_DIR)/action.c \ | ||||
$(COMMON_DIR)/action_tapping.c \ | $(COMMON_DIR)/action_tapping.c \ | ||||
$(COMMON_DIR)/action_macro.c \ | $(COMMON_DIR)/action_macro.c \ |
;---------------------------------------------------------------------------; | |||||
; Software implemented UART module ; | |||||
; (C)ChaN, 2005 (http://elm-chan.org/) ; | |||||
;---------------------------------------------------------------------------; | |||||
; Bit rate settings: | |||||
; | |||||
; 1MHz 2MHz 4MHz 6MHz 8MHz 10MHz 12MHz 16MHz 20MHz | |||||
; 2.4kbps 138 - - - - - - - - | |||||
; 4.8kbps 68 138 - - - - - - - | |||||
; 9.6kbps 33 68 138 208 - - - - - | |||||
; 19.2kbps - 33 68 102 138 173 208 - - | |||||
; 38.4kbps - - 33 50 68 85 102 138 172 | |||||
; 57.6kbps - - 21 33 44 56 68 91 114 | |||||
; 115.2kbps - - - - 21 27 33 44 56 | |||||
.nolist | |||||
#include <avr/io.h> | |||||
.list | |||||
#define BPS 44 /* Bit delay. (see above table) */ | |||||
#define BIDIR 0 /* 0:Separated Tx/Rx, 1:Shared Tx/Rx */ | |||||
#define OUT_1 sbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 1 */ | |||||
#define OUT_0 cbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 0 */ | |||||
#define SKIP_IN_1 sbis _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 1 */ | |||||
#define SKIP_IN_0 sbic _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 0 */ | |||||
#ifdef SPM_PAGESIZE | |||||
.macro _LPMI reg | |||||
lpm \reg, Z+ | |||||
.endm | |||||
.macro _MOVW dh,dl, sh,sl | |||||
movw \dl, \sl | |||||
.endm | |||||
#else | |||||
.macro _LPMI reg | |||||
lpm | |||||
mov \reg, r0 | |||||
adiw ZL, 1 | |||||
.endm | |||||
.macro _MOVW dh,dl, sh,sl | |||||
mov \dl, \sl | |||||
mov \dh, \sh | |||||
.endm | |||||
#endif | |||||
;---------------------------------------------------------------------------; | |||||
; Transmit a byte in serial format of N81 | |||||
; | |||||
;Prototype: void xmit (uint8_t data); | |||||
;Size: 16 words | |||||
.global xmit | |||||
.func xmit | |||||
xmit: | |||||
#if BIDIR | |||||
ldi r23, BPS-1 ;Pre-idle time for bidirectional data line | |||||
5: dec r23 ; | |||||
brne 5b ;/ | |||||
#endif | |||||
in r0, _SFR_IO_ADDR(SREG) ;Save flags | |||||
com r24 ;C = start bit | |||||
ldi r25, 10 ;Bit counter | |||||
cli ;Start critical section | |||||
1: ldi r23, BPS-1 ;----- Bit transferring loop | |||||
2: dec r23 ;Wait for a bit time | |||||
brne 2b ;/ | |||||
brcs 3f ;MISO = bit to be sent | |||||
OUT_1 ; | |||||
3: brcc 4f ; | |||||
OUT_0 ;/ | |||||
4: lsr r24 ;Get next bit into C | |||||
dec r25 ;All bits sent? | |||||
brne 1b ; no, coutinue | |||||
out _SFR_IO_ADDR(SREG), r0 ;End of critical section | |||||
ret | |||||
.endfunc | |||||
;---------------------------------------------------------------------------; | |||||
; Receive a byte | |||||
; | |||||
;Prototype: uint8_t rcvr (void); | |||||
;Size: 19 words | |||||
.global rcvr | |||||
.func rcvr | |||||
rcvr: | |||||
in r0, _SFR_IO_ADDR(SREG) ;Save flags | |||||
ldi r24, 0x80 ;Receiving shift reg | |||||
cli ;Start critical section | |||||
1: SKIP_IN_1 ;Wait for idle | |||||
rjmp 1b | |||||
2: SKIP_IN_0 ;Wait for start bit | |||||
rjmp 2b | |||||
ldi r25, BPS/2 ;Wait for half bit time | |||||
3: dec r25 | |||||
brne 3b | |||||
4: ldi r25, BPS ;----- Bit receiving loop | |||||
5: dec r25 ;Wait for a bit time | |||||
brne 5b ;/ | |||||
lsr r24 ;Next bit | |||||
SKIP_IN_0 ;Get a data bit into r24.7 | |||||
ori r24, 0x80 | |||||
brcc 4b ;All bits received? no, continue | |||||
out _SFR_IO_ADDR(SREG), r0 ;End of critical section | |||||
ret | |||||
.endfunc | |||||
; Not wait for start bit. This should be called after detecting start bit. | |||||
.global recv | |||||
.func recv | |||||
recv: | |||||
in r0, _SFR_IO_ADDR(SREG) ;Save flags | |||||
ldi r24, 0x80 ;Receiving shift reg | |||||
cli ;Start critical section | |||||
;1: SKIP_IN_1 ;Wait for idle | |||||
; rjmp 1b | |||||
;2: SKIP_IN_0 ;Wait for start bit | |||||
; rjmp 2b | |||||
ldi r25, BPS/2 ;Wait for half bit time | |||||
3: dec r25 | |||||
brne 3b | |||||
4: ldi r25, BPS ;----- Bit receiving loop | |||||
5: dec r25 ;Wait for a bit time | |||||
brne 5b ;/ | |||||
lsr r24 ;Next bit | |||||
SKIP_IN_0 ;Get a data bit into r24.7 | |||||
ori r24, 0x80 | |||||
brcc 4b ;All bits received? no, continue | |||||
ldi r25, BPS/2 ;Wait for half bit time | |||||
6: dec r25 | |||||
brne 6b | |||||
7: SKIP_IN_1 ;Wait for stop bit | |||||
rjmp 7b | |||||
out _SFR_IO_ADDR(SREG), r0 ;End of critical section | |||||
ret | |||||
.endfunc |
#ifndef SUART | |||||
#define SUART | |||||
void xmit(uint8_t); | |||||
uint8_t rcvr(void); | |||||
uint8_t recv(void); | |||||
#endif /* SUART */ |
) | ) | ||||
void suspend_idle(uint8_t time) | |||||
{ | |||||
cli(); | |||||
set_sleep_mode(SLEEP_MODE_IDLE); | |||||
sleep_enable(); | |||||
sei(); | |||||
sleep_cpu(); | |||||
sleep_disable(); | |||||
} | |||||
/* Power down MCU with watchdog timer | /* Power down MCU with watchdog timer | ||||
* wdto: watchdog timer timeout defined in <avr/wdt.h> | * wdto: watchdog timer timeout defined in <avr/wdt.h> | ||||
* WDTO_15MS | * WDTO_15MS | ||||
wdt_disable(); | wdt_disable(); | ||||
} | } | ||||
static void standby(void) | |||||
{ | |||||
set_sleep_mode(SLEEP_MODE_STANDBY); | |||||
sleep_enable(); | |||||
sei(); | |||||
sleep_cpu(); | |||||
sleep_disable(); | |||||
} | |||||
static void idle(void) | |||||
{ | |||||
set_sleep_mode(SLEEP_MODE_IDLE); | |||||
sleep_enable(); | |||||
sei(); | |||||
sleep_cpu(); | |||||
sleep_disable(); | |||||
} | |||||
void suspend_idle(uint8_t time) | |||||
{ | |||||
idle(); | |||||
} | |||||
void suspend_power_down(void) | void suspend_power_down(void) | ||||
{ | { | ||||
#ifdef SUSPEND_MODE_STANDBY | |||||
standby(); | |||||
#elif defined(SUSPEND_MODE_IDLE) | |||||
idle(); | |||||
#else | |||||
power_down(WDTO_15MS); | power_down(WDTO_15MS); | ||||
#endif | |||||
} | } | ||||
__attribute__ ((weak)) void matrix_power_up(void) {} | |||||
__attribute__ ((weak)) void matrix_power_down(void) {} | |||||
bool suspend_wakeup_condition(void) | bool suspend_wakeup_condition(void) | ||||
{ | { | ||||
matrix_power_up(); | matrix_power_up(); | ||||
void suspend_wakeup_init(void) | void suspend_wakeup_init(void) | ||||
{ | { | ||||
// clear keyboard state | // clear keyboard state | ||||
matrix_clear(); | |||||
clear_keyboard(); | clear_keyboard(); | ||||
#ifdef BACKLIGHT_ENABLE | #ifdef BACKLIGHT_ENABLE | ||||
backlight_init(); | backlight_init(); |
#endif | #endif | ||||
__attribute__ ((weak)) void matrix_setup(void) {} | |||||
void keyboard_setup(void) | void keyboard_setup(void) | ||||
{ | { | ||||
matrix_setup(); | matrix_setup(); |
/* | |||||
Copyright 2016 Jun Wako <[email protected]> | |||||
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 "print.h" | |||||
#include "matrix.h" | |||||
__attribute__ ((weak)) | |||||
uint8_t matrix_rows(void) | |||||
{ | |||||
return MATRIX_ROWS; | |||||
} | |||||
__attribute__ ((weak)) | |||||
uint8_t matrix_cols(void) | |||||
{ | |||||
return MATRIX_COLS; | |||||
} | |||||
__attribute__ ((weak)) | |||||
void matrix_clear(void) | |||||
{ | |||||
matrix_init(); | |||||
} | |||||
__attribute__ ((weak)) | |||||
void matrix_setup(void) {} | |||||
__attribute__ ((weak)) | |||||
bool matrix_is_on(uint8_t row, uint8_t col) | |||||
{ | |||||
return (matrix_get_row(row) & (1<<col)); | |||||
} | |||||
__attribute__ ((weak)) | |||||
void matrix_print(void) | |||||
{ | |||||
#if (MATRIX_COLS <= 8) | |||||
print("r/c 01234567\n"); | |||||
#elif (MATRIX_COLS <= 16) | |||||
print("r/c 0123456789ABCDEF\n"); | |||||
#elif (MATRIX_COLS <= 32) | |||||
print("r/c 0123456789ABCDEF0123456789ABCDEF\n"); | |||||
#endif | |||||
for (uint8_t row = 0; row < MATRIX_ROWS; row++) { | |||||
xprintf("%02X:", row); | |||||
#if (MATRIX_COLS <= 8) | |||||
print_bin_reverse8(matrix_get_row(row)); | |||||
#elif (MATRIX_COLS <= 16) | |||||
print_bin_reverse16(matrix_get_row(row)); | |||||
#elif (MATRIX_COLS <= 32) | |||||
print_bin_reverse32(matrix_get_row(row)); | |||||
#endif | |||||
#ifdef MATRIX_HAS_GHOST | |||||
if (matrix_has_ghost_in_row(row)) { | |||||
print(" <ghost"); | |||||
} | |||||
#endif | |||||
print("\n"); | |||||
} | |||||
} | |||||
#ifdef MATRIX_HAS_GHOST | |||||
__attribute__ ((weak)) | |||||
bool matrix_has_ghost_in_row(uint8_t row) | |||||
{ | |||||
matrix_row_t matrix_row = matrix_get_row(row); | |||||
// No ghost exists when less than 2 keys are down on the row | |||||
if (((matrix_row - 1) & matrix_row) == 0) | |||||
return false; | |||||
// Ghost occurs when the row shares column line with other row | |||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) { | |||||
if (i != row && (matrix_get_row(i) & matrix_row)) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
#endif | |||||
__attribute__ ((weak)) void matrix_power_up(void) {} | |||||
__attribute__ ((weak)) void matrix_power_down(void) {} |
matrix_row_t matrix_get_row(uint8_t row); | matrix_row_t matrix_get_row(uint8_t row); | ||||
/* print matrix for debug */ | /* print matrix for debug */ | ||||
void matrix_print(void); | void matrix_print(void); | ||||
/* clear matrix */ | |||||
void matrix_clear(void); | |||||
#ifdef MATRIX_HAS_GHOST | |||||
bool matrix_has_ghost_in_row(uint8_t row); | |||||
#endif | |||||
/* power control */ | /* power control */ | ||||
void matrix_power_up(void); | void matrix_power_up(void); |
# This indicates using LUFA stack | # This indicates using LUFA stack | ||||
OPT_DEFS += -DPROTOCOL_LUFA | OPT_DEFS += -DPROTOCOL_LUFA | ||||
ifeq (yes,$(strip $(LUFA_DEBUG_SUART))) | |||||
SRC += common/avr/suart.S | |||||
LUFA_OPTS += -DLUFA_DEBUG_SUART | |||||
endif |
/* | |||||
/* | |||||
* Copyright 2012 Jun Wako <[email protected]> | * Copyright 2012 Jun Wako <[email protected]> | ||||
* This file is based on: | * This file is based on: | ||||
* LUFA-120219/Demos/Device/Lowlevel/KeyboardMouse | * LUFA-120219/Demos/Device/Lowlevel/KeyboardMouse | ||||
#include "suspend.h" | #include "suspend.h" | ||||
#include "hook.h" | #include "hook.h" | ||||
#ifdef LUFA_DEBUG_SUART | |||||
#include "avr/suart.h" | |||||
#endif | |||||
#include "matrix.h" | |||||
#include "descriptor.h" | #include "descriptor.h" | ||||
#include "lufa.h" | #include "lufa.h" | ||||
//#define LUFA_DEBUG | |||||
uint8_t keyboard_idle = 0; | uint8_t keyboard_idle = 0; | ||||
/* 0: Boot Protocol, 1: Report Protocol(default) */ | /* 0: Boot Protocol, 1: Report Protocol(default) */ | ||||
uint8_t keyboard_protocol = 1; | uint8_t keyboard_protocol = 1; | ||||
{ | { | ||||
/* Create a temporary buffer to hold the read in report from the host */ | /* Create a temporary buffer to hold the read in report from the host */ | ||||
uint8_t ConsoleData[CONSOLE_EPSIZE]; | uint8_t ConsoleData[CONSOLE_EPSIZE]; | ||||
/* Read Console Report Data */ | /* Read Console Report Data */ | ||||
Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL); | Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL); | ||||
/* Process Console Report Data */ | /* Process Console Report Data */ | ||||
//ProcessConsoleHIDReport(ConsoleData); | //ProcessConsoleHIDReport(ConsoleData); | ||||
} | } | ||||
print("[D]"); | print("[D]"); | ||||
/* For battery powered device */ | /* For battery powered device */ | ||||
USB_IsInitialized = false; | USB_IsInitialized = false; | ||||
/* TODO: This doesn't work. After several plug in/outs can not be enumerated. | |||||
/* TODO: This doesn't work. After several plug in/outs can not be enumerated. | |||||
if (USB_IsInitialized) { | if (USB_IsInitialized) { | ||||
USB_Disable(); // Disable all interrupts | USB_Disable(); // Disable all interrupts | ||||
USB_Controller_Enable(); | USB_Controller_Enable(); | ||||
void EVENT_USB_Device_Reset(void) | void EVENT_USB_Device_Reset(void) | ||||
{ | { | ||||
#ifdef LUFA_DEBUG | |||||
print("[R]"); | print("[R]"); | ||||
#endif | |||||
} | } | ||||
void EVENT_USB_Device_Suspend() | void EVENT_USB_Device_Suspend() | ||||
{ | { | ||||
#ifdef LUFA_DEBUG | |||||
print("[S]"); | print("[S]"); | ||||
#endif | |||||
hook_usb_suspend_entry(); | hook_usb_suspend_entry(); | ||||
} | } | ||||
void EVENT_USB_Device_WakeUp() | void EVENT_USB_Device_WakeUp() | ||||
{ | { | ||||
#ifdef LUFA_DEBUG | |||||
print("[W]"); | print("[W]"); | ||||
#endif | |||||
hook_usb_wakeup(); | hook_usb_wakeup(); | ||||
} | } | ||||
*/ | */ | ||||
void EVENT_USB_Device_ConfigurationChanged(void) | void EVENT_USB_Device_ConfigurationChanged(void) | ||||
{ | { | ||||
#ifdef LUFA_DEBUG | |||||
print("[c]"); | |||||
#endif | |||||
bool ConfigSuccess = true; | bool ConfigSuccess = true; | ||||
/* Setup Keyboard HID Report Endpoints */ | /* Setup Keyboard HID Report Endpoints */ | ||||
/* Write the report data to the control endpoint */ | /* Write the report data to the control endpoint */ | ||||
Endpoint_Write_Control_Stream_LE(ReportData, ReportSize); | Endpoint_Write_Control_Stream_LE(ReportData, ReportSize); | ||||
Endpoint_ClearOUT(); | Endpoint_ClearOUT(); | ||||
#ifdef LUFA_DEBUG | |||||
xprintf("[r%d]", USB_ControlRequest.wIndex); | |||||
#endif | |||||
} | } | ||||
break; | break; | ||||
Endpoint_ClearOUT(); | Endpoint_ClearOUT(); | ||||
Endpoint_ClearStatusStage(); | Endpoint_ClearStatusStage(); | ||||
#ifdef LUFA_DEBUG | |||||
xprintf("[L%d]", USB_ControlRequest.wIndex); | |||||
#endif | |||||
break; | break; | ||||
} | } | ||||
Endpoint_Write_8(keyboard_protocol); | Endpoint_Write_8(keyboard_protocol); | ||||
Endpoint_ClearIN(); | Endpoint_ClearIN(); | ||||
Endpoint_ClearStatusStage(); | Endpoint_ClearStatusStage(); | ||||
#ifdef LUFA_DEBUG | |||||
print("[p]"); | |||||
#endif | |||||
} | } | ||||
} | } | ||||
keyboard_protocol = (USB_ControlRequest.wValue & 0xFF); | keyboard_protocol = (USB_ControlRequest.wValue & 0xFF); | ||||
clear_keyboard(); | clear_keyboard(); | ||||
#ifdef LUFA_DEBUG | |||||
print("[P]"); | |||||
#endif | |||||
} | } | ||||
} | } | ||||
Endpoint_ClearStatusStage(); | Endpoint_ClearStatusStage(); | ||||
keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8); | keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8); | ||||
#ifdef LUFA_DEBUG | |||||
xprintf("[I%d]%d", USB_ControlRequest.wIndex, (USB_ControlRequest.wValue & 0xFF00) >> 8); | |||||
#endif | |||||
} | } | ||||
break; | break; | ||||
Endpoint_Write_8(keyboard_idle); | Endpoint_Write_8(keyboard_idle); | ||||
Endpoint_ClearIN(); | Endpoint_ClearIN(); | ||||
Endpoint_ClearStatusStage(); | Endpoint_ClearStatusStage(); | ||||
#ifdef LUFA_DEBUG | |||||
print("[i]"); | |||||
#endif | |||||
} | } | ||||
break; | break; | ||||
} | } | ||||
/******************************************************************************* | /******************************************************************************* | ||||
* Host driver | |||||
* Host driver | |||||
******************************************************************************/ | ******************************************************************************/ | ||||
static uint8_t keyboard_leds(void) | static uint8_t keyboard_leds(void) | ||||
{ | { | ||||
#define SEND_TIMEOUT 5 | #define SEND_TIMEOUT 5 | ||||
int8_t sendchar(uint8_t c) | int8_t sendchar(uint8_t c) | ||||
{ | { | ||||
#ifdef LUFA_DEBUG_SUART | |||||
xmit(c); | |||||
#endif | |||||
// Not wait once timeouted. | // Not wait once timeouted. | ||||
// Because sendchar() is called so many times, waiting each call causes big lag. | // Because sendchar() is called so many times, waiting each call causes big lag. | ||||
static bool timeouted = false; | static bool timeouted = false; | ||||
#else | #else | ||||
int8_t sendchar(uint8_t c) | int8_t sendchar(uint8_t c) | ||||
{ | { | ||||
#ifdef LUFA_DEBUG_SUART | |||||
xmit(c); | |||||
#endif | |||||
return 0; | return 0; | ||||
} | } | ||||
#endif | #endif | ||||
// for Console_Task | // for Console_Task | ||||
USB_Device_EnableSOFEvents(); | USB_Device_EnableSOFEvents(); | ||||
print_set_sendchar(sendchar); | |||||
} | } | ||||
int main(void) __attribute__ ((weak)); | int main(void) __attribute__ ((weak)); | ||||
int main(void) | int main(void) | ||||
{ | { | ||||
setup_mcu(); | setup_mcu(); | ||||
#ifdef LUFA_DEBUG_SUART | |||||
SUART_OUT_DDR |= (1<<SUART_OUT_BIT); | |||||
SUART_OUT_PORT |= (1<<SUART_OUT_BIT); | |||||
#endif | |||||
print_set_sendchar(sendchar); | |||||
print("\r\ninit\n"); | |||||
hook_early_init(); | hook_early_init(); | ||||
keyboard_setup(); | keyboard_setup(); | ||||
setup_usb(); | setup_usb(); | ||||
hook_late_init(); | hook_late_init(); | ||||
while (1) { | while (1) { | ||||
while (USB_DeviceState == DEVICE_STATE_Suspended) { | while (USB_DeviceState == DEVICE_STATE_Suspended) { | ||||
#ifdef LUFA_DEBUG | |||||
print("[s]"); | print("[s]"); | ||||
#endif | |||||
hook_usb_suspend_loop(); | hook_usb_suspend_loop(); | ||||
} | } | ||||
__attribute__((weak)) | __attribute__((weak)) | ||||
void hook_late_init(void) {} | void hook_late_init(void) {} | ||||
static uint8_t _led_stats = 0; | |||||
__attribute__((weak)) | __attribute__((weak)) | ||||
void hook_usb_suspend_entry(void) | void hook_usb_suspend_entry(void) | ||||
{ | { | ||||
// Turn LED off to save power | |||||
// Set 0 with putting aside status before suspend and restore | |||||
// it after wakeup, then LED is updated at keyboard_task() in main loop | |||||
_led_stats = keyboard_led_stats; | |||||
keyboard_led_stats = 0; | |||||
led_set(keyboard_led_stats); | |||||
matrix_clear(); | |||||
clear_keyboard(); | |||||
#ifdef SLEEP_LED_ENABLE | #ifdef SLEEP_LED_ENABLE | ||||
sleep_led_enable(); | sleep_led_enable(); | ||||
#endif | #endif | ||||
{ | { | ||||
suspend_power_down(); | suspend_power_down(); | ||||
if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) { | if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) { | ||||
USB_Device_SendRemoteWakeup(); | |||||
USB_Device_SendRemoteWakeup(); | |||||
} | } | ||||
} | } | ||||
suspend_wakeup_init(); | suspend_wakeup_init(); | ||||
#ifdef SLEEP_LED_ENABLE | #ifdef SLEEP_LED_ENABLE | ||||
sleep_led_disable(); | sleep_led_disable(); | ||||
// NOTE: converters may not accept this | |||||
led_set(host_keyboard_leds()); | |||||
#endif | #endif | ||||
// Restore LED status | |||||
// BIOS/grub won't recognize/enumerate if led_set() takes long(around 40ms?) | |||||
// Converters fall into the case and miss wakeup event(timeout to reply?) in the end. | |||||
//led_set(host_keyboard_leds()); | |||||
// Instead, restore stats and update at keyboard_task() in main loop | |||||
keyboard_led_stats = _led_stats; | |||||
} | } |