1 /*
2 * Copyright 2023 Google LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/device.h>
8 #include <zephyr/input/input.h>
9 #include <zephyr/input/input_kbd_matrix.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/util.h>
12 #include <zephyr/ztest.h>
13
14 #define TEST_KBD_SCAN_NODE DT_INST(0, test_kbd_scan)
15
16 /* test driver */
17
18 /* Mock data for every valid column. */
19 static struct {
20 kbd_row_t rows[3];
21 int col;
22 bool detect_mode;
23 } state;
24
test_drive_column(const struct device * dev,int col)25 static void test_drive_column(const struct device *dev, int col)
26 {
27 state.col = col;
28 }
29
test_read_row(const struct device * dev)30 static kbd_row_t test_read_row(const struct device *dev)
31 {
32 if (state.col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE ||
33 state.col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) {
34 return 0;
35 }
36
37 return state.rows[state.col];
38 }
39
test_set_detect_mode(const struct device * dev,bool enabled)40 static void test_set_detect_mode(const struct device *dev, bool enabled)
41 {
42 TC_PRINT("detect mode: enabled=%d\n", enabled);
43 state.detect_mode = enabled;
44 }
45
46 static const struct input_kbd_matrix_api test_api = {
47 .drive_column = test_drive_column,
48 .read_row = test_read_row,
49 .set_detect_mode = test_set_detect_mode,
50 };
51
52 INPUT_KBD_MATRIX_DT_DEFINE(TEST_KBD_SCAN_NODE);
53
54 static const struct input_kbd_matrix_common_config
55 test_cfg = INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(
56 TEST_KBD_SCAN_NODE, &test_api);
57
58 static struct input_kbd_matrix_common_data test_data;
59
60 DEVICE_DT_DEFINE(TEST_KBD_SCAN_NODE, input_kbd_matrix_common_init, NULL,
61 &test_data, &test_cfg,
62 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);
63
64 static const struct device *const test_dev = DEVICE_DT_GET(TEST_KBD_SCAN_NODE);
65
66 /* The test only supports a 3 column matrix */
67 BUILD_ASSERT(DT_PROP(TEST_KBD_SCAN_NODE, col_size) == 3);
68
69 /* support stuff */
70
71 static const struct device *column_hook_last_dev;
72 static int column_hook_last_col;
73
input_kbd_matrix_drive_column_hook(const struct device * dev,int col)74 void input_kbd_matrix_drive_column_hook(const struct device *dev, int col)
75 {
76 column_hook_last_dev = dev;
77 column_hook_last_col = col;
78 }
79
state_set_rows_by_column(kbd_row_t c0,kbd_row_t c1,kbd_row_t c2)80 static void state_set_rows_by_column(kbd_row_t c0, kbd_row_t c1, kbd_row_t c2)
81 {
82 memcpy(&state.rows, (kbd_row_t[]){c0, c1, c2}, sizeof(state.rows));
83 TC_PRINT("set state [%" PRIkbdrow " %" PRIkbdrow " %" PRIkbdrow "]\n", c0, c1, c2);
84 }
85
86 static struct {
87 int row;
88 int col;
89 int val;
90 int event_count;
91 } test_event_data;
92
93 static int last_checked_event_count;
94
95 #define assert_no_new_events() \
96 zassert_equal(last_checked_event_count, test_event_data.event_count);
97
98 #define assert_new_event(_row, _col, _val) { \
99 last_checked_event_count++; \
100 zassert_equal(last_checked_event_count, test_event_data.event_count); \
101 zassert_equal(_row, test_event_data.row); \
102 zassert_equal(_col, test_event_data.col); \
103 zassert_equal(_val, test_event_data.val); \
104 }
105
test_cb(struct input_event * evt,void * user_data)106 static void test_cb(struct input_event *evt, void *user_data)
107 {
108 static int row, col, val;
109
110 switch (evt->code) {
111 case INPUT_ABS_X:
112 col = evt->value;
113 break;
114 case INPUT_ABS_Y:
115 row = evt->value;
116 break;
117 case INPUT_BTN_TOUCH:
118 val = evt->value;
119 break;
120 }
121
122 if (evt->sync) {
123 test_event_data.row = row;
124 test_event_data.col = col;
125 test_event_data.val = val;
126 test_event_data.event_count++;
127 TC_PRINT("input event: count=%d row=%d col=%d val=%d\n",
128 test_event_data.event_count, row, col, val);
129 }
130 }
131 INPUT_CALLBACK_DEFINE(test_dev, test_cb, NULL);
132
133 #define WAIT_FOR_IDLE_TIMEOUT_US (5 * USEC_PER_SEC)
134
kbd_scan_wait_for_idle(void)135 static void kbd_scan_wait_for_idle(void)
136 {
137 bool to;
138
139 to = WAIT_FOR(state.detect_mode,
140 WAIT_FOR_IDLE_TIMEOUT_US,
141 k_sleep(K_MSEC(100)));
142
143 zassert_true(to, "timeout waiting for idle state");
144 }
145
146 /* actual tests */
147
148 /* no event before debounce time, event after */
ZTEST(kbd_scan,test_kbd_scan)149 ZTEST(kbd_scan, test_kbd_scan)
150 {
151 const struct input_kbd_matrix_common_config *cfg = test_dev->config;
152
153 input_kbd_matrix_poll_start(test_dev);
154
155 state_set_rows_by_column(0x00, BIT(2), 0x00);
156 k_sleep(K_USEC(cfg->debounce_down_us / 2));
157 assert_no_new_events();
158
159 k_sleep(K_USEC(cfg->debounce_down_us));
160 assert_new_event(2, 1, 1);
161
162 state_set_rows_by_column(0x00, 0x00, 0x00);
163 k_sleep(K_USEC(cfg->debounce_up_us / 2));
164 assert_no_new_events();
165
166 k_sleep(K_USEC(cfg->debounce_up_us));
167 assert_new_event(2, 1, 0);
168
169 kbd_scan_wait_for_idle();
170 assert_no_new_events();
171
172 zassert_equal(column_hook_last_dev, test_dev);
173 zassert_equal(column_hook_last_col, INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL);
174 }
175
176 /* no event for short glitches */
ZTEST(kbd_scan,test_kbd_scan_glitch)177 ZTEST(kbd_scan, test_kbd_scan_glitch)
178 {
179 const struct input_kbd_matrix_common_config *cfg = test_dev->config;
180
181 input_kbd_matrix_poll_start(test_dev);
182
183 state_set_rows_by_column(0x00, BIT(2), 0x00);
184 k_sleep(K_USEC(cfg->debounce_down_us / 2));
185 assert_no_new_events();
186
187 state_set_rows_by_column(0x00, 0x00, 0x00);
188 k_sleep(K_USEC(cfg->debounce_down_us));
189 assert_no_new_events();
190
191 kbd_scan_wait_for_idle();
192 assert_no_new_events();
193 }
194
195 /* very bouncy key delays events indefinitely */
ZTEST(kbd_scan,test_kbd_long_debounce)196 ZTEST(kbd_scan, test_kbd_long_debounce)
197 {
198 const struct input_kbd_matrix_common_config *cfg = test_dev->config;
199
200 input_kbd_matrix_poll_start(test_dev);
201
202 state_set_rows_by_column(0x00, BIT(2), 0x00);
203 k_sleep(K_USEC(cfg->debounce_down_us / 2));
204 assert_no_new_events();
205
206 for (int i = 0; i < 10; i++) {
207 state_set_rows_by_column(0x00, 0x00, 0x00);
208 k_sleep(K_USEC(cfg->debounce_down_us / 2));
209 assert_no_new_events();
210
211 state_set_rows_by_column(0x00, BIT(2), 0x00);
212 k_sleep(K_USEC(cfg->debounce_down_us / 2));
213 assert_no_new_events();
214 }
215
216 k_sleep(K_USEC(cfg->debounce_down_us));
217 assert_new_event(2, 1, 1);
218
219 state_set_rows_by_column(0x00, 0x00, 0x00);
220 k_sleep(K_USEC(cfg->debounce_up_us / 2));
221 assert_no_new_events();
222
223 for (int i = 0; i < 10; i++) {
224 state_set_rows_by_column(0x00, BIT(2), 0x00);
225 k_sleep(K_USEC(cfg->debounce_up_us / 2));
226 assert_no_new_events();
227
228 state_set_rows_by_column(0x00, 0x00, 0x00);
229 k_sleep(K_USEC(cfg->debounce_up_us / 2));
230 assert_no_new_events();
231 }
232
233 k_sleep(K_USEC(cfg->debounce_up_us));
234 assert_new_event(2, 1, 0);
235
236 kbd_scan_wait_for_idle();
237 assert_no_new_events();
238 }
239
240 /* ghosting keys should not produce any event */
ZTEST(kbd_scan,test_kbd_ghosting_check)241 ZTEST(kbd_scan, test_kbd_ghosting_check)
242 {
243 const struct input_kbd_matrix_common_config *cfg = test_dev->config;
244
245 if (cfg->ghostkey_check == false) {
246 ztest_test_skip();
247 return;
248 }
249
250 input_kbd_matrix_poll_start(test_dev);
251
252 state_set_rows_by_column(BIT(0), 0x00, 0x00);
253 k_sleep(K_USEC(cfg->debounce_down_us * 1.5));
254 assert_new_event(0, 0, 1);
255
256 state_set_rows_by_column(BIT(0), BIT(1), 0x00);
257 k_sleep(K_USEC(cfg->debounce_down_us * 1.5));
258 assert_new_event(1, 1, 1);
259
260 /* ghosting */
261 state_set_rows_by_column(BIT(0) | BIT(1), BIT(0) | BIT(1), 0x00);
262 k_sleep(K_USEC(cfg->debounce_down_us * 10));
263 assert_no_new_events();
264
265 /* back to not ghosting anymore */
266 state_set_rows_by_column(BIT(0), BIT(1), 0x00);
267 k_sleep(K_USEC(cfg->debounce_down_us * 10));
268 assert_no_new_events();
269
270 state_set_rows_by_column(0x00, BIT(1), 0x00);
271 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
272 assert_new_event(0, 0, 0);
273
274 state_set_rows_by_column(0x00, 0x00, 0x00);
275 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
276 assert_new_event(1, 1, 0);
277
278 kbd_scan_wait_for_idle();
279 assert_no_new_events();
280 }
281
282 /* ghosting keys can be disabled */
ZTEST(kbd_scan,test_kbd_no_ghosting_check)283 ZTEST(kbd_scan, test_kbd_no_ghosting_check)
284 {
285 const struct input_kbd_matrix_common_config *cfg = test_dev->config;
286
287 if (cfg->ghostkey_check == true) {
288 ztest_test_skip();
289 return;
290 }
291
292 input_kbd_matrix_poll_start(test_dev);
293
294 state_set_rows_by_column(BIT(0), 0x00, 0x00);
295 k_sleep(K_USEC(cfg->debounce_down_us * 1.5));
296 assert_new_event(0, 0, 1);
297
298 state_set_rows_by_column(BIT(0), BIT(1), 0x00);
299 k_sleep(K_USEC(cfg->debounce_down_us * 1.5));
300 assert_new_event(1, 1, 1);
301
302 state_set_rows_by_column(BIT(0) | BIT(1), BIT(1), 0x00);
303 k_sleep(K_USEC(cfg->debounce_down_us * 1.5));
304 assert_new_event(1, 0, 1);
305
306 state_set_rows_by_column(BIT(0) | BIT(1), BIT(0) | BIT(1), 0x00);
307 k_sleep(K_USEC(cfg->debounce_down_us * 1.5));
308 assert_new_event(0, 1, 1);
309
310 k_sleep(K_USEC(cfg->debounce_down_us * 10));
311 assert_no_new_events();
312
313 state_set_rows_by_column(BIT(1), BIT(0) | BIT(1), 0x00);
314 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
315 assert_new_event(0, 0, 0);
316
317 state_set_rows_by_column(BIT(1), BIT(0), 0x00);
318 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
319 assert_new_event(1, 1, 0);
320
321 state_set_rows_by_column(0x00, BIT(0), 0x00);
322 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
323 assert_new_event(1, 0, 0);
324
325 state_set_rows_by_column(0x00, 0x00, 0x00);
326 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
327 assert_new_event(0, 1, 0);
328
329 kbd_scan_wait_for_idle();
330 assert_no_new_events();
331 }
332
333 /* keymap is applied and can skip ghosting */
ZTEST(kbd_scan,test_kbd_actual_keymap)334 ZTEST(kbd_scan, test_kbd_actual_keymap)
335 {
336 const struct input_kbd_matrix_common_config *cfg = test_dev->config;
337
338 if (cfg->actual_key_mask == NULL) {
339 ztest_test_skip();
340 return;
341 }
342
343 input_kbd_matrix_poll_start(test_dev);
344
345 state_set_rows_by_column(BIT(0), 0x00, 0x00);
346 k_sleep(K_USEC(cfg->debounce_down_us * 1.5));
347 assert_new_event(0, 0, 1);
348
349 state_set_rows_by_column(BIT(0), 0x00, BIT(0));
350 k_sleep(K_USEC(cfg->debounce_down_us * 1.5));
351 assert_new_event(0, 2, 1);
352
353 /* ghosting cleared by the keymap */
354 state_set_rows_by_column(BIT(0) | BIT(2), 0x00, BIT(0) | BIT(2));
355 k_sleep(K_USEC(cfg->debounce_down_us * 1.5));
356 assert_new_event(2, 0, 1);
357
358 state_set_rows_by_column(BIT(0) | BIT(2), 0x00, BIT(2));
359 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
360 assert_new_event(0, 2, 0);
361
362 state_set_rows_by_column(BIT(2), 0x00, BIT(2));
363 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
364 assert_new_event(0, 0, 0);
365
366 state_set_rows_by_column(BIT(2), 0x00, 0x00);
367 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
368 assert_no_new_events();
369
370 state_set_rows_by_column(0x00, 0x00, 0x00);
371 k_sleep(K_USEC(cfg->debounce_up_us * 1.5));
372 assert_new_event(2, 0, 0);
373
374 kbd_scan_wait_for_idle();
375 assert_no_new_events();
376 }
377
ZTEST(kbd_scan,test_kbd_actual_key_map_set)378 ZTEST(kbd_scan, test_kbd_actual_key_map_set)
379 {
380 #if CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC
381 kbd_row_t mask[4] = {0x00, 0xff, 0x00, 0x00};
382 const struct input_kbd_matrix_common_config cfg = {
383 .row_size = 3,
384 .col_size = 4,
385 .actual_key_mask = mask,
386 };
387 const struct device fake_dev = {
388 .config = &cfg,
389 };
390 int ret;
391
392 ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 0, 0, true);
393 zassert_equal(ret, 0);
394 zassert_equal(mask[0], 0x01);
395
396 ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 2, 1, false);
397 zassert_equal(ret, 0);
398 zassert_equal(mask[1], 0xfb);
399
400 ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 2, 3, true);
401 zassert_equal(ret, 0);
402 zassert_equal(mask[3], 0x04);
403
404 ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 3, 0, true);
405 zassert_equal(ret, -EINVAL);
406
407 ret = input_kbd_matrix_actual_key_mask_set(&fake_dev, 0, 4, true);
408 zassert_equal(ret, -EINVAL);
409
410 zassert_equal(memcmp(mask, (uint8_t[]){0x01, 0xfb, 0x00, 0x04}, 4), 0);
411 #else
412 ztest_test_skip();
413 #endif
414 }
415
kbd_scan_setup(void)416 static void *kbd_scan_setup(void)
417 {
418 const struct input_kbd_matrix_common_config *cfg = test_dev->config;
419
420 TC_PRINT("actual kbd-matrix timing: poll_period_us=%d "
421 "debounce_down_us=%d debounce_up_us=%d\n",
422 cfg->poll_period_us,
423 cfg->debounce_down_us,
424 cfg->debounce_up_us);
425
426 return NULL;
427 }
428
kbd_scan_before(void * data)429 static void kbd_scan_before(void *data)
430 {
431 memset(&state, 0, sizeof(state));
432 state.detect_mode = true;
433
434 last_checked_event_count = 0;
435 memset(&test_event_data, 0, sizeof(test_event_data));
436 }
437
kbd_scan_after(void * data)438 static void kbd_scan_after(void *data)
439 {
440 /* Clear the test data so if a test fails early the testsuite does not
441 * hang indefinitely.
442 */
443 state_set_rows_by_column(0x00, 0x00, 0x00);
444 kbd_scan_wait_for_idle();
445 }
446
447 ZTEST_SUITE(kbd_scan, NULL, kbd_scan_setup, kbd_scan_before, kbd_scan_after, NULL);
448