Skip to content

Commit 3d18c5c

Browse files
committed
Use a single list of keypad scanners
1 parent 4655a71 commit 3d18c5c

File tree

7 files changed

+105
-131
lines changed

7 files changed

+105
-131
lines changed

py/circuitpy_mpconfig.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -533,9 +533,7 @@ extern const struct _mp_obj_module_t ipaddress_module;
533533
#if CIRCUITPY_KEYPAD
534534
extern const struct _mp_obj_module_t keypad_module;
535535
#define KEYPAD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_keypad), (mp_obj_t)&keypad_module },
536-
#define KEYPAD_ROOT_POINTERS \
537-
mp_obj_t keypad_keys_linked_list; \
538-
mp_obj_t keypad_keymatrix_linked_list;
536+
#define KEYPAD_ROOT_POINTERS mp_obj_t keypad_scanners_linked_list;
539537
#else
540538
#define KEYPAD_MODULE
541539
#define KEYPAD_ROOT_POINTERS

shared-module/keypad/KeyMatrix.c

Lines changed: 7 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,14 @@
2626

2727
#include "py/gc.h"
2828
#include "py/runtime.h"
29+
#include "shared-bindings/keypad/__init__.h"
2930
#include "shared-bindings/keypad/Event.h"
3031
#include "shared-bindings/keypad/KeyMatrix.h"
3132
#include "shared-bindings/digitalio/DigitalInOut.h"
3233
#include "shared-bindings/util.h"
3334
#include "supervisor/port.h"
34-
#include "supervisor/shared/lock.h"
3535
#include "supervisor/shared/tick.h"
3636

37-
static supervisor_lock_t keypad_keymatrix_linked_list_lock;
38-
3937
#define DEBOUNCE_TICKS (20)
4038

4139
// Top bit of 16-bit event indicates pressed or released. Rest is key_num.
@@ -75,12 +73,8 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint
7573
// Event queue is 16-bit values.
7674
ringbuf_alloc(&self->encoded_events, max_events * 2, false);
7775

78-
// Add self to the list of active Keys objects.
79-
80-
supervisor_acquire_lock(&keypad_keymatrix_linked_list_lock);
81-
self->next = MP_STATE_VM(keypad_keymatrix_linked_list);
82-
MP_STATE_VM(keypad_keymatrix_linked_list) = self;
83-
supervisor_release_lock(&keypad_keymatrix_linked_list_lock);
76+
// Add self to the list of active keypad scanners.
77+
keypad_register_scanner((keypad_scanner_obj_t *)self);
8478

8579
supervisor_enable_tick();
8680
}
@@ -90,6 +84,9 @@ void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) {
9084
return;
9185
}
9286

87+
// Remove self from the list of active keypad scanners first.
88+
keypad_deregister_scanner((keypad_scanner_obj_t *)self);
89+
9390
for (size_t row = 0; row < common_hal_keypad_keymatrix_num_rows(self); row++) {
9491
common_hal_digitalio_digitalinout_deinit(self->row_digitalinouts->items[row]);
9592
}
@@ -99,25 +96,6 @@ void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) {
9996
common_hal_digitalio_digitalinout_deinit(self->col_digitalinouts->items[col]);
10097
}
10198
self->col_digitalinouts = MP_ROM_NONE;
102-
103-
// Remove self from the list of active KeyMatrix objects.
104-
105-
supervisor_acquire_lock(&keypad_keymatrix_linked_list_lock);
106-
if (MP_STATE_VM(keypad_keymatrix_linked_list) == self) {
107-
// I'm at the front; splice myself out.
108-
MP_STATE_VM(keypad_keymatrix_linked_list) = self->next;
109-
} else {
110-
keypad_keymatrix_obj_t *current = MP_STATE_VM(keypad_keymatrix_linked_list);
111-
while (current) {
112-
if (current->next == self) {
113-
// Splice myself out.
114-
current->next = self->next;
115-
break;
116-
}
117-
current = current->next;
118-
}
119-
}
120-
supervisor_release_lock(&keypad_keymatrix_linked_list_lock);
12199
}
122100

123101
bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self) {
@@ -160,7 +138,7 @@ mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_u
160138
return row_col_to_key_num(self, row, col);
161139
}
162140

163-
static void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) {
141+
void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) {
164142
uint64_t now = port_get_raw_ticks(NULL);
165143
if (now - self->last_scan_ticks < DEBOUNCE_TICKS) {
166144
// Too soon. Wait longer to debounce.
@@ -201,28 +179,3 @@ static void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) {
201179
common_hal_digitalio_digitalinout_switch_to_input(self->row_digitalinouts->items[row], PULL_UP);
202180
}
203181
}
204-
205-
void keypad_keymatrix_tick(void) {
206-
// Fast path.
207-
if (!MP_STATE_VM(keypad_keymatrix_linked_list)) {
208-
return;
209-
}
210-
211-
if (supervisor_try_lock(&keypad_keymatrix_linked_list_lock)) {
212-
keypad_keymatrix_obj_t *keypad_keymatrix = MP_STATE_VM(keypad_keymatrix_linked_list);
213-
while (keypad_keymatrix) {
214-
keypad_keymatrix_scan(keypad_keymatrix);
215-
keypad_keymatrix = keypad_keymatrix->next;
216-
}
217-
supervisor_release_lock(&keypad_keymatrix_linked_list_lock);
218-
}
219-
}
220-
221-
void keypad_keymatrix_reset(void) {
222-
if (MP_STATE_VM(keypad_keymatrix_linked_list)) {
223-
supervisor_disable_tick();
224-
}
225-
226-
MP_STATE_VM(keypad_keys_linked_list) = NULL;
227-
keypad_keymatrix_linked_list_lock = false;
228-
}

shared-module/keypad/KeyMatrix.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,25 @@
2727
#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H
2828
#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H
2929

30-
#include "common-hal/digitalio/DigitalInOut.h"
31-
3230
#include "py/obj.h"
3331
#include "py/objtuple.h"
3432
#include "py/ringbuf.h"
3533

36-
typedef struct _keypad_keymatrix_obj_t {
34+
#include "common-hal/digitalio/DigitalInOut.h"
35+
#include "shared-module/keypad/__init__.h"
36+
37+
typedef struct {
3738
mp_obj_base_t base;
39+
// All scanners have a next field here, to keep a linked list of active scanners.
40+
keypad_scanner_obj_t *next;
3841
mp_obj_tuple_t *row_digitalinouts;
3942
mp_obj_tuple_t *col_digitalinouts;
4043
uint64_t last_scan_ticks;
4144
bool *previously_pressed;
4245
bool *currently_pressed;
4346
ringbuf_t encoded_events;
44-
// Keep a linked list of active KeyMatrix objects.
45-
struct _keypad_keymatrix_obj_t *next;
4647
} keypad_keymatrix_obj_t;
4748

48-
void keypad_keymatrix_tick(void);
49-
void keypad_keymatrix_reset(void);
49+
void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self);
5050

5151
#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H

shared-module/keypad/Keys.c

Lines changed: 7 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,13 @@
2626

2727
#include "py/gc.h"
2828
#include "py/runtime.h"
29+
#include "shared-bindings/keypad/__init__.h"
2930
#include "shared-bindings/keypad/Event.h"
3031
#include "shared-bindings/keypad/Keys.h"
3132
#include "shared-bindings/digitalio/DigitalInOut.h"
3233
#include "supervisor/port.h"
33-
#include "supervisor/shared/lock.h"
3434
#include "supervisor/shared/tick.h"
3535

36-
static supervisor_lock_t keypad_keys_linked_list_lock;
37-
3836
#define DEBOUNCE_TICKS (20)
3937

4038
// Top bit of 16-bit event indicates pressed or released. Rest is key_num.
@@ -64,12 +62,8 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin
6462
// Event queue is 16-bit values.
6563
ringbuf_alloc(&self->encoded_events, max_events * 2, false);
6664

67-
// Add self to the list of active Keys objects.
68-
69-
supervisor_acquire_lock(&keypad_keys_linked_list_lock);
70-
self->next = MP_STATE_VM(keypad_keys_linked_list);
71-
MP_STATE_VM(keypad_keys_linked_list) = self;
72-
supervisor_release_lock(&keypad_keys_linked_list_lock);
65+
// Add self to the list of active keypad scanners.
66+
keypad_register_scanner((keypad_scanner_obj_t *)self);
7367

7468
supervisor_enable_tick();
7569
}
@@ -79,29 +73,14 @@ void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self) {
7973
return;
8074
}
8175

76+
// Remove self from the list of active keypad scanners first.
77+
keypad_deregister_scanner((keypad_scanner_obj_t *)self);
78+
8279
for (size_t key = 0; key < common_hal_keypad_keys_num_keys(self); key++) {
8380
common_hal_digitalio_digitalinout_deinit(self->digitalinouts->items[key]);
8481
}
8582
self->digitalinouts = MP_ROM_NONE;
8683

87-
// Remove self from the list of active Keys objects.
88-
89-
supervisor_acquire_lock(&keypad_keys_linked_list_lock);
90-
if (MP_STATE_VM(keypad_keys_linked_list) == self) {
91-
// I'm at the front; splice myself out.
92-
MP_STATE_VM(keypad_keys_linked_list) = self->next;
93-
} else {
94-
keypad_keys_obj_t *current = MP_STATE_VM(keypad_keys_linked_list);
95-
while (current) {
96-
if (current->next == self) {
97-
// Splice myself out.
98-
current->next = self->next;
99-
break;
100-
}
101-
current = current->next;
102-
}
103-
}
104-
supervisor_release_lock(&keypad_keys_linked_list_lock);
10584
}
10685

10786
bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self) {
@@ -131,7 +110,7 @@ void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self) {
131110
ringbuf_clear(&self->encoded_events);
132111
}
133112

134-
static void keypad_keys_scan(keypad_keys_obj_t *self) {
113+
void keypad_keys_scan(keypad_keys_obj_t *self) {
135114
uint64_t now = port_get_raw_ticks(NULL);
136115
if (now - self->last_scan_ticks < DEBOUNCE_TICKS) {
137116
// Too soon. Wait longer to debounce.
@@ -160,28 +139,3 @@ static void keypad_keys_scan(keypad_keys_obj_t *self) {
160139
}
161140
}
162141
}
163-
164-
void keypad_keys_tick(void) {
165-
// Fast path.
166-
if (!MP_STATE_VM(keypad_keys_linked_list)) {
167-
return;
168-
}
169-
170-
if (supervisor_try_lock(&keypad_keys_linked_list_lock)) {
171-
keypad_keys_obj_t *keypad_keys = MP_STATE_VM(keypad_keys_linked_list);
172-
while (keypad_keys) {
173-
keypad_keys_scan(keypad_keys);
174-
keypad_keys = keypad_keys->next;
175-
}
176-
supervisor_release_lock(&keypad_keys_linked_list_lock);
177-
}
178-
}
179-
180-
void keypad_keys_reset(void) {
181-
if (MP_STATE_VM(keypad_keys_linked_list)) {
182-
supervisor_disable_tick();
183-
}
184-
185-
MP_STATE_VM(keypad_keys_linked_list) = NULL;
186-
keypad_keys_linked_list_lock = false;
187-
}

shared-module/keypad/Keys.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,25 @@
2727
#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H
2828
#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H
2929

30-
#include "common-hal/digitalio/DigitalInOut.h"
31-
3230
#include "py/obj.h"
3331
#include "py/objtuple.h"
3432
#include "py/ringbuf.h"
3533

36-
typedef struct _keypad_keys_obj_t {
34+
#include "common-hal/digitalio/DigitalInOut.h"
35+
#include "shared-module/keypad/__init__.h"
36+
37+
typedef struct {
3738
mp_obj_base_t base;
39+
// All scanners have a next field here, to keep a linked list of active scanners.
40+
keypad_scanner_obj_t *next;
3841
mp_obj_tuple_t *digitalinouts;
3942
uint64_t last_scan_ticks;
40-
bool value_when_pressed;
4143
bool *previously_pressed;
4244
bool *currently_pressed;
4345
ringbuf_t encoded_events;
44-
// Keep a linked list of active Keys objects.
45-
struct _keypad_keys_obj_t *next;
46+
bool value_when_pressed;
4647
} keypad_keys_obj_t;
4748

48-
void keypad_keys_tick(void);
49-
void keypad_keys_reset(void);
49+
void keypad_keys_scan(keypad_keys_obj_t *self);
5050

5151
#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H

shared-module/keypad/__init__.c

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,70 @@
2424
* THE SOFTWARE.
2525
*/
2626

27-
#include "shared-module/keypad/Keys.h"
28-
#include "shared-module/keypad/KeyMatrix.h"
27+
#include "shared-bindings/keypad/Keys.h"
28+
#include "shared-bindings/keypad/KeyMatrix.h"
29+
#include "supervisor/shared/lock.h"
30+
#include "supervisor/shared/tick.h"
31+
32+
static supervisor_lock_t keypad_scanners_linked_list_lock;
2933

3034
void keypad_tick(void) {
31-
keypad_keys_tick();
32-
keypad_keymatrix_tick();
35+
// Fast path. Return immediately if there are no scanners.
36+
if (!MP_STATE_VM(keypad_scanners_linked_list)) {
37+
return;
38+
}
39+
40+
// Skip scanning if someone else has the lock. Don't wait for the lock.
41+
if (supervisor_try_lock(&keypad_scanners_linked_list_lock)) {
42+
mp_obj_t scanner = MP_STATE_VM(keypad_scanners_linked_list);
43+
while (scanner) {
44+
if (mp_obj_is_type(scanner, &keypad_keys_type)) {
45+
keypad_keys_scan((keypad_keys_obj_t *)scanner);
46+
} else if (mp_obj_is_type(scanner, &keypad_keymatrix_type)) {
47+
keypad_keymatrix_scan((keypad_keymatrix_obj_t *)scanner);
48+
}
49+
50+
scanner = ((keypad_scanner_obj_t *)scanner)->next;
51+
}
52+
supervisor_release_lock(&keypad_scanners_linked_list_lock);
53+
}
3354
}
3455

3556
void keypad_reset(void) {
36-
keypad_keys_reset();
37-
keypad_keymatrix_reset();
57+
if (MP_STATE_VM(keypad_scanners_linked_list)) {
58+
supervisor_disable_tick();
59+
}
60+
61+
MP_STATE_VM(keypad_scanners_linked_list) = NULL;
62+
keypad_scanners_linked_list_lock = false;
63+
}
64+
65+
// Register a Keys, KeyMatrix, etc. that will be scanned in the background
66+
void keypad_register_scanner(keypad_scanner_obj_t *scanner) {
67+
supervisor_acquire_lock(&keypad_scanners_linked_list_lock);
68+
scanner->next = MP_STATE_VM(keypad_scanners_linked_list);
69+
MP_STATE_VM(keypad_scanners_linked_list) = scanner;
70+
supervisor_release_lock(&keypad_scanners_linked_list_lock);
71+
}
72+
73+
// Remove scanner from the list of active scanners.
74+
void keypad_deregister_scanner(keypad_scanner_obj_t *scanner) {
75+
supervisor_acquire_lock(&keypad_scanners_linked_list_lock);
76+
if (MP_STATE_VM(keypad_scanners_linked_list) == scanner) {
77+
// Scanner is at the front; splice it out.
78+
MP_STATE_VM(keypad_scanners_linked_list) = scanner->next;
79+
scanner->next = NULL;
80+
} else {
81+
keypad_scanner_obj_t *current = MP_STATE_VM(keypad_scanners_linked_list);
82+
while (current) {
83+
if (current->next == scanner) {
84+
// Splice myself out.
85+
current->next = scanner->next;
86+
scanner->next = NULL;
87+
break;
88+
}
89+
current = current->next;
90+
}
91+
}
92+
supervisor_release_lock(&keypad_scanners_linked_list_lock);
3893
}

shared-module/keypad/__init__.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,21 @@
2727
#ifndef SHARED_MODULE_KEYPAD_H
2828
#define SHARED_MODULE_KEYPAD_H
2929

30+
#include "py/obj.h"
31+
32+
// All scanners must have a next field immediately following base.
33+
// This is an ad hoc "superclass" struct for scanners, though they do
34+
// not actually have a superclass relationship.
35+
typedef struct _keypad_scanner_obj_t {
36+
mp_obj_base_t base;
37+
struct _keypad_scanner_obj_t *next;
38+
} keypad_scanner_obj_t;
39+
3040
void keypad_tick(void);
3141
void keypad_reset(void);
3242

43+
void keypad_register_scanner(keypad_scanner_obj_t *scanner);
44+
void keypad_deregister_scanner(keypad_scanner_obj_t *scanner);
45+
46+
3347
#endif // SHARED_MODULE_KEYPAD_H

0 commit comments

Comments
 (0)