aboutsummaryrefslogtreecommitdiffstats
path: root/src/keymat.c
blob: d1349e34291d86d5cb1312d3b444631accca4f29 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include "keymat.h"

#include "keymap.h"
#include "split.h"
#include "util.h"

#include "bsp/board.h"
#include "pico/types.h"
#include "hardware/gpio.h"
#include "hardware/timer.h"

#include <string.h>

#define DEBOUNCE_MS 50

#ifdef BAD_GPIO_MITIGATION
static const uint keymat_row_pins[] = { 4, 9, 6, 7 };
#else
static const uint keymat_row_pins[] = { 4, 5, 6, 7 };
#endif

static const uint keymat_col_pins[] = { 29, 28, 27, 26, 22, 20 };
static_assert(ARRLEN(keymat_row_pins) == KEY_ROWS_HALF);
static_assert(ARRLEN(keymat_col_pins) == KEY_COLS);

bool keymat_prev[KEY_ROWS][KEY_COLS];
bool keymat[KEY_ROWS][KEY_COLS];

static uint32_t keymat_modt[KEY_ROWS_HALF][KEY_COLS];

void
keymat_init(void)
{
	uint x, y;

	for (x = 0; x < KEY_COLS; x++) {
		gpio_init(keymat_col_pins[x]);
		gpio_set_dir(keymat_col_pins[x], GPIO_IN);
		gpio_set_drive_strength(keymat_col_pins[x], GPIO_DRIVE_STRENGTH_2MA);
		gpio_set_slew_rate(keymat_col_pins[x], GPIO_SLEW_RATE_FAST);
		gpio_pull_up(keymat_col_pins[x]);
	}

	for (y = 0; y < KEY_ROWS_HALF; y++) {
		gpio_init(keymat_row_pins[y]);
		gpio_set_dir(keymat_row_pins[y], GPIO_OUT);
		gpio_set_drive_strength(keymat_col_pins[x], GPIO_DRIVE_STRENGTH_2MA);
		gpio_set_slew_rate(keymat_row_pins[y], GPIO_SLEW_RATE_FAST);
		gpio_put(keymat_row_pins[y], 0);
	}
}

bool
keymat_scan(void)
{
	bool (*keymat_half)[KEY_COLS];
	bool state, modified;
	uint32_t now_ms;
	uint x, y;

	now_ms = board_millis();
	modified = false;

	memcpy(keymat_prev, keymat, sizeof(keymat));
	keymat_half = KEYMAT_HALF(keymat, SPLIT_SIDE);
	for (y = 0; y < KEY_ROWS_HALF; y++) {
		gpio_put(keymat_row_pins[y], 0);
		busy_wait_us(5);
		for (x = 0; x < KEY_COLS; x++) {
			if (keymat_modt[y][x] > now_ms - DEBOUNCE_MS)
				continue;
			state = !gpio_get(keymat_col_pins[x]);
			if (state != keymat_half[y][x]) {
				modified = true;
				keymat_half[y][x] = state;
				keymat_modt[y][x] = now_ms;
			}
		}
		gpio_put(keymat_row_pins[y], 1);
		busy_wait_us(5);
	}

	return modified;
}

uint32_t
keymat_encode_half(int side)
{
	bool (*keymat_half)[KEY_COLS];
	uint32_t mask;
	uint x, y;

	mask = 0;
	keymat_half = KEYMAT_HALF(keymat, side);
	for (y = 0; y < KEY_ROWS_HALF; y++) {
		for (x = 0; x < KEY_COLS; x++) {
			if (keymat_half[y][x])
				mask |= 1 << (y * KEY_COLS + x);
		}
	}

	return mask;
}

void
keymat_decode_half(int side, uint32_t mask)
{
	bool (*keymat_half)[KEY_COLS];
	uint x, y;

	keymat_half = KEYMAT_HALF(keymat, side);
	for (y = 0; y < KEY_ROWS_HALF; y++) {
		for (x = 0; x < KEY_COLS; x++) {
			keymat_half[y][x] = (mask >> (y * KEY_COLS + x)) & 1;
		}
	}
}

void
keymat_debug(void)
{
	uint x, y;

	if (log_level_min > LOG_DEBUG)
		return;

	for (y = 0; y < KEY_ROWS; y++) {
		for (x = 0; x < KEY_COLS; x++) {
			if (!keymat_prev[y][x] && keymat[y][x])
				DEBUG(LOG_KEYMAT, "Key pressed: %u %u", x, y);
			else if (keymat_prev[y][x] && !keymat[y][x])
				DEBUG(LOG_KEYMAT, "Key released: %u %u", x, y);
		}
	}
}