unified_retro_keyboard/firmware/asdf/test/test_keypress_lib.c

506 lines
14 KiB
C

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "unity.h"
#include "asdf.h"
#include "asdf_arch.h"
#include "asdf_ascii.h"
#include "asdf_modifiers.h"
#include "asdf_keymaps.h"
#include "asdf_keymap_defs.h"
#include "asdf_buffer.h"
#include "asdf_repeat.h"
#define A 'a'
#define B 'b'
#define TEST_STRING "abcdefghijklmnop"
#define NUM_REPEATS (ASDF_KEYCODE_BUFFER_SIZE - 2)
#define TESTMAP(row, col, mapname, mapname2) \
do { \
asdf_keycode_t expected = mapname##_matrix[(row)][(col)]; \
asdf_keycode_t result = asdf_keymaps_get_code((row), (col), MOD_##mapname2##_MAP); \
TEST_ASSERT_EQUAL_INT(expected, result); \
} while (0);
#define TESTPLAIN(row, col, n) TESTMAP((row), (col), PLAIN, n)
#define TESTSHIFT(row, col, n) TESTMAP((row), (col), SHIFT, n)
#define TESTCAPS(row, col, n) TESTMAP((row), (col), CAPS, n)
#define TESTCTRL(row, col, n) TESTMAP((row), (col), CTRL, n)
const char test_string[] = TEST_STRING;
const asdf_keycode_t key_a = A;
const asdf_keycode_t key_b = B;
typedef struct {
int32_t row;
int32_t col;
} coord_t;
ASDF_TEST_DECLARATIONS;
static uint32_t key_matrix[ASDF_NUM_ROWS];
void setUp(void)
{
asdf_buffer_init();
asdf_init();
// initialize simulated key matrix
for (uint32_t i = 0; i < ASDF_NUM_ROWS; i++) {
key_matrix[i] = 0;
}
}
void tearDown(void) {}
coord_t *find_code(asdf_keycode_t code)
{
uint32_t done = 0;
static coord_t location = { .row = -1, .col = -1 };
for (uint32_t row = 0; !done && (row < ASDF_NUM_ROWS); row++) {
for (uint32_t col = 0; !done && (col < ASDF_NUM_COLS); col++) {
if (test_PLAIN_matrix[row][col] == code) {
done = 1;
location.row = row;
location.col = col;
}
}
}
return &location;
}
asdf_keycode_t shifted(asdf_keycode_t code)
<{
coord_t *location = find_code(code);
return test_SHIFT_matrix[location->row][location->col];
}
asdf_keycode_t caps(asdf_keycode_t code)
{
coord_t *xy = find_code(code);
return test_CAPS_matrix[xy->row][xy->col];
}
asdf_keycode_t ctrl(asdf_keycode_t code)
{
coord_t *xy = find_code(code);
return test_CTRL_matrix[xy->row][xy->col];
}
void keyscan_delay(int32_t ticks)
{
for (; ticks; ticks--) {
asdf_keyscan();
}
}
void press_no_debounce(asdf_keycode_t code)
{
coord_t *location = find_code(code);
key_matrix[location->row] |= (1 << location->col);
}
void release_no_debounce(asdf_keycode_t code)
{
coord_t *location = find_code(code);
key_matrix[location->row] &= ~(1 << location->col);
}
void press(asdf_keycode_t code)
{
press_no_debounce(code);
keyscan_delay(ASDF_DEBOUNCE_TIME_MS);
}
void release(asdf_keycode_t code)
{
release_no_debounce(code);
keyscan_delay(ASDF_DEBOUNCE_TIME_MS);
}
asdf_cols_t asdf_arch_read_row(uint8_t row)
{
return key_matrix[row];
}
// No repsonse to a keypress before it is debounced.
void pressing_a_gives_nothing_before_debounce(void)
{
press_no_debounce(key_a);
// no keypress after only ASDF_DEBOUNCE_TIME_MS -1 ticks (not yet debounced):
keyscan_delay(ASDF_DEBOUNCE_TIME_MS - 1);
TEST_ASSERT_EQUAL_INT32(ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing 'A' gives 'a'
void pressing_a_gives_a(void)
{
press_no_debounce(key_a);
// no keypress after only ASDF_DEBOUNCE_TIME_MS -1 ticks (not yet debounced):
keyscan_delay(ASDF_DEBOUNCE_TIME_MS - 1);
TEST_ASSERT_EQUAL_INT32(ASDF_INVALID_CODE, (int32_t) asdf_next_code());
// allow the key to finish debounce
keyscan_delay(1);
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (int32_t) asdf_next_code());
// no more codes in the buffer.
TEST_ASSERT_EQUAL_INT32(ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing SHIFT+A gives 'A'
void pressing_shift_a_gives_shifted_a(void)
{
press(ACTION_SHIFT);
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) shifted(key_a), (int32_t) asdf_next_code());
}
// pressing CAPS+A gives 'A'
void pressing_caps_a_gives_caps_a(void)
{
press(ACTION_CAPS);
release(ACTION_CAPS);
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) caps(key_a), (int32_t) asdf_next_code());
}
// pressing CTRL+A gives 0x01 (Ctrl-A)
void pressing_ctrl_a_gives_ctrl_a(void)
{
press(ACTION_CTRL);
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) ctrl(key_a), (int32_t) asdf_next_code());
}
// pressing REPT+A repeats 'a'
void pressing_rept_a_repeats_a(void)
{
press(ACTION_REPEAT);
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
for (int i = 0; i < NUM_REPEATS; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
}
// and verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing REPT+SHIFT+A repeats 'A'
void pressing_shift_rept_a_repeats_shifted_a(void)
{
press(ACTION_REPEAT);
press(ACTION_SHIFT);
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) shifted(key_a), (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
for (int i = 0; i < NUM_REPEATS; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) shifted(key_a), (uint32_t) asdf_next_code());
}
// and verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing REPT+CAPS+A repeats 'A'
void pressing_caps_rept_a_repeats_caps_a(void)
{
press(ACTION_REPEAT);
press(ACTION_CAPS);
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) caps(key_a), (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
for (int i = 0; i < NUM_REPEATS; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) caps(key_a), (uint32_t) asdf_next_code());
}
// and verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing REPT+CTRL+A repeats CTRL-A
void pressing_ctrl_rept_a_repeats_ctrl_a(void)
{
press(ACTION_REPEAT);
press(ACTION_CTRL);
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) ctrl(key_a), (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
for (int i = 0; i < NUM_REPEATS + 1; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) ctrl(key_a), (uint32_t) asdf_next_code());
}
// and verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing and holding 'A' autorepeats 'A'
void holding_a_autorepeats_a(void)
{
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(ASDF_AUTOREPEAT_TIME_MS);
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
// and verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing and holding 'A' autorepeats 'A'
void holding_a_autorepeats_slow_then_fast(void)
{
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(ASDF_AUTOREPEAT_TIME_MS);
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
for (int i = 0; i < NUM_REPEATS; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
}
// and verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing and holding 'A' and 'B' within less than debounce interval
// eventually returns 'A' then 'B'
void pressing_a_then_b_before_debounce_gives_a_then_b(void)
{
press_no_debounce(key_a);
// press B very quickly after a
keyscan_delay(1);
press(key_b);
// first get back A
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
// next get back B
TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code());
// and then verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing and holding a series of keys (up to buffer size) in rapid
// succession, allowing each key to debounce, before sending the next, sends all
// the keys in order. (n-key rollover)
void test_key_sequence_nkro(void)
{
for (int i = 0; i < (int32_t) strlen(test_string); i++) {
press((asdf_keycode_t) test_string[i]);
}
for (int i = 0; i < (int32_t) strlen(test_string); i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) test_string[i], (int32_t) asdf_next_code());
}
// and then verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// pressing and holding a series of keys (up to buffer size) in rapid succession
// without waiting for prior keys to debounce, eventually debounces and sends
// all the keys in order. (n-key rollover)
void test_key_sequence_nkro_simultaneous_debounce(void)
{
for (int i = 0; i < (int32_t) strlen(test_string); i++) {
press_no_debounce((asdf_keycode_t) test_string[i]);
keyscan_delay(1);
}
// several keys are already debounced, but now make sure they all are:
keyscan_delay(ASDF_DEBOUNCE_TIME_MS);
for (int i = 0; i < (int32_t) strlen(test_string); i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) test_string[i], (int32_t) asdf_next_code());
}
// and then verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// holding 'A' then pressing 'B' before autorepeat interval and holding 'B' gives 'A', then repeats
// 'B'
void holding_a_briefly_then_holding_b_gives_a_and_repeats_b(void)
{
press(key_a);
keyscan_delay(ASDF_AUTOREPEAT_TIME_MS / 2);
press(key_b);
// hold "a" and "b" for autorepeat delay:
keyscan_delay(ASDF_AUTOREPEAT_TIME_MS);
// hold "a" and "b" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
// should get "a" back, then "b"
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code());
// now get back NUM_REEPEATS repetitions of "b"
for (int i = 0; i < NUM_REPEATS; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code());
}
// and then verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// holding 'B' while repeating 'A' starts autorepeat delay, then starts repeating 'B'
void holding_a_then_holding_b_autorepeats_a_then_autorepeats_b(void)
{
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
// hold "a" for AUTOREPEAT delay
keyscan_delay(ASDF_AUTOREPEAT_TIME_MS);
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
// empty the buffer to make room for 'B'
for (int i = 0; i < NUM_REPEATS; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
}
// now press "b" while "a" is autorepeating:
press(key_b);
TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code());
// hold "a" for autorepeat delay
keyscan_delay(ASDF_AUTOREPEAT_TIME_MS);
TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
// empty the buffer to make room for 'B'
for (int i = 0; i < NUM_REPEATS; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code());
}
// and verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
// Pressing and holding 'A' then holding 'B' with repeat key held repeats 'A' then 'B'
void repeating_with_a_then_adding_b_repeats_a_then_repeats_b(void)
{
press(ACTION_REPEAT);
press(key_a);
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
// empty the buffer to make room for 'B'
for (int i = 0; i < NUM_REPEATS; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code());
}
// now press "b" while "a" is autorepeating:
press(key_b);
TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code());
// hold "a" for NUM_REPEATS repeat cycles:
keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS);
// empty the buffer to make room for 'B'
for (int i = 0; i < NUM_REPEATS; i++) {
TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code());
}
// and verify there are no more codes in buffer:
TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code());
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(pressing_a_gives_nothing_before_debounce);
RUN_TEST(pressing_a_gives_a);
RUN_TEST(pressing_shift_a_gives_shifted_a);
RUN_TEST(pressing_caps_a_gives_caps_a);
RUN_TEST(pressing_ctrl_a_gives_ctrl_a);
RUN_TEST(pressing_rept_a_repeats_a);
RUN_TEST(pressing_shift_rept_a_repeats_shifted_a);
RUN_TEST(pressing_caps_rept_a_repeats_caps_a);
RUN_TEST(holding_a_autorepeats_a);
RUN_TEST(holding_a_autorepeats_slow_then_fast);
RUN_TEST(pressing_a_then_b_before_debounce_gives_a_then_b);
RUN_TEST(test_key_sequence_nkro);
RUN_TEST(test_key_sequence_nkro_simultaneous_debounce);
RUN_TEST(holding_a_briefly_then_holding_b_gives_a_and_repeats_b);
RUN_TEST(holding_a_then_holding_b_autorepeats_a_then_autorepeats_b);
RUN_TEST(repeating_with_a_then_adding_b_repeats_a_then_repeats_b);
return UNITY_END();
}