clean source | clean source | ||||
debouncing | debouncing | ||||
anti-ghost | anti-ghost | ||||
sleep&wakeup | |||||
boot keyboard support | |||||
mouse key | |||||
keymap layer | keymap layer | ||||
key combination switch | key combination switch | ||||
toggle siwtch | toggle siwtch | ||||
debug console | debug console | ||||
keymap setting | keymap setting | ||||
matrix display | matrix display | ||||
PS/2 keyboard mode | |||||
HHKB support | HHKB support | ||||
Trackpoint(PS/2) support | Trackpoint(PS/2) support | ||||
Thinkpad keyboard support | Thinkpad keyboard support |
#include "matrix.h" | #include "matrix.h" | ||||
#include "print.h" | #include "print.h" | ||||
// matrix is active low. (key on: 0/key off: 1) | |||||
// row: Hi-Z(unselected)/low output(selected) | |||||
// PD:0,1,2,3,6,7/PC:6,7/PF:7 | |||||
// col: input w/pullup | |||||
// PB:0-8 | |||||
// matrix state buffer | |||||
uint8_t *matrix; | uint8_t *matrix; | ||||
uint8_t *prev_matrix; | |||||
uint8_t *matrix_prev; | |||||
static uint8_t _matrix0[MATRIX_ROWS]; | static uint8_t _matrix0[MATRIX_ROWS]; | ||||
static uint8_t _matrix1[MATRIX_ROWS]; | static uint8_t _matrix1[MATRIX_ROWS]; | ||||
static uint8_t read_col(void); | static uint8_t read_col(void); | ||||
static void unselect_rows(void); | |||||
static void select_row(uint8_t row); | static void select_row(uint8_t row); | ||||
// this must be called once before matrix_scan. | |||||
void matrix_init(void) | void matrix_init(void) | ||||
{ | { | ||||
// Column: input w/pullup | |||||
// initialize row and col | |||||
unselect_rows(); | |||||
DDRB = 0x00; | DDRB = 0x00; | ||||
PORTB = 0xFF; | PORTB = 0xFF; | ||||
// Row: Hi-Z(unselected) | |||||
// PD:0,1,2,3,6,7 | |||||
// PC:6,7 | |||||
// PF:7 | |||||
DDRD = 0x00; | |||||
PORTD = 0x00; | |||||
DDRC = 0x00; | |||||
PORTC = 0x00; | |||||
DDRF = 0x00; | |||||
PORTF = 0x00; | |||||
for (int i=0; i < MATRIX_ROWS; i++) { | |||||
_matrix0[i] = 0xFF; | |||||
_matrix1[i] = 0xFF; | |||||
} | |||||
// initialize matrix state: all keys off | |||||
for (int i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0xFF; | |||||
for (int i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0xFF; | |||||
matrix = _matrix0; | matrix = _matrix0; | ||||
prev_matrix = _matrix1; | |||||
matrix_prev = _matrix1; | |||||
} | } | ||||
uint8_t matrix_scan(void) | uint8_t matrix_scan(void) | ||||
uint8_t row, state; | uint8_t row, state; | ||||
uint8_t *tmp; | uint8_t *tmp; | ||||
tmp = prev_matrix; | |||||
prev_matrix = matrix; | |||||
tmp = matrix_prev; | |||||
matrix_prev = matrix; | |||||
matrix = tmp; | matrix = tmp; | ||||
for (row = 0; row < MATRIX_ROWS; row++) { | for (row = 0; row < MATRIX_ROWS; row++) { | ||||
select_row(row); | select_row(row); | ||||
_delay_us(30); // without this wait read unstable value. | _delay_us(30); // without this wait read unstable value. | ||||
state = read_col(); | state = read_col(); | ||||
unselect_rows(); | |||||
matrix[row] = state; | matrix[row] = state; | ||||
} | } | ||||
return 1; | return 1; | ||||
} | } | ||||
bool matrix_is_modified(void) { | |||||
for (int i=0; i <MATRIX_ROWS; i++) { | |||||
if (matrix[i] != matrix_prev[i]) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
bool matrix_has_ghost(void) { | |||||
for (int i=0; i <MATRIX_ROWS; i++) { | |||||
if (matrix_has_ghost_in_row(i)) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
bool matrix_has_ghost_in_row(uint8_t row) { | |||||
uint8_t state = ~matrix[row]; | |||||
// no ghost exists in case less than 2 keys on | |||||
if (((state - 1) & state) == 0) | |||||
return false; | |||||
// ghost exists in case same state as other row | |||||
for (int i=0; i < MATRIX_ROWS; i++) { | |||||
if (i == row) continue; | |||||
if ((~matrix[i] & state) == state) return true; | |||||
} | |||||
return false; | |||||
} | |||||
static uint8_t read_col(void) | static uint8_t read_col(void) | ||||
{ | { | ||||
return PINB; | return PINB; | ||||
} | } | ||||
static void unselect_rows(void) { | |||||
DDRD = 0x00; | |||||
PORTD = 0x00; | |||||
DDRC = 0x00; | |||||
PORTC = 0x00; | |||||
DDRF = 0x00; | |||||
PORTF = 0x00; | |||||
} | |||||
static void select_row(uint8_t row) | static void select_row(uint8_t row) | ||||
{ | { | ||||
switch (row) { | switch (row) { |
#include <stdbool.h> | |||||
extern uint8_t *matrix; | extern uint8_t *matrix; | ||||
extern uint8_t *prev_matrix; | |||||
extern uint8_t *matrix_prev; | |||||
void matrix_init(void); | void matrix_init(void); | ||||
uint8_t matrix_scan(void); | uint8_t matrix_scan(void); | ||||
bool matrix_is_modified(void); | |||||
bool matrix_has_ghost(void); | |||||
bool matrix_has_ghost_in_row(uint8_t row); |
* THE SOFTWARE. | * THE SOFTWARE. | ||||
*/ | */ | ||||
#include <stdbool.h> | |||||
#include <avr/io.h> | #include <avr/io.h> | ||||
#include <avr/pgmspace.h> | #include <avr/pgmspace.h> | ||||
#include <avr/interrupt.h> | #include <avr/interrupt.h> | ||||
#include <util/delay.h> | #include <util/delay.h> | ||||
#include "usb_keyboard_debug.h" | #include "usb_keyboard_debug.h" | ||||
#include "print.h" | #include "print.h" | ||||
#include "matrix.h" | #include "matrix.h" | ||||
int main(void) | int main(void) | ||||
{ | { | ||||
uint8_t modified = 0; | |||||
bool modified = false; | |||||
bool has_ghost = false; | |||||
uint8_t key_index = 0; | uint8_t key_index = 0; | ||||
// set for 16 MHz clock | // set for 16 MHz clock | ||||
while (1) { | while (1) { | ||||
uint8_t row, col, code; | uint8_t row, col, code; | ||||
modified = 0; | |||||
matrix_scan(); | matrix_scan(); | ||||
keyboard_modifier_keys = 0; | |||||
for (int i = 0; i < 6; i++) | |||||
keyboard_keys[i] = KB_NO; | |||||
key_index = 0; | |||||
modified = matrix_is_modified(); | |||||
has_ghost = matrix_has_ghost(); | |||||
for (row = 0; row < MATRIX_ROWS; row++) { | |||||
if (matrix[row] != prev_matrix[row]) { | |||||
modified = 1; | |||||
} | |||||
// doesnt send keys during ghost occurs | |||||
if (modified && !has_ghost) { | |||||
key_index = 0; | |||||
keyboard_modifier_keys = 0; | |||||
for (int i = 0; i < 6; i++) keyboard_keys[i] = KB_NO; | |||||
for (col = 0; col < MATRIX_COLS; col++) { | |||||
if (matrix[row] & 1<<col) continue; | |||||
code = get_keycode(row, col); | |||||
// Modifier keycode: 0xE0-0xE7 | |||||
if (KB_LCTRL <= code && code <= KB_RGUI) { | |||||
keyboard_modifier_keys |= 1<<(code&0x07); | |||||
} else { | |||||
if (key_index < 6) { | |||||
keyboard_keys[key_index] = code; | |||||
for (row = 0; row < MATRIX_ROWS; row++) { | |||||
for (col = 0; col < MATRIX_COLS; col++) { | |||||
if (matrix[row] & 1<<col) continue; | |||||
code = get_keycode(row, col); | |||||
if (KB_LCTRL <= code && code <= KB_RGUI) { | |||||
// modifier keycode: 0xE0-0xE7 | |||||
keyboard_modifier_keys |= 1<<(code & 0x07); | |||||
} else { | |||||
if (key_index < 6) | |||||
keyboard_keys[key_index] = code; | |||||
key_index++; | |||||
} | } | ||||
key_index++; | |||||
} | } | ||||
} | |||||
if (key_index > 6) { | |||||
//Rollover | |||||
} | } | ||||
} | |||||
if (key_index > 6) { | |||||
//Rollover | |||||
} | |||||
usb_keyboard_send(); | |||||
// if any keypresses were detected, reset the idle counter | |||||
// variables shared with interrupt routines must be | |||||
// accessed carefully so the interrupt routine doesn't | |||||
// try to use the variable in the middle of our access | |||||
cli(); | |||||
idle_count = 0; | |||||
sei(); | |||||
} | |||||
// print matrix state for debug | |||||
if (modified) { | if (modified) { | ||||
print(" 01234567\n"); | |||||
print("r/c 01234567\n"); | |||||
for (row = 0; row < MATRIX_ROWS; row++) { | for (row = 0; row < MATRIX_ROWS; row++) { | ||||
phex(row); print(": "); pbin_reverse(matrix[row]); print("\n"); | |||||
phex(row); print(": "); | |||||
pbin_reverse(matrix[row]); | |||||
if (matrix_has_ghost_in_row(row)) { | |||||
print(" <ghost"); | |||||
} | |||||
print("\n"); | |||||
} | } | ||||
print("keys: "); | print("keys: "); | ||||
for (int i = 0; i < 6; i++) { phex(keyboard_keys[i]); print(" "); } | for (int i = 0; i < 6; i++) { phex(keyboard_keys[i]); print(" "); } | ||||
print("\n"); | print("\n"); | ||||
print("mod: "); phex(keyboard_modifier_keys); print("\n"); | print("mod: "); phex(keyboard_modifier_keys); print("\n"); | ||||
usb_keyboard_send(); | |||||
// variables shared with interrupt routines must be | |||||
// accessed carefully so the interrupt routine doesn't | |||||
// try to use the variable in the middle of our access | |||||
cli(); | |||||
idle_count = 0; | |||||
sei(); | |||||
} | } | ||||
// now the current pins will be the previous, and | // now the current pins will be the previous, and |