ADD: Build option: MATRIX_HAS_GHOST to enable ghost blocking logic. FIX: choose matrix buffer type(uint8_t/uint16_t) automatically depending on column size in matrix.c. FIX: use uint8_t insted of int in matrix.c.core
@@ -1,18 +1,20 @@ | |||
#ifndef CONFIG_H | |||
#define CONFIG_H | |||
/* controller configuration */ | |||
#include "controller_teensy.h" | |||
#define VENDOR_ID 0xFEED | |||
#define PRODUCT_ID 0xCAFE | |||
#define MANUFACTURER t.m.k. | |||
#define PRODUCT HHKB mod | |||
#define DESCRIPTION t.m.k. keyboard firmware for HHKB mod | |||
/* controller */ | |||
#include "controller_teensy.h" | |||
/* matrix size */ | |||
#define MATRIX_ROWS 8 | |||
#define MATRIX_COLS 8 | |||
/* define if matrix has ghost */ | |||
//#define MATRIX_HAS_GHOST | |||
/* USB NKey Rollover */ | |||
#ifdef USB_NKRO_ENABLE |
@@ -12,6 +12,8 @@ | |||
#include "keymap_skel.h" | |||
// Convert physical keyboard layout to matrix array. | |||
// This is a macro to define keymap easily in keyboard layout form. | |||
#define KEYMAP( \ | |||
R3C1, R3C0, R0C0, R1C0, R1C1, R2C0, R2C1, R4C0, R4C1, R6C0, R6C1, R7C0, R7C1, R5C0, R5C1, \ | |||
R3C2, R0C1, R0C2, R1C3, R1C2, R2C3, R2C2, R4C2, R4C3, R6C2, R6C3, R7C3, R7C2, R5C2, \ | |||
@@ -33,19 +35,29 @@ | |||
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)])) | |||
/* layer to change into while Fn key pressed */ | |||
static const int PROGMEM fn_layer[] = { 0, 1, 2, 3, 4, 0, 0, 1 }; | |||
// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed. | |||
static const uint8_t PROGMEM fn_layer[] = { | |||
0, // FN_0 | |||
1, // FN_1 | |||
2, // FN_2 | |||
3, // FN_3 | |||
4, // FN_4 | |||
0, // FN_5 | |||
0, // FN_6 | |||
1 // FN_7 | |||
}; | |||
/* keycode to sent when Fn key released without using layer keys. */ | |||
// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer. | |||
// See layer.c for details. | |||
static const uint8_t PROGMEM fn_keycode[] = { | |||
KB_NO, // FN_0 [NOT USED] | |||
KB_NO, // FN_1 layer 1 | |||
KB_SLSH, // FN_2 layer 2 | |||
KB_SCLN, // FN_3 layer 3 | |||
KB_SPC, // FN_4 layer 4 | |||
KB_NO, // FN_5 [NOT USED] | |||
KB_NO, // FN_6 [NOT USED] | |||
KB_NO // FN_7 layer 1 | |||
KB_NO, // FN_0 | |||
KB_NO, // FN_1 | |||
KB_SLSH, // FN_2 | |||
KB_SCLN, // FN_3 | |||
KB_SPC, // FN_4 | |||
KB_NO, // FN_5 | |||
KB_NO, // FN_6 | |||
KB_NO // FN_7 | |||
}; | |||
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
@@ -152,7 +164,7 @@ uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col) | |||
return KEYCODE(layer, row, col); | |||
} | |||
int keymap_fn_layer(uint8_t fn_bits) | |||
uint8_t keymap_fn_layer(uint8_t fn_bits) | |||
{ | |||
return pgm_read_byte(&fn_layer[biton(fn_bits)]); | |||
} | |||
@@ -162,6 +174,7 @@ uint8_t keymap_fn_keycode(uint8_t fn_bits) | |||
return pgm_read_byte(&fn_keycode[(biton(fn_bits))]); | |||
} | |||
// define a condition to enter special function mode | |||
bool keymap_is_special_mode(uint8_t fn_bits) | |||
{ | |||
return (usb_keyboard_mods == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI)); |
@@ -9,6 +9,33 @@ | |||
#include "util.h" | |||
#include "matrix_skel.h" | |||
#if (MATRIX_COLS > 16) | |||
# error "MATRIX_COLS must not exceed 16" | |||
#endif | |||
#if (MATRIX_ROWS > 255) | |||
# error "MATRIX_ROWS must not exceed 255" | |||
#endif | |||
// matrix state buffer(1:on, 0:off) | |||
#if (MATRIX_COLS <= 8) | |||
static uint8_t *matrix; | |||
static uint8_t *matrix_prev; | |||
static uint8_t _matrix0[MATRIX_ROWS]; | |||
static uint8_t _matrix1[MATRIX_ROWS]; | |||
#else | |||
static uint16_t *matrix; | |||
static uint16_t *matrix_prev; | |||
static uint16_t _matrix0[MATRIX_ROWS]; | |||
static uint16_t _matrix1[MATRIX_ROWS]; | |||
#endif | |||
#ifdef MATRIX_HAS_GHOST | |||
static bool matrix_has_ghost_in_row(uint8_t row); | |||
#endif | |||
// matrix is active low. (key on: 0/key off: 1) | |||
// | |||
// HHKB has no ghost and no bounce. | |||
@@ -28,26 +55,19 @@ | |||
#define KEY_PREV_ON (PORTE |= (1<<7)) | |||
#define KEY_PREV_OFF (PORTE &= ~(1<<7)) | |||
// matrix state buffer | |||
static uint8_t *matrix; | |||
static uint8_t *matrix_prev; | |||
static uint8_t _matrix0[MATRIX_ROWS]; | |||
static uint8_t _matrix1[MATRIX_ROWS]; | |||
inline | |||
int matrix_rows(void) | |||
uint8_t matrix_rows(void) | |||
{ | |||
return MATRIX_ROWS; | |||
} | |||
inline | |||
int matrix_cols(void) | |||
uint8_t matrix_cols(void) | |||
{ | |||
return MATRIX_COLS; | |||
} | |||
// this must be called once before matrix_scan. | |||
void matrix_init(void) | |||
{ | |||
// row & col output(PB0-6) | |||
@@ -59,13 +79,13 @@ void matrix_init(void) | |||
PORTE = 0x40; | |||
// initialize matrix state: all keys off | |||
for (int i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00; | |||
for (int i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00; | |||
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00; | |||
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00; | |||
matrix = _matrix0; | |||
matrix_prev = _matrix1; | |||
} | |||
int matrix_scan(void) | |||
uint8_t matrix_scan(void) | |||
{ | |||
uint8_t *tmp; | |||
@@ -73,8 +93,8 @@ int matrix_scan(void) | |||
matrix_prev = matrix; | |||
matrix = tmp; | |||
for (int row = 0; row < MATRIX_ROWS; row++) { | |||
for (int col = 0; col < MATRIX_COLS; col++) { | |||
for (uint8_t row = 0; row < MATRIX_ROWS; row++) { | |||
for (uint8_t col = 0; col < MATRIX_COLS; col++) { | |||
KEY_SELELCT(row, col); | |||
_delay_us(40); // from logic analyzer chart | |||
if (matrix_prev[row] & (1<<col)) { | |||
@@ -98,7 +118,7 @@ int matrix_scan(void) | |||
bool matrix_is_modified(void) | |||
{ | |||
for (int i = 0; i < MATRIX_ROWS; i++) { | |||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | |||
if (matrix[i] != matrix_prev[i]) | |||
return true; | |||
} | |||
@@ -108,36 +128,80 @@ bool matrix_is_modified(void) | |||
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 | |||
bool matrix_is_on(int row, int col) | |||
bool matrix_is_on(uint8_t row, uint8_t col) | |||
{ | |||
return (matrix[row] & (1<<col)); | |||
} | |||
inline | |||
uint16_t matrix_get_row(int row) | |||
#if (MATRIX_COLS <= 8) | |||
uint8_t matrix_get_row(uint8_t row) | |||
#else | |||
uint16_t matrix_get_row(uint8_t row) | |||
#endif | |||
{ | |||
return matrix[row]; | |||
} | |||
void matrix_print(void) | |||
{ | |||
#if (MATRIX_COLS <= 8) | |||
print("\nr/c 01234567\n"); | |||
for (int row = 0; row < matrix_rows(); row++) { | |||
#else | |||
print("\nr/c 0123456789ABCDEF\n"); | |||
#endif | |||
for (uint8_t row = 0; row < matrix_rows(); row++) { | |||
phex(row); print(": "); | |||
#if (MATRIX_COLS <= 8) | |||
pbin_reverse(matrix_get_row(row)); | |||
#else | |||
pbin_reverse16(matrix_get_row(row)); | |||
#endif | |||
#ifdef MATRIX_HAS_GHOST | |||
if (matrix_has_ghost_in_row(row)) { | |||
print(" <ghost"); | |||
} | |||
#endif | |||
print("\n"); | |||
} | |||
} | |||
int matrix_key_count(void) | |||
uint8_t matrix_key_count(void) | |||
{ | |||
int count = 0; | |||
for (int i = 0; i < MATRIX_ROWS; i++) { | |||
uint8_t count = 0; | |||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | |||
#if (MATRIX_COLS <= 8) | |||
count += bitpop(matrix[i]); | |||
#else | |||
count += bitpop16(matrix[i]); | |||
#endif | |||
} | |||
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 |
@@ -1,18 +1,20 @@ | |||
#ifndef CONFIG_H | |||
#define CONFIG_H | |||
/* controller configuration */ | |||
#include "controller_teensy.h" | |||
#define VENDOR_ID 0xFEED | |||
#define PRODUCT_ID 0xBEE0 | |||
#define MANUFACTURER t.m.k. | |||
#define PRODUCT Macway mod | |||
#define DESCRIPTION t.m.k. keyboard firmware for Macway mod | |||
/* controller */ | |||
#include "controller_teensy.h" | |||
/* matrix size */ | |||
#define MATRIX_ROWS 9 | |||
#define MATRIX_COLS 8 | |||
/* define if matrix has ghost */ | |||
#define MATRIX_HAS_GHOST | |||
/* USB NKey Rollover */ | |||
#ifdef USB_NKRO_ENABLE |
@@ -4,7 +4,6 @@ | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#include <avr/pgmspace.h> | |||
#include <avr/interrupt.h> | |||
#include "usb_keyboard.h" | |||
#include "usb_keycodes.h" | |||
#include "print.h" | |||
@@ -13,6 +12,8 @@ | |||
#include "keymap_skel.h" | |||
// Convert physical keyboard layout to matrix array. | |||
// This is a macro to define keymap easily in keyboard layout form. | |||
#define KEYMAP( \ | |||
R1C1, R1C0, R2C0, R3C0, R4C0, R4C1, R5C1, R5C0, R6C0, R7C0, R8C0, R8C1, R6C1, R0C2, \ | |||
R1C2, R1C3, R2C3, R3C3, R4C3, R4C2, R5C2, R5C3, R6C3, R7C3, R8C3, R8C2, R6C2, \ | |||
@@ -34,17 +35,29 @@ | |||
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)])) | |||
static const uint8_t PROGMEM fn_layer[] = { 0, 1, 2, 3, 4, 0, 2, 3 }; | |||
// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed. | |||
static const uint8_t PROGMEM fn_layer[] = { | |||
0, // FN_0 | |||
1, // FN_1 | |||
2, // FN_2 | |||
3, // FN_3 | |||
4, // FN_4 | |||
0, // FN_5 | |||
2, // FN_6 | |||
3 // FN_7 | |||
}; | |||
// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer. | |||
// See layer.c for details. | |||
static const uint8_t PROGMEM fn_keycode[] = { | |||
KB_NO, // FN_0 [NOT USED] | |||
KB_NO, // FN_1 layer 1 | |||
KB_SLSH, // FN_2 layer 2 | |||
KB_SCLN, // FN_3 layer 3 | |||
KB_SPC, // FN_4 layer 4 | |||
KB_NO, // FN_5 [NOT USED] | |||
KB_NO, // FN_6 layer 2 | |||
KB_NO // FN_7 layer 3 | |||
KB_NO, // FN_0 | |||
KB_NO, // FN_1 | |||
KB_SLSH, // FN_2 | |||
KB_SCLN, // FN_3 | |||
KB_SPC, // FN_4 | |||
KB_NO, // FN_5 | |||
KB_NO, // FN_6 | |||
KB_NO // FN_7 | |||
}; | |||
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
@@ -155,7 +168,7 @@ uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col) | |||
return KEYCODE(layer, row, col); | |||
} | |||
int keymap_fn_layer(uint8_t fn_bits) | |||
uint8_t keymap_fn_layer(uint8_t fn_bits) | |||
{ | |||
return pgm_read_byte(&fn_layer[biton(fn_bits)]); | |||
} | |||
@@ -165,6 +178,7 @@ uint8_t keymap_fn_keycode(uint8_t fn_bits) | |||
return pgm_read_byte(&fn_keycode[(biton(fn_bits))]); | |||
} | |||
// define a condition to enter special function mode | |||
bool keymap_is_special_mode(uint8_t fn_bits) | |||
{ | |||
//return (usb_keyboard_mods == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI)); |
@@ -10,31 +10,47 @@ | |||
#include "matrix_skel.h" | |||
// matrix state buffer (key on: 1/key off: 0) | |||
#if (MATRIX_COLS > 16) | |||
# error "MATRIX_COLS must not exceed 16" | |||
#endif | |||
#if (MATRIX_ROWS > 255) | |||
# error "MATRIX_ROWS must not exceed 255" | |||
#endif | |||
// matrix state buffer(1:on, 0:off) | |||
#if (MATRIX_COLS <= 8) | |||
static uint8_t *matrix; | |||
static uint8_t *matrix_prev; | |||
static uint8_t _matrix0[MATRIX_ROWS]; | |||
static uint8_t _matrix1[MATRIX_ROWS]; | |||
#else | |||
static uint16_t *matrix; | |||
static uint16_t *matrix_prev; | |||
static uint16_t _matrix0[MATRIX_ROWS]; | |||
static uint16_t _matrix1[MATRIX_ROWS]; | |||
#endif | |||
#ifdef MATRIX_HAS_GHOST | |||
static bool matrix_has_ghost_in_row(uint8_t row); | |||
#endif | |||
static uint8_t read_col(void); | |||
static void unselect_rows(void); | |||
static void select_row(uint8_t row); | |||
inline | |||
int matrix_rows(void) | |||
uint8_t matrix_rows(void) | |||
{ | |||
return MATRIX_ROWS; | |||
} | |||
inline | |||
int matrix_cols(void) | |||
uint8_t matrix_cols(void) | |||
{ | |||
return MATRIX_COLS; | |||
} | |||
// this must be called once before matrix_scan. | |||
void matrix_init(void) | |||
{ | |||
// initialize row and col | |||
@@ -44,13 +60,13 @@ void matrix_init(void) | |||
PORTB = 0xFF; | |||
// initialize matrix state: all keys off | |||
for (int i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00; | |||
for (int i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00; | |||
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00; | |||
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00; | |||
matrix = _matrix0; | |||
matrix_prev = _matrix1; | |||
} | |||
int matrix_scan(void) | |||
uint8_t matrix_scan(void) | |||
{ | |||
uint8_t *tmp; | |||
@@ -58,7 +74,7 @@ int matrix_scan(void) | |||
matrix_prev = matrix; | |||
matrix = tmp; | |||
for (int i = 0; i < MATRIX_ROWS; i++) { | |||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | |||
unselect_rows(); | |||
select_row(i); | |||
_delay_us(30); // without this wait read unstable value. | |||
@@ -70,30 +86,37 @@ int matrix_scan(void) | |||
bool matrix_is_modified(void) | |||
{ | |||
for (int i = 0; i < MATRIX_ROWS; i++) { | |||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | |||
if (matrix[i] != matrix_prev[i]) | |||
return true; | |||
} | |||
return false; | |||
} | |||
inline | |||
bool matrix_has_ghost(void) | |||
{ | |||
for (int i = 0; i < MATRIX_ROWS; i++) { | |||
#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 | |||
bool matrix_is_on(int row, int col) | |||
bool matrix_is_on(uint8_t row, uint8_t col) | |||
{ | |||
return (matrix[row] & (1<<col)); | |||
} | |||
inline | |||
uint16_t matrix_get_row(int row) | |||
#if (MATRIX_COLS <= 8) | |||
uint8_t matrix_get_row(uint8_t row) | |||
#else | |||
uint16_t matrix_get_row(uint8_t row) | |||
#endif | |||
{ | |||
return matrix[row]; | |||
} | |||
@@ -101,25 +124,37 @@ uint16_t matrix_get_row(int row) | |||
void matrix_print(void) | |||
{ | |||
print("\nr/c 01234567\n"); | |||
for (int row = 0; row < matrix_rows(); row++) { | |||
for (uint8_t row = 0; row < matrix_rows(); row++) { | |||
phex(row); print(": "); | |||
#if (MATRIX_COLS <= 8) | |||
pbin_reverse(matrix_get_row(row)); | |||
#else | |||
pbin_reverse16(matrix_get_row(row)); | |||
#endif | |||
#ifdef MATRIX_HAS_GHOST | |||
if (matrix_has_ghost_in_row(row)) { | |||
print(" <ghost"); | |||
} | |||
#endif | |||
print("\n"); | |||
} | |||
} | |||
int matrix_key_count(void) | |||
uint8_t matrix_key_count(void) | |||
{ | |||
int count = 0; | |||
for (int i = 0; i < MATRIX_ROWS; i++) { | |||
uint8_t count = 0; | |||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | |||
#if (MATRIX_COLS <= 8) | |||
count += bitpop(matrix[i]); | |||
#else | |||
count += bitpop16(matrix[i]); | |||
#endif | |||
} | |||
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 | |||
@@ -127,18 +162,21 @@ static bool matrix_has_ghost_in_row(uint8_t row) | |||
return false; | |||
// ghost exists in case same state as other row | |||
for (int i=0; i < MATRIX_ROWS; i++) { | |||
for (uint8_t i=0; i < MATRIX_ROWS; i++) { | |||
if (i != row && (matrix[i] & matrix[row]) == matrix[row]) | |||
return true; | |||
} | |||
return false; | |||
} | |||
#endif | |||
inline | |||
static uint8_t read_col(void) | |||
{ | |||
return PINB; | |||
} | |||
inline | |||
static void unselect_rows(void) | |||
{ | |||
// Hi-Z(DDR:0, PORT:0) to unselect | |||
@@ -150,6 +188,7 @@ static void unselect_rows(void) | |||
PORTF &= ~0b11000000; | |||
} | |||
inline | |||
static void select_row(uint8_t row) | |||
{ | |||
// Output low(DDR:1, PORT:0) to select |
@@ -4,23 +4,27 @@ | |||
#include <stdbool.h> | |||
/* number of matrix rows */ | |||
int matrix_rows(void); | |||
uint8_t matrix_rows(void); | |||
/* number of matrix columns */ | |||
int matrix_cols(void); | |||
uint8_t matrix_cols(void); | |||
/* intialize matrix for scaning. should be called once. */ | |||
void matrix_init(void); | |||
/* scan all key states on matrix */ | |||
int matrix_scan(void); | |||
uint8_t matrix_scan(void); | |||
/* whether modified from previous scan. used after matrix_scan. */ | |||
bool matrix_is_modified(void); | |||
/* whether ghosting occur on matrix. */ | |||
bool matrix_has_ghost(void); | |||
/* whether a swtich is on */ | |||
bool matrix_is_on(int row, int col); | |||
bool matrix_is_on(uint8_t row, uint8_t col); | |||
/* matrix state on row */ | |||
uint16_t matrix_get_row(int row); | |||
#if (MATRIX_COLS <= 8) | |||
uint8_t matrix_get_row(uint8_t row); | |||
#else | |||
uint16_t matrix_get_row(uint8_t row); | |||
#endif | |||
/* count keys pressed */ | |||
int matrix_key_count(void); | |||
uint8_t matrix_key_count(void); | |||
/* print matrix for debug */ | |||
void matrix_print(void); | |||