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.tags/v1.9
#ifndef CONFIG_H | #ifndef CONFIG_H | ||||
#define CONFIG_H | #define CONFIG_H | ||||
/* controller configuration */ | |||||
#include "controller_teensy.h" | |||||
#define VENDOR_ID 0xFEED | #define VENDOR_ID 0xFEED | ||||
#define PRODUCT_ID 0xCAFE | #define PRODUCT_ID 0xCAFE | ||||
#define MANUFACTURER t.m.k. | #define MANUFACTURER t.m.k. | ||||
#define PRODUCT HHKB mod | #define PRODUCT HHKB mod | ||||
#define DESCRIPTION t.m.k. keyboard firmware for HHKB mod | #define DESCRIPTION t.m.k. keyboard firmware for HHKB mod | ||||
/* controller */ | |||||
#include "controller_teensy.h" | |||||
/* matrix size */ | /* matrix size */ | ||||
#define MATRIX_ROWS 8 | #define MATRIX_ROWS 8 | ||||
#define MATRIX_COLS 8 | #define MATRIX_COLS 8 | ||||
/* define if matrix has ghost */ | |||||
//#define MATRIX_HAS_GHOST | |||||
/* USB NKey Rollover */ | /* USB NKey Rollover */ | ||||
#ifdef USB_NKRO_ENABLE | #ifdef USB_NKRO_ENABLE |
#include "keymap_skel.h" | #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( \ | #define KEYMAP( \ | ||||
R3C1, R3C0, R0C0, R1C0, R1C1, R2C0, R2C1, R4C0, R4C1, R6C0, R6C1, R7C0, R7C1, R5C0, R5C1, \ | 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, \ | R3C2, R0C1, R0C2, R1C3, R1C2, R2C3, R2C2, R4C2, R4C3, R6C2, R6C3, R7C3, R7C2, R5C2, \ | ||||
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)])) | #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[] = { | 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] = { | static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||||
return KEYCODE(layer, row, 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)]); | return pgm_read_byte(&fn_layer[biton(fn_bits)]); | ||||
} | } | ||||
return pgm_read_byte(&fn_keycode[(biton(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) | bool keymap_is_special_mode(uint8_t fn_bits) | ||||
{ | { | ||||
return (usb_keyboard_mods == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI)); | return (usb_keyboard_mods == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI)); |
#include "util.h" | #include "util.h" | ||||
#include "matrix_skel.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) | // matrix is active low. (key on: 0/key off: 1) | ||||
// | // | ||||
// HHKB has no ghost and no bounce. | // HHKB has no ghost and no bounce. | ||||
#define KEY_PREV_ON (PORTE |= (1<<7)) | #define KEY_PREV_ON (PORTE |= (1<<7)) | ||||
#define KEY_PREV_OFF (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 | inline | ||||
int matrix_rows(void) | |||||
uint8_t matrix_rows(void) | |||||
{ | { | ||||
return MATRIX_ROWS; | return MATRIX_ROWS; | ||||
} | } | ||||
inline | inline | ||||
int matrix_cols(void) | |||||
uint8_t matrix_cols(void) | |||||
{ | { | ||||
return MATRIX_COLS; | return MATRIX_COLS; | ||||
} | } | ||||
// this must be called once before matrix_scan. | |||||
void matrix_init(void) | void matrix_init(void) | ||||
{ | { | ||||
// row & col output(PB0-6) | // row & col output(PB0-6) | ||||
PORTE = 0x40; | PORTE = 0x40; | ||||
// initialize matrix state: all keys off | // 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 = _matrix0; | ||||
matrix_prev = _matrix1; | matrix_prev = _matrix1; | ||||
} | } | ||||
int matrix_scan(void) | |||||
uint8_t matrix_scan(void) | |||||
{ | { | ||||
uint8_t *tmp; | uint8_t *tmp; | ||||
matrix_prev = matrix; | matrix_prev = matrix; | ||||
matrix = tmp; | 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); | KEY_SELELCT(row, col); | ||||
_delay_us(40); // from logic analyzer chart | _delay_us(40); // from logic analyzer chart | ||||
if (matrix_prev[row] & (1<<col)) { | if (matrix_prev[row] & (1<<col)) { | ||||
bool matrix_is_modified(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]) | if (matrix[i] != matrix_prev[i]) | ||||
return true; | return true; | ||||
} | } | ||||
inline | inline | ||||
bool matrix_has_ghost(void) | 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; | return false; | ||||
} | } | ||||
inline | inline | ||||
bool matrix_is_on(int row, int col) | |||||
bool matrix_is_on(uint8_t row, uint8_t col) | |||||
{ | { | ||||
return (matrix[row] & (1<<col)); | return (matrix[row] & (1<<col)); | ||||
} | } | ||||
inline | 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]; | return matrix[row]; | ||||
} | } | ||||
void matrix_print(void) | void matrix_print(void) | ||||
{ | { | ||||
#if (MATRIX_COLS <= 8) | |||||
print("\nr/c 01234567\n"); | 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(": "); | phex(row); print(": "); | ||||
#if (MATRIX_COLS <= 8) | |||||
pbin_reverse(matrix_get_row(row)); | 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"); | 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]); | count += bitpop(matrix[i]); | ||||
#else | |||||
count += bitpop16(matrix[i]); | |||||
#endif | |||||
} | } | ||||
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 |
#ifndef CONFIG_H | #ifndef CONFIG_H | ||||
#define CONFIG_H | #define CONFIG_H | ||||
/* controller configuration */ | |||||
#include "controller_teensy.h" | |||||
#define VENDOR_ID 0xFEED | #define VENDOR_ID 0xFEED | ||||
#define PRODUCT_ID 0xBEE0 | #define PRODUCT_ID 0xBEE0 | ||||
#define MANUFACTURER t.m.k. | #define MANUFACTURER t.m.k. | ||||
#define PRODUCT Macway mod | #define PRODUCT Macway mod | ||||
#define DESCRIPTION t.m.k. keyboard firmware for Macway mod | #define DESCRIPTION t.m.k. keyboard firmware for Macway mod | ||||
/* controller */ | |||||
#include "controller_teensy.h" | |||||
/* matrix size */ | /* matrix size */ | ||||
#define MATRIX_ROWS 9 | #define MATRIX_ROWS 9 | ||||
#define MATRIX_COLS 8 | #define MATRIX_COLS 8 | ||||
/* define if matrix has ghost */ | |||||
#define MATRIX_HAS_GHOST | |||||
/* USB NKey Rollover */ | /* USB NKey Rollover */ | ||||
#ifdef USB_NKRO_ENABLE | #ifdef USB_NKRO_ENABLE |
#include <stdint.h> | #include <stdint.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <avr/pgmspace.h> | #include <avr/pgmspace.h> | ||||
#include <avr/interrupt.h> | |||||
#include "usb_keyboard.h" | #include "usb_keyboard.h" | ||||
#include "usb_keycodes.h" | #include "usb_keycodes.h" | ||||
#include "print.h" | #include "print.h" | ||||
#include "keymap_skel.h" | #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( \ | #define KEYMAP( \ | ||||
R1C1, R1C0, R2C0, R3C0, R4C0, R4C1, R5C1, R5C0, R6C0, R7C0, R8C0, R8C1, R6C1, R0C2, \ | 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, \ | R1C2, R1C3, R2C3, R3C3, R4C3, R4C2, R5C2, R5C3, R6C3, R7C3, R8C3, R8C2, R6C2, \ | ||||
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)])) | #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[] = { | 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] = { | static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||||
return KEYCODE(layer, row, 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)]); | return pgm_read_byte(&fn_layer[biton(fn_bits)]); | ||||
} | } | ||||
return pgm_read_byte(&fn_keycode[(biton(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) | bool keymap_is_special_mode(uint8_t fn_bits) | ||||
{ | { | ||||
//return (usb_keyboard_mods == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI)); | //return (usb_keyboard_mods == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI)); |
#include "matrix_skel.h" | #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; | ||||
static uint8_t *matrix_prev; | static 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]; | ||||
#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); | static bool matrix_has_ghost_in_row(uint8_t row); | ||||
#endif | |||||
static uint8_t read_col(void); | static uint8_t read_col(void); | ||||
static void unselect_rows(void); | static void unselect_rows(void); | ||||
static void select_row(uint8_t row); | static void select_row(uint8_t row); | ||||
inline | inline | ||||
int matrix_rows(void) | |||||
uint8_t matrix_rows(void) | |||||
{ | { | ||||
return MATRIX_ROWS; | return MATRIX_ROWS; | ||||
} | } | ||||
inline | inline | ||||
int matrix_cols(void) | |||||
uint8_t matrix_cols(void) | |||||
{ | { | ||||
return MATRIX_COLS; | return MATRIX_COLS; | ||||
} | } | ||||
// this must be called once before matrix_scan. | |||||
void matrix_init(void) | void matrix_init(void) | ||||
{ | { | ||||
// initialize row and col | // initialize row and col | ||||
PORTB = 0xFF; | PORTB = 0xFF; | ||||
// initialize matrix state: all keys off | // 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 = _matrix0; | ||||
matrix_prev = _matrix1; | matrix_prev = _matrix1; | ||||
} | } | ||||
int matrix_scan(void) | |||||
uint8_t matrix_scan(void) | |||||
{ | { | ||||
uint8_t *tmp; | uint8_t *tmp; | ||||
matrix_prev = matrix; | matrix_prev = matrix; | ||||
matrix = tmp; | matrix = tmp; | ||||
for (int i = 0; i < MATRIX_ROWS; i++) { | |||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | |||||
unselect_rows(); | unselect_rows(); | ||||
select_row(i); | select_row(i); | ||||
_delay_us(30); // without this wait read unstable value. | _delay_us(30); // without this wait read unstable value. | ||||
bool matrix_is_modified(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]) | if (matrix[i] != matrix_prev[i]) | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
inline | |||||
bool matrix_has_ghost(void) | 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)) | if (matrix_has_ghost_in_row(i)) | ||||
return true; | return true; | ||||
} | } | ||||
#endif | |||||
return false; | return false; | ||||
} | } | ||||
inline | inline | ||||
bool matrix_is_on(int row, int col) | |||||
bool matrix_is_on(uint8_t row, uint8_t col) | |||||
{ | { | ||||
return (matrix[row] & (1<<col)); | return (matrix[row] & (1<<col)); | ||||
} | } | ||||
inline | 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]; | return matrix[row]; | ||||
} | } | ||||
void matrix_print(void) | void matrix_print(void) | ||||
{ | { | ||||
print("\nr/c 01234567\n"); | 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(": "); | phex(row); print(": "); | ||||
#if (MATRIX_COLS <= 8) | |||||
pbin_reverse(matrix_get_row(row)); | 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)) { | if (matrix_has_ghost_in_row(row)) { | ||||
print(" <ghost"); | print(" <ghost"); | ||||
} | } | ||||
#endif | |||||
print("\n"); | 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]); | count += bitpop(matrix[i]); | ||||
#else | |||||
count += bitpop16(matrix[i]); | |||||
#endif | |||||
} | } | ||||
return count; | return count; | ||||
} | } | ||||
#ifdef MATRIX_HAS_GHOST | |||||
inline | |||||
static bool matrix_has_ghost_in_row(uint8_t row) | static bool matrix_has_ghost_in_row(uint8_t row) | ||||
{ | { | ||||
// no ghost exists in case less than 2 keys on | // no ghost exists in case less than 2 keys on | ||||
return false; | return false; | ||||
// ghost exists in case same state as other row | // 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]) | if (i != row && (matrix[i] & matrix[row]) == matrix[row]) | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
#endif | |||||
inline | |||||
static uint8_t read_col(void) | static uint8_t read_col(void) | ||||
{ | { | ||||
return PINB; | return PINB; | ||||
} | } | ||||
inline | |||||
static void unselect_rows(void) | static void unselect_rows(void) | ||||
{ | { | ||||
// Hi-Z(DDR:0, PORT:0) to unselect | // Hi-Z(DDR:0, PORT:0) to unselect | ||||
PORTF &= ~0b11000000; | PORTF &= ~0b11000000; | ||||
} | } | ||||
inline | |||||
static void select_row(uint8_t row) | static void select_row(uint8_t row) | ||||
{ | { | ||||
// Output low(DDR:1, PORT:0) to select | // Output low(DDR:1, PORT:0) to select |
#include <stdbool.h> | #include <stdbool.h> | ||||
/* number of matrix rows */ | /* number of matrix rows */ | ||||
int matrix_rows(void); | |||||
uint8_t matrix_rows(void); | |||||
/* number of matrix columns */ | /* number of matrix columns */ | ||||
int matrix_cols(void); | |||||
uint8_t matrix_cols(void); | |||||
/* intialize matrix for scaning. should be called once. */ | /* intialize matrix for scaning. should be called once. */ | ||||
void matrix_init(void); | void matrix_init(void); | ||||
/* scan all key states on matrix */ | /* scan all key states on matrix */ | ||||
int matrix_scan(void); | |||||
uint8_t matrix_scan(void); | |||||
/* whether modified from previous scan. used after matrix_scan. */ | /* whether modified from previous scan. used after matrix_scan. */ | ||||
bool matrix_is_modified(void); | bool matrix_is_modified(void); | ||||
/* whether ghosting occur on matrix. */ | /* whether ghosting occur on matrix. */ | ||||
bool matrix_has_ghost(void); | bool matrix_has_ghost(void); | ||||
/* whether a swtich is on */ | /* 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 */ | /* 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 */ | /* count keys pressed */ | ||||
int matrix_key_count(void); | |||||
uint8_t matrix_key_count(void); | |||||
/* print matrix for debug */ | /* print matrix for debug */ | ||||
void matrix_print(void); | void matrix_print(void); | ||||