Merge pull request #4891 from dhalbert/keypad-scanning-events

keypad: support for vector and matrix key scanning
This commit is contained in:
Scott Shawcroft 2021-06-24 10:25:21 -07:00 committed by GitHub
commit b81573d439
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 2604 additions and 24 deletions

View File

@ -83,10 +83,22 @@ msgstr ""
msgid "%q indices must be integers, not %s"
msgstr ""
#: py/argcheck.c
msgid "%q length must be %q"
msgstr ""
#: shared-bindings/vectorio/Polygon.c
msgid "%q list must be a list"
msgstr ""
#: py/argcheck.c
msgid "%q must <= %d"
msgstr ""
#: py/argcheck.c
msgid "%q must be %d-%d"
msgstr ""
#: shared-bindings/usb_hid/Device.c
msgid "%q must be 0-255"
msgstr ""
@ -95,7 +107,11 @@ msgstr ""
msgid "%q must be 1-255"
msgstr ""
#: shared-bindings/memorymonitor/AllocationAlarm.c
#: py/argcheck.c
msgid "%q must be >= %d"
msgstr ""
#: py/argcheck.c shared-bindings/memorymonitor/AllocationAlarm.c
msgid "%q must be >= 0"
msgstr ""
@ -111,6 +127,10 @@ msgstr ""
msgid "%q must be None or between 1 and len(report_descriptor)-1"
msgstr ""
#: py/argcheck.c
msgid "%q must be a string"
msgstr ""
#: shared-module/vectorio/Polygon.c
msgid "%q must be a tuple of length 2"
msgstr ""
@ -119,6 +139,15 @@ msgstr ""
msgid "%q must be between %d and %d"
msgstr ""
#: py/argcheck.c
msgid "%q must of type %q"
msgstr ""
#: shared-bindings/keypad/KeyMatrix.c shared-bindings/keypad/Keys.c
#: shared-bindings/keypad/ShiftRegisterKeys.c
msgid "%q must store bytes"
msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#: shared-bindings/canio/Match.c
msgid "%q out of range"

10
main.c
View File

@ -86,6 +86,10 @@
#include "shared-module/displayio/__init__.h"
#endif
#if CIRCUITPY_KEYPAD
#include "shared-module/keypad/__init__.h"
#endif
#if CIRCUITPY_MEMORYMONITOR
#include "shared-module/memorymonitor/__init__.h"
#endif
@ -230,9 +234,11 @@ STATIC void cleanup_after_vm(supervisor_allocation* heap) {
#if CIRCUITPY_DISPLAYIO
reset_displays();
#endif
#if CIRCUITPY_MEMORYMONITOR
memorymonitor_reset();
#endif
filesystem_flush();
stop_mp();
free_memory(heap);
@ -242,6 +248,10 @@ STATIC void cleanup_after_vm(supervisor_allocation* heap) {
common_hal_canio_reset();
#endif
#if CIRCUITPY_KEYPAD
keypad_reset();
#endif
// reset_board_busses() first because it may release pins from the never_reset state, so that
// reset_port() can reset them.
#if CIRCUITPY_BOARD

View File

@ -14,6 +14,7 @@ LONGINT_IMPL = NONE
CIRCUITPY_BUSDEVICE = 1
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_KEYPAD = 0
# Include these Python libraries in firmware.
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_CircuitPlayground

View File

@ -11,6 +11,7 @@ EXTERNAL_FLASH_DEVICES = "S25FL216K, GD25Q16C"
# Turn off features and optimizations for displayio build to make room for additional frozen libs.
LONGINT_IMPL = NONE
CIRCUITPY_KEYPAD = 0
CIRCUITPY_PIXELBUF = 0
CIRCUITPY_ROTARYIO = 0
CIRCUITPY_RTC = 0

View File

@ -12,7 +12,6 @@ LONGINT_IMPL = NONE
# To keep the build small
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_GAMEPAD = 0
# Include these Python libraries in firmware.
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH

View File

@ -15,6 +15,7 @@ CIRCUITPY_AUDIOMP3 = 0
CIRCUITPY_BLEIO_HCI = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_MSGPACK = 0
CIRCUITPY_PS2IO = 0
CIRCUITPY_RGBMATRIX = 0

View File

@ -16,8 +16,8 @@ CIRCUITPY_DRIVE_LABEL = "PYCUBED"
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_BITMAPTOOLS = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_GAMEPAD = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_PS2IO = 0

View File

@ -17,7 +17,7 @@ CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_BITMAPTOOLS = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_GAMEPAD = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_PS2IO = 0

View File

@ -11,4 +11,6 @@ SPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = AT25SF161
LONGINT_IMPL = MPZ
CIRCUITPY_KEYPAD = 0
CIRCUITPY_BITBANG_APA102 = 1

View File

@ -22,7 +22,6 @@ CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_BLEIO = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_GAMEPAD = 0
CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_TOUCHIO = 0
CIRCUITPY_RGBMATRIX = 0

View File

@ -21,7 +21,6 @@ CIRCUITPY_BITMAPTOOLS = 0
CIRCUITPY_BLEIO_HCI = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_GAMEPAD = 0
CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_TOUCHIO = 0
CIRCUITPY_RGBMATRIX = 0

View File

@ -50,6 +50,7 @@ CIRCUITPY_FRAMEBUFFERIO ?= 0
CIRCUITPY_FREQUENCYIO ?= 0
CIRCUITPY_I2CPERIPHERAL ?= 0
CIRCUITPY_JSON ?= 0
CIRCUITPY_KEYPAD ?= 0
CIRCUITPY_MSGPACK ?= 0
CIRCUITPY_RE ?= 0
CIRCUITPY_SDCARDIO ?= 0

View File

@ -18,6 +18,7 @@ CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_JSON = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_MSGPACK = 0
CIRCUITPY_NEOPIXEL_WRITE = 0
CIRCUITPY_NVM = 0

View File

@ -20,7 +20,7 @@ CIRCUITPY_COUNTIO = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_ERRNO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_GAMEPAD = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_MSGPACK = 0
CIRCUITPY_NEOPIXEL_WRITE = 0
CIRCUITPY_NVM = 0

View File

@ -22,6 +22,7 @@ CIRCUITPY_AUDIOPWMIO = 0
CIRCUITPY_BUSDEVICE = 0
CIRCUITPY_BITMAPTOOLS = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_MIDI = 0
CIRCUITPY_MSGPACK = 0
CIRCUITPY_ULAB = 0

View File

@ -20,4 +20,5 @@ LD_FILE = boards/STM32F401xe_boot.ld
# For debugging - also comment BOOTLOADER_OFFSET and BOARD_VTOR_DEFER
# LD_FILE = boards/STM32F401xe_fs.ld
CIRCUITPY_BLEIO_HCI = 0
CIRCUITPY_ULAB = 0

View File

@ -16,5 +16,6 @@ LD_FILE = boards/STM32F411_fs.ld
# Too big for the flash
CIRCUITPY_AUDIOCORE = 0
CIRCUITPY_AUDIOPWMIO = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_MIDI = 0
CIRCUITPY_MSGPACK = 0

View File

@ -15,5 +15,6 @@ LD_FILE = boards/STM32F411_fs.ld
# Too big for the flash
CIRCUITPY_AUDIOCORE = 0
CIRCUITPY_AUDIOPWMIO = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_MIDI = 0
CIRCUITPY_MSGPACK = 0

View File

@ -162,3 +162,56 @@ NORETURN void mp_arg_error_unimpl_kw(void) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("keyword argument(s) not yet implemented - use normal args instead"));
}
#endif
mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name) {
if (i < min) {
mp_raise_ValueError_varg(translate("%q must be >= %d"), arg_name, min);
}
return i;
}
mp_int_t mp_arg_validate_int_max(mp_int_t i, mp_int_t max, qstr arg_name) {
if (i > max) {
mp_raise_ValueError_varg(translate("%q must <= %d"), arg_name, max);
}
return i;
}
mp_int_t mp_arg_validate_int_range(mp_int_t i, mp_int_t min, mp_int_t max, qstr arg_name) {
if (i < min || i > max) {
mp_raise_ValueError_varg(translate("%q must be %d-%d"), arg_name, min, max);
}
return i;
}
mp_float_t mp_arg_validate_obj_float_non_negative(mp_obj_t float_in, mp_float_t default_for_null, qstr arg_name) {
const mp_float_t f = (float_in == MP_OBJ_NULL)
? default_for_null
: mp_obj_get_float(float_in);
if (f <= (mp_float_t)0.0) {
mp_raise_ValueError_varg(translate("%q must be >= 0"), arg_name);
}
return f;
}
size_t mp_arg_validate_length_with_name(mp_int_t i, size_t length, qstr arg_name, qstr length_name) {
if (i != (mp_int_t)length) {
mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_pressed, MP_QSTR_num_keys);
}
return (size_t)i;
}
mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_name) {
if (!mp_obj_is_type(obj, type)) {
mp_raise_TypeError_varg(translate("%q must of type %q"), arg_name, type->name);
}
return obj;
}
mp_obj_t mp_arg_validate_string(mp_obj_t obj, qstr arg_name) {
if (!mp_obj_is_str(obj)) {
mp_raise_TypeError_varg(translate("%q must be a string"), arg_name);
}
return obj;
}

View File

@ -178,6 +178,9 @@ endif
ifeq ($(CIRCUITPY_FRAMEBUFFERIO),1)
SRC_PATTERNS += framebufferio/%
endif
ifeq ($(CIRCUITPY__EVE),1)
SRC_PATTERNS += _eve/%
endif
ifeq ($(CIRCUITPY_FREQUENCYIO),1)
SRC_PATTERNS += frequencyio/%
endif
@ -196,12 +199,12 @@ endif
ifeq ($(CIRCUITPY_IPADDRESS),1)
SRC_PATTERNS += ipaddress/%
endif
ifeq ($(CIRCUITPY_KEYPAD),1)
SRC_PATTERNS += keypad/%
endif
ifeq ($(CIRCUITPY_MATH),1)
SRC_PATTERNS += math/%
endif
ifeq ($(CIRCUITPY__EVE),1)
SRC_PATTERNS += _eve/%
endif
ifeq ($(CIRCUITPY_MEMORYMONITOR),1)
SRC_PATTERNS += memorymonitor/%
endif
@ -512,6 +515,12 @@ SRC_SHARED_MODULE_ALL = \
framebufferio/__init__.c \
ipaddress/IPv4Address.c \
ipaddress/__init__.c \
keypad/__init__.c \
keypad/Event.c \
keypad/EventQueue.c \
keypad/KeyMatrix.c \
keypad/ShiftRegisterKeys.c \
keypad/Keys.c \
sdcardio/SDCard.c \
sdcardio/__init__.c \
gamepad/GamePad.c \

View File

@ -440,6 +440,13 @@ extern const struct _mp_obj_module_t espidf_module;
#define ESPIDF_MODULE
#endif
#if CIRCUITPY__EVE
extern const struct _mp_obj_module_t _eve_module;
#define _EVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__eve), (mp_obj_t)&_eve_module },
#else
#define _EVE_MODULE
#endif
#if CIRCUITPY_FRAMEBUFFERIO
extern const struct _mp_obj_module_t framebufferio_module;
#define FRAMEBUFFERIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_framebufferio), (mp_obj_t)&framebufferio_module },
@ -523,6 +530,23 @@ extern const struct _mp_obj_module_t ipaddress_module;
#define JSON_MODULE
#endif
#if CIRCUITPY_KEYPAD
extern const struct _mp_obj_module_t keypad_module;
#define KEYPAD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_keypad), (mp_obj_t)&keypad_module },
#define KEYPAD_ROOT_POINTERS mp_obj_t keypad_scanners_linked_list;
#else
#define KEYPAD_MODULE
#define KEYPAD_ROOT_POINTERS
#endif
#if CIRCUITPY_GAMEPAD || CIRCUITPY_GAMEPADSHIFT
// Scan gamepad every 32ms
#define CIRCUITPY_GAMEPAD_TICKS 0x1f
#define GAMEPAD_ROOT_POINTERS mp_obj_t gamepad_singleton;
#else
#define GAMEPAD_ROOT_POINTERS
#endif
#if CIRCUITPY_MATH
extern const struct _mp_obj_module_t math_module;
#define MATH_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module },
@ -530,13 +554,6 @@ extern const struct _mp_obj_module_t math_module;
#define MATH_MODULE
#endif
#if CIRCUITPY__EVE
extern const struct _mp_obj_module_t _eve_module;
#define _EVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__eve), (mp_obj_t)&_eve_module },
#else
#define _EVE_MODULE
#endif
#if CIRCUITPY_MEMORYMONITOR
extern const struct _mp_obj_module_t memorymonitor_module;
#define MEMORYMONITOR_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_memorymonitor), (mp_obj_t)&memorymonitor_module },
@ -877,6 +894,7 @@ extern const struct _mp_obj_module_t msgpack_module;
VECTORIO_MODULE \
ERRNO_MODULE \
ESPIDF_MODULE \
_EVE_MODULE \
FRAMEBUFFERIO_MODULE \
FREQUENCYIO_MODULE \
GAMEPAD_MODULE \
@ -886,8 +904,8 @@ extern const struct _mp_obj_module_t msgpack_module;
IPADDRESS_MODULE \
IMAGECAPTURE_MODULE \
JSON_MODULE \
KEYPAD_MODULE \
MATH_MODULE \
_EVE_MODULE \
MEMORYMONITOR_MODULE \
MICROCONTROLLER_MODULE \
MSGPACK_MODULE \
@ -954,6 +972,7 @@ struct _supervisor_allocation_node;
vstr_t *repl_line; \
mp_obj_t rtc_time_source; \
GAMEPAD_ROOT_POINTERS \
KEYPAD_ROOT_POINTERS \
mp_obj_t pew_singleton; \
BOARD_UART_ROOT_POINTER \
FLASH_ROOT_POINTERS \

View File

@ -178,10 +178,13 @@ CFLAGS += -DCIRCUITPY_ERRNO=$(CIRCUITPY_ERRNO)
CIRCUITPY_ESPIDF ?= 0
CFLAGS += -DCIRCUITPY_ESPIDF=$(CIRCUITPY_ESPIDF)
CIRCUITPY__EVE ?= 0
CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE)
CIRCUITPY_FREQUENCYIO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO)
CIRCUITPY_GAMEPAD ?= $(CIRCUITPY_FULL_BUILD)
CIRCUITPY_GAMEPAD ?= 0
CFLAGS += -DCIRCUITPY_GAMEPAD=$(CIRCUITPY_GAMEPAD)
CIRCUITPY_GAMEPADSHIFT ?= 0
@ -199,12 +202,12 @@ CFLAGS += -DCIRCUITPY_IPADDRESS=$(CIRCUITPY_IPADDRESS)
CIRCUITPY_JSON ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_JSON=$(CIRCUITPY_JSON)
CIRCUITPY_KEYPAD ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_KEYPAD=$(CIRCUITPY_KEYPAD)
CIRCUITPY_MATH ?= 1
CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH)
CIRCUITPY__EVE ?= 0
CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE)
CIRCUITPY_MEMORYMONITOR ?= 0
CFLAGS += -DCIRCUITPY_MEMORYMONITOR=$(CIRCUITPY_MEMORYMONITOR)

View File

@ -91,6 +91,14 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args,
NORETURN void mp_arg_error_terse_mismatch(void);
NORETURN void mp_arg_error_unimpl_kw(void);
mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name);
mp_int_t mp_arg_validate_int_max(mp_int_t i, mp_int_t j, qstr arg_name);
mp_int_t mp_arg_validate_int_range(mp_int_t i, mp_int_t min, mp_int_t max, qstr arg_name);
mp_float_t mp_arg_validate_obj_float_non_negative(mp_obj_t float_in, mp_float_t default_for_null, qstr arg_name);
size_t mp_arg_validate_length_with_name(mp_int_t i, size_t length, qstr arg_name, qstr length_name);
mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_name);
mp_obj_t mp_arg_validate_string(mp_obj_t obj, qstr arg_name);
static inline mp_obj_dict_t *PLACE_IN_ITCM(mp_locals_get)(void) {
return MP_STATE_THREAD(dict_locals);
}

View File

@ -43,7 +43,7 @@
//| clock: microcontroller.Pin,
//| vsync: Optional[microcontroller.Pin],
//| href: Optional[microcontroller.Pin],
//| ):
//| ) -> None:
//| """Create a parallel image capture object
//|
//| :param List[microcontroller.Pin] data_pins: The data pins.

View File

@ -0,0 +1,180 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/obj.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "shared-bindings/keypad/Event.h"
//| class Event:
//| """A key transition event."""
//| def __init__(self, key_number: int=0, pressed: bool=True) -> None:
//| """Create a key transition event, which reports a key-pressed or key-released transition.
//|
//| :param int key_number: the key number
//| :param bool pressed: ``True`` if the key was pressed; ``False`` if it was released.
//| """
//| ...
//|
STATIC mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
keypad_event_obj_t *self = m_new_obj(keypad_event_obj_t);
self->base.type = &keypad_event_type;
enum { ARG_key_number, ARG_pressed };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_key_number, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_pressed, MP_ARG_BOOL, {.u_bool = true} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const mp_uint_t key_number =
(mp_uint_t)mp_arg_validate_int_min(args[ARG_key_number].u_int, 0, MP_QSTR_key_number);
common_hal_keypad_event_construct(self, key_number, args[ARG_pressed].u_bool);
return MP_OBJ_FROM_PTR(self);
}
//| key_number: int
//| """The key number."""
//|
STATIC mp_obj_t keypad_event_get_key_number(mp_obj_t self_in) {
keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_event_get_key_number(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_key_number_obj, keypad_event_get_key_number);
const mp_obj_property_t keypad_event_key_number_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_event_get_key_number_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
//| pressed: bool
//| """``True`` if the event represents a key down (pressed) transition.
//| The opposite of `released`.
//| """
//|
STATIC mp_obj_t keypad_event_get_pressed(mp_obj_t self_in) {
keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_bool(common_hal_keypad_event_get_pressed(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_pressed_obj, keypad_event_get_pressed);
const mp_obj_property_t keypad_event_pressed_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_event_get_pressed_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
//| released: bool
//| """``True`` if the event represents a key up (released) transition.
//| The opposite of `pressed`.
//| """
//|
STATIC mp_obj_t keypad_event_get_released(mp_obj_t self_in) {
keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_bool(common_hal_keypad_event_get_released(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_released_obj, keypad_event_get_released);
const mp_obj_property_t keypad_event_released_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_event_get_released_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
//| def __eq__(self, other: object) -> bool:
//| """Two `Event` objects are equal if their `key_number`
//| and `pressed`/`released` values are equal.
//| """
//| ...
//|
STATIC mp_obj_t keypad_event_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
switch (op) {
case MP_BINARY_OP_EQUAL:
if (mp_obj_is_type(rhs_in, &keypad_event_type)) {
keypad_event_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in);
keypad_event_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in);
return mp_obj_new_bool(
(common_hal_keypad_event_get_key_number(lhs) ==
common_hal_keypad_event_get_key_number(rhs)) &&
(common_hal_keypad_event_get_pressed(lhs) ==
common_hal_keypad_event_get_pressed(rhs))
);
} else {
return mp_const_false;
}
default:
return MP_OBJ_NULL; // op not supported
}
}
//| def __hash__(self) -> int:
//| """Returns a hash for the `Event`, so it can be used in dictionaries, etc.."""
//| ...
//|
STATIC mp_obj_t keypad_event_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
keypad_event_obj_t *self = MP_OBJ_TO_PTR(self);
switch (op) {
case MP_UNARY_OP_HASH: {
const mp_int_t key_number = common_hal_keypad_event_get_key_number(self);
const bool pressed = common_hal_keypad_event_get_pressed(self);
return MP_OBJ_NEW_SMALL_INT((pressed << 15) + key_number);
}
default:
return MP_OBJ_NULL; // op not supported
}
}
STATIC void keypad_event_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "<Event: key_number %d %s>",
common_hal_keypad_event_get_key_number(self),
common_hal_keypad_event_get_pressed(self) ? "pressed" : "released");
}
STATIC const mp_rom_map_elem_t keypad_event_locals_dict_table[] = {
// Properties
{ MP_ROM_QSTR(MP_QSTR_key_number), MP_ROM_PTR(&keypad_event_key_number_obj) },
{ MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_event_pressed_obj) },
{ MP_ROM_QSTR(MP_QSTR_released), MP_ROM_PTR(&keypad_event_released_obj) },
};
STATIC MP_DEFINE_CONST_DICT(keypad_event_locals_dict, keypad_event_locals_dict_table);
const mp_obj_type_t keypad_event_type = {
{ &mp_type_type },
.name = MP_QSTR_Event,
.make_new = keypad_event_make_new,
.print = keypad_event_print,
.unary_op = keypad_event_unary_op,
.binary_op = keypad_event_binary_op,
.locals_dict = (mp_obj_dict_t *)&keypad_event_locals_dict,
};

View File

@ -0,0 +1,40 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H
#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H
#include "py/obj.h"
#include "shared-module/keypad/Event.h"
extern const mp_obj_type_t keypad_event_type;
void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_uint_t key_number, bool pressed);
mp_int_t common_hal_keypad_event_get_key_number(keypad_event_obj_t *self);
bool common_hal_keypad_event_get_pressed(keypad_event_obj_t *self);
bool common_hal_keypad_event_get_released(keypad_event_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H

View File

@ -0,0 +1,152 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/objproperty.h"
#include "py/runtime.h"
#include "shared-bindings/keypad/Event.h"
#include "shared-bindings/keypad/EventQueue.h"
//| class EventQueue:
//| """A queue of `Event` objects, filled by a `keypad` scanner such as `Keys` or `KeyMatrix`.
//|
//| You cannot create an instance of `EventQueue` directly. Each scanner creates an
//| instance when it is created.
//| """
//| ...
//| def get(self) -> Optional[Event]:
//| """Return the next key transition event. Return ``None`` if no events are pending.
//|
//| Note that the queue size is limited; see ``max_events`` in the constructor of
//| a scanner such as `Keys` or `KeyMatrix`.
//| If a new event arrives when the queue is full, the event is discarded, and
//| `overflowed` is set to ``True``.
//|
//| :return: the next queued key transition `Event`
//| :rtype: Optional[Event]
//| """
//| ...
//|
STATIC mp_obj_t keypad_eventqueue_get(mp_obj_t self_in) {
keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
return common_hal_keypad_eventqueue_get(self);
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_get_obj, keypad_eventqueue_get);
//| def get_into(self, event: Event) -> bool:
//| """Store the next key transition event in the supplied event, if available,
//| and return ``True``.
//| If there are no queued events, do not touch ``event`` and return ``False``.
//|
//| The advantage of this method over ``get()`` is that it does not allocate storage.
//| Instead you can reuse an existing ``Event`` object.
//|
//| Note that the queue size is limited; see ``max_events`` in the constructor of
//| a scanner such as `Keys` or `KeyMatrix`.
//|
//| :return ``True`` if an event was available and stored, ``False`` if not.
//| :rtype: bool
//| """
//| ...
//|
STATIC mp_obj_t keypad_eventqueue_get_into(mp_obj_t self_in, mp_obj_t event_in) {
keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
keypad_event_obj_t *event = MP_OBJ_TO_PTR(mp_arg_validate_type(event_in, &keypad_event_type, MP_QSTR_event));
return mp_obj_new_bool(common_hal_keypad_eventqueue_get_into(self, event));
}
MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_get_into_obj, keypad_eventqueue_get_into);
//| def clear(self) -> None:
//| """Clear any queued key transition events. Also sets `overflowed` to ``False``.
//| """
//| ...
//|
STATIC mp_obj_t keypad_eventqueue_clear(mp_obj_t self_in) {
keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_keypad_eventqueue_clear(self);
return MP_ROM_NONE;
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_clear_obj, keypad_eventqueue_clear);
//| def __bool__(self) -> bool:
//| """``True`` if `len()` is greater than zero.
//| This is an easy way to check if the queue is empty.
//| """
//| ...
//|
//| def __len__(self) -> int:
//| """Return the number of events currently in the queue. Used to implement ``len()``."""
//| ...
//|
STATIC mp_obj_t keypad_eventqueue_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
uint16_t len = common_hal_keypad_eventqueue_get_length(self);
switch (op) {
case MP_UNARY_OP_BOOL:
return mp_obj_new_bool(len != 0);
case MP_UNARY_OP_LEN:
return MP_OBJ_NEW_SMALL_INT(len);
default:
return MP_OBJ_NULL; // op not supported
}
}
//| overflowed: bool
//| """``True`` if an event could not be added to the event queue because it was full. (read-only)
//| Set to ``False`` by `clear()`.
//| """
//|
STATIC mp_obj_t keypad_eventqueue_get_overflowed(mp_obj_t self_in) {
keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_bool(common_hal_keypad_eventqueue_get_overflowed(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_get_overflowed_obj, keypad_eventqueue_get_overflowed);
const mp_obj_property_t keypad_eventqueue_overflowed_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_eventqueue_get_overflowed_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
STATIC const mp_rom_map_elem_t keypad_eventqueue_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&keypad_eventqueue_clear_obj) },
{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&keypad_eventqueue_get_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_into), MP_ROM_PTR(&keypad_eventqueue_get_into_obj) },
};
STATIC MP_DEFINE_CONST_DICT(keypad_eventqueue_locals_dict, keypad_eventqueue_locals_dict_table);
const mp_obj_type_t keypad_eventqueue_type = {
{ &mp_type_type },
.name = MP_QSTR_Keys,
.unary_op = keypad_eventqueue_unary_op,
.locals_dict = (mp_obj_t)&keypad_eventqueue_locals_dict,
};

View File

@ -0,0 +1,45 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H
#include "shared-module/keypad/Event.h"
#include "shared-module/keypad/EventQueue.h"
extern const mp_obj_type_t keypad_eventqueue_type;
void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events);
void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self);
size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self);
mp_obj_t common_hal_keypad_eventqueue_get(keypad_eventqueue_obj_t *self);
bool common_hal_keypad_eventqueue_get_into(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event);
bool common_hal_keypad_eventqueue_get_overflowed(keypad_eventqueue_obj_t *self);
void common_hal_keypad_eventqueue_set_overflowed(keypad_eventqueue_obj_t *self, bool overflowed);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H

View File

@ -0,0 +1,269 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "lib/utils/context_manager_helpers.h"
#include "py/binary.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "shared-bindings/keypad/Event.h"
#include "shared-bindings/keypad/KeyMatrix.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/util.h"
//| class KeyMatrix:
//| """Manage a 2D matrix of keys with row and column pins."""
//|
//| def __init__(self, row_pins: Sequence[microcontroller.Pin], column_pins: Sequence[microcontroller.Pin], columns_to_anodes: bool = True, interval: float = 0.020, max_events: int = 64) -> None:
//| """
//| Create a `Keys` object that will scan the key matrix attached to the given row and column pins.
//| There should not be any external pull-ups or pull-downs on the matrix:
//| ``KeyMatrix`` enables internal pull-ups or pull-downs on the pins as necessary.
//|
//| The keys are numbered sequentially from zero. A key number can be computed
//| by ``row * len(column_pins) + column``.
//|
//| An `EventQueue` is created when this object is created and is available in the `events` attribute.
//|
//| :param Sequence[microcontroller.Pin] row_pins: The pins attached to the rows.
//| :param Sequence[microcontroller.Pin] column_pins: The pins attached to the colums.
//| :param bool columns_to_anodes: Default ``True``.
//| If the matrix uses diodes, the diode anodes are typically connected to the column pins,
//| and the cathodes should be connected to the row pins. If your diodes are reversed,
//| set ``columns_to_anodes`` to ``False``.
//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
//| :param int max_events: maximum size of `events` `EventQueue`:
//| maximum number of key transition events that are saved.
//| Must be >= 1.
//| If a new event arrives when the queue is full, the oldest event is discarded.
//| """
//| ...
STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
keypad_keymatrix_obj_t *self = m_new_obj(keypad_keymatrix_obj_t);
self->base.type = &keypad_keymatrix_type;
enum { ARG_row_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_column_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_columns_to_anodes, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
{ MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_obj_t row_pins = args[ARG_row_pins].u_obj;
// mp_obj_len() will be >= 0.
const size_t num_row_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(row_pins));
mp_obj_t column_pins = args[ARG_column_pins].u_obj;
const size_t num_column_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(column_pins));
const mp_float_t interval =
mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
mcu_pin_obj_t *row_pins_array[num_row_pins];
mcu_pin_obj_t *column_pins_array[num_column_pins];
for (size_t row = 0; row < num_row_pins; row++) {
mcu_pin_obj_t *pin =
validate_obj_is_free_pin(mp_obj_subscr(row_pins, MP_OBJ_NEW_SMALL_INT(row), MP_OBJ_SENTINEL));
row_pins_array[row] = pin;
}
for (size_t column = 0; column < num_column_pins; column++) {
mcu_pin_obj_t *pin =
validate_obj_is_free_pin(mp_obj_subscr(column_pins, MP_OBJ_NEW_SMALL_INT(column), MP_OBJ_SENTINEL));
column_pins_array[column] = pin;
}
common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events);
return MP_OBJ_FROM_PTR(self);
}
//| def deinit(self) -> None:
//| """Stop scanning and release the pins."""
//| ...
//|
STATIC mp_obj_t keypad_keymatrix_deinit(mp_obj_t self_in) {
keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_keypad_keymatrix_deinit(self);
return MP_ROM_NONE;
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_deinit_obj, keypad_keymatrix_deinit);
//| def __enter__(self) -> KeyMatrix:
//| """No-op used by Context Managers."""
//| ...
//|
// Provided by context manager helper.
//| def __exit__(self) -> None:
//| """Automatically deinitializes when exiting a context. See
//| :ref:`lifetime-and-contextmanagers` for more info."""
//| ...
//|
STATIC mp_obj_t keypad_keymatrix___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
common_hal_keypad_keymatrix_deinit(args[0]);
return MP_ROM_NONE;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_keymatrix___exit___obj, 4, 4, keypad_keymatrix___exit__);
STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) {
if (common_hal_keypad_keymatrix_deinited(self)) {
raise_deinited_error();
}
}
//| def reset(self) -> None:
//| """Reset the internal state of the scanner to assume that all keys are now released.
//| Any key that is already pressed at the time of this call will therefore immediately cause
//| a new key-pressed event to occur.
//| """
//| ...
//|
STATIC mp_obj_t keypad_keymatrix_reset(mp_obj_t self_in) {
keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
common_hal_keypad_keymatrix_reset(self);
return MP_ROM_NONE;
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_reset_obj, keypad_keymatrix_reset);
//| key_count: int
//| """The number of keys that are being scanned. (read-only)
//| """
//|
STATIC mp_obj_t keypad_keymatrix_get_key_count(mp_obj_t self_in) {
keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keymatrix_get_key_count(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_get_key_count_obj, keypad_keymatrix_get_key_count);
const mp_obj_property_t keypad_keymatrix_key_count_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_keymatrix_get_key_count_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
//| def key_number_to_row_column(self, row: int, column: int) -> Tuple[int]:
//| """Return the row and column for the given key number.
//| The row is ``key_number // len(column_pins)``.
//| The column is ``key_number % len(column_pins)``.
//|
//| :return: ``(row, column)``
//| :rtype: Tuple[int]
//| """
//| ...
//|
STATIC mp_obj_t keypad_keymatrix_key_number_to_row_column(mp_obj_t self_in, mp_obj_t key_number_in) {
keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
const mp_uint_t key_number = (mp_uint_t)mp_arg_validate_int_range(
mp_obj_get_int(key_number_in),
0, (mp_int_t)common_hal_keypad_keymatrix_get_key_count(self),
MP_QSTR_key_number);
mp_uint_t row;
mp_uint_t column;
common_hal_keypad_keymatrix_key_number_to_row_column(self, key_number, &row, &column);
mp_obj_t row_column[2];
row_column[0] = MP_OBJ_NEW_SMALL_INT(row);
row_column[1] = MP_OBJ_NEW_SMALL_INT(column);
return mp_obj_new_tuple(2, row_column);
}
MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_key_number_to_row_column_obj, keypad_keymatrix_key_number_to_row_column);
//| def row_column_to_key_number(self, row: int, column: int) -> int:
//| """Return the key number for a given row and column.
//| The key number is ``row * len(column_pins) + column``.
//| """
//| ...
//|
STATIC mp_obj_t keypad_keymatrix_row_column_to_key_number(mp_obj_t self_in, mp_obj_t row_in, mp_obj_t column_in) {
keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
const mp_uint_t row = (mp_uint_t)mp_arg_validate_int_range(
mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_row_count(self), MP_QSTR_row);
const mp_int_t column = (mp_uint_t)mp_arg_validate_int_range(
mp_obj_get_int(column_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_column_count(self), MP_QSTR_column);
return MP_OBJ_NEW_SMALL_INT(
(mp_int_t)common_hal_keypad_keymatrix_row_column_to_key_number(self, row, column));
}
MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_row_column_to_key_number_obj, keypad_keymatrix_row_column_to_key_number);
//| events: EventQueue
//| """The `EventQueue` associated with this `Keys` object. (read-only)
//| """
//|
STATIC mp_obj_t keypad_keymatrix_get_events(mp_obj_t self_in) {
keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return common_hal_keypad_keymatrix_get_events(self);
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_get_events_obj, keypad_keymatrix_get_events);
const mp_obj_property_t keypad_keymatrix_events_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_keymatrix_get_events_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keymatrix_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keymatrix_events_obj) },
{ MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keymatrix_key_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_keymatrix_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_key_number_to_row_column), MP_ROM_PTR(&keypad_keymatrix_key_number_to_row_column_obj) },
{ MP_ROM_QSTR(MP_QSTR_row_column_to_key_number), MP_ROM_PTR(&keypad_keymatrix_row_column_to_key_number_obj) },
};
STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_locals_dict_table);
const mp_obj_type_t keypad_keymatrix_type = {
{ &mp_type_type },
.name = MP_QSTR_KeyMatrix,
.make_new = keypad_keymatrix_make_new,
.locals_dict = (mp_obj_t)&keypad_keymatrix_locals_dict,
};

View File

@ -0,0 +1,50 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H
#include "py/objlist.h"
#include "shared-module/keypad/KeyMatrix.h"
extern const mp_obj_type_t keypad_keymatrix_type;
void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events);
void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self);
bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self);
void common_hal_keypad_keymatrix_key_number_to_row_column(keypad_keymatrix_obj_t *self, mp_uint_t key_number, mp_uint_t *row, mp_uint_t *column);
mp_uint_t common_hal_keypad_keymatrix_row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column);
size_t common_hal_keypad_keymatrix_get_key_count(keypad_keymatrix_obj_t *self);
size_t common_hal_keypad_keymatrix_get_column_count(keypad_keymatrix_obj_t *self);
size_t common_hal_keypad_keymatrix_get_row_count(keypad_keymatrix_obj_t *self);
mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self);
void common_hal_keypad_keymatrix_reset(keypad_keymatrix_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H

View File

@ -0,0 +1,209 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "lib/utils/context_manager_helpers.h"
#include "py/binary.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "shared-bindings/keypad/Event.h"
#include "shared-bindings/keypad/Keys.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/util.h"
//| class Keys:
//| """Manage a set of independent keys."""
//|
//| def __init__(self, pins: Sequence[microcontroller.Pin], *, value_when_pressed: bool, pull: bool = True, interval: float = 0.020, max_events: int = 64) -> None:
//| """
//| Create a `Keys` object that will scan keys attached to the given sequence of pins.
//| Each key is independent and attached to its own pin.
//|
//| An `EventQueue` is created when this object is created and is available in the `events` attribute.
//|
//| :param Sequence[microcontroller.Pin] pins: The pins attached to the keys.
//| The key numbers correspond to indices into this sequence.
//| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed.
//| ``False`` if the pin reads low (is grounded) when the key is pressed.
//| All the pins must be connected in the same way.
//| :param bool pull: ``True`` if an internal pull-up or pull-down should be
//| enabled on each pin. A pull-up will be used if ``value_when_pressed`` is ``False``;
//| a pull-down will be used if it is ``True``.
//| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``.
//| However, enabling an internal pull when an external one is already present is not a problem;
//| it simply uses slightly more current.
//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
//| :param int max_events: maximum size of `events` `EventQueue`:
//| maximum number of key transition events that are saved.
//| Must be >= 1.
//| If a new event arrives when the queue is full, the oldest event is discarded.
//| """
//| ...
STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
keypad_keys_obj_t *self = m_new_obj(keypad_keys_obj_t);
self->base.type = &keypad_keys_type;
enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_interval, ARG_max_events };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL },
{ MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
{ MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL } },
{ MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_obj_t pins = args[ARG_pins].u_obj;
// mp_obj_len() will be >= 0.
const size_t num_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(pins));
const bool value_when_pressed = args[ARG_value_when_pressed].u_bool;
const mp_float_t interval =
mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
mcu_pin_obj_t *pins_array[num_pins];
for (mp_uint_t i = 0; i < num_pins; i++) {
mcu_pin_obj_t *pin =
validate_obj_is_free_pin(mp_obj_subscr(pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL));
pins_array[i] = pin;
}
common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events);
return MP_OBJ_FROM_PTR(self);
}
//| def deinit(self) -> None:
//| """Stop scanning and release the pins."""
//| ...
//|
STATIC mp_obj_t keypad_keys_deinit(mp_obj_t self_in) {
keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_keypad_keys_deinit(self);
return MP_ROM_NONE;
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_deinit_obj, keypad_keys_deinit);
//| def __enter__(self) -> Keys:
//| """No-op used by Context Managers."""
//| ...
//|
// Provided by context manager helper.
//| def __exit__(self) -> None:
//| """Automatically deinitializes when exiting a context. See
//| :ref:`lifetime-and-contextmanagers` for more info."""
//| ...
//|
STATIC mp_obj_t keypad_keys___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
common_hal_keypad_keys_deinit(args[0]);
return MP_ROM_NONE;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_keys___exit___obj, 4, 4, keypad_keys___exit__);
STATIC void check_for_deinit(keypad_keys_obj_t *self) {
if (common_hal_keypad_keys_deinited(self)) {
raise_deinited_error();
}
}
//| def reset(self) -> None:
//| """Reset the internal state of the scanner to assume that all keys are now released.
//| Any key that is already pressed at the time of this call will therefore immediately cause
//| a new key-pressed event to occur.
//| """
//| ...
//|
STATIC mp_obj_t keypad_keys_reset(mp_obj_t self_in) {
keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
common_hal_keypad_keys_reset(self);
return MP_ROM_NONE;
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_reset_obj, keypad_keys_reset);
//| key_count: int
//| """The number of keys that are being scanned. (read-only)
//| """
//|
STATIC mp_obj_t keypad_keys_get_key_count(mp_obj_t self_in) {
keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keys_get_key_count(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_get_key_count_obj, keypad_keys_get_key_count);
const mp_obj_property_t keypad_keys_key_count_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_keys_get_key_count_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
//| events: EventQueue
//| """The `EventQueue` associated with this `Keys` object. (read-only)
//| """
//|
STATIC mp_obj_t keypad_keys_get_events(mp_obj_t self_in) {
keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return common_hal_keypad_keys_get_events(self);
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_get_events_obj, keypad_keys_get_events);
const mp_obj_property_t keypad_keys_events_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_keys_get_events_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keys_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keys_events_obj) },
{ MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keys_key_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_keys_reset_obj) },
};
STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table);
const mp_obj_type_t keypad_keys_type = {
{ &mp_type_type },
.name = MP_QSTR_Keys,
.make_new = keypad_keys_make_new,
.locals_dict = (mp_obj_t)&keypad_keys_locals_dict,
};

View File

@ -0,0 +1,44 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H
#include "py/objlist.h"
#include "shared-module/keypad/Keys.h"
extern const mp_obj_type_t keypad_keys_type;
void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events);
void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self);
bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self);
mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self);
size_t common_hal_keypad_keys_get_key_count(keypad_keys_obj_t *self);
void common_hal_keypad_keys_reset(keypad_keys_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H

View File

@ -0,0 +1,213 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "lib/utils/context_manager_helpers.h"
#include "py/binary.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "shared-bindings/keypad/Event.h"
#include "shared-bindings/keypad/ShiftRegisterKeys.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/util.h"
//| class ShiftRegisterKeys:
//| """Manage a set of keys attached to an incoming shift register."""
//|
//| def __init__(self, *, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, value_to_latch: bool = True, key_count: int, value_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None:
//| """
//| Create a `Keys` object that will scan keys attached to a parallel-in serial-out shift register
//| like the 74HC165 or CD4021.
//| Note that you may chain shift registers to load in as many values as you need.
//|
//| Key number 0 is the first (or more properly, the zero-th) bit read. In the
//| 74HC165, this bit is labeled ``Q7``. Key number 1 will be the value of ``Q6``, etc.
//|
//| An `EventQueue` is created when this object is created and is available in the `events` attribute.
//|
//| :param microcontroller.Pin clock: The shift register clock pin.
//| The shift register should clock on a low-to-high transition.
//| :param microcontroller.Pin data: the incoming shift register data pin
//| :param microcontroller.Pin latch:
//| Pin used to latch parallel data going into the shift register.
//| :param bool value_to_latch: Pin state to latch data being read.
//| ``True`` if the data is latched when ``latch`` goes high
//| ``False`` if the data is latched when ``latch goes low.
//| The default is ``True``, which is how the 74HC165 operates. The CD4021 latch is the opposite.
//| Once the data is latched, it will be shifted out by toggling the clock pin.
//| :param int key_count: number of data lines to clock in
//| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed.
//| ``False`` if the pin reads low (is grounded) when the key is pressed.
//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
//| :param int max_events: maximum size of `events` `EventQueue`:
//| maximum number of key transition events that are saved.
//| Must be >= 1.
//| If a new event arrives when the queue is full, the oldest event is discarded.
//| """
//| ...
STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
keypad_shiftregisterkeys_obj_t *self = m_new_obj(keypad_shiftregisterkeys_obj_t);
self->base.type = &keypad_shiftregisterkeys_type;
enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_key_count, ARG_value_when_pressed, ARG_interval, ARG_max_events };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_latch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_value_to_latch, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
{ MP_QSTR_key_count, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL },
{ MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj);
mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj);
mcu_pin_obj_t *latch = validate_obj_is_free_pin(args[ARG_latch].u_obj);
const bool value_to_latch = args[ARG_value_to_latch].u_bool;
const size_t key_count = (size_t)mp_arg_validate_int_min(args[ARG_key_count].u_int, 1, MP_QSTR_key_count);
const bool value_when_pressed = args[ARG_value_when_pressed].u_bool;
const mp_float_t interval =
mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
common_hal_keypad_shiftregisterkeys_construct(
self, clock, data, latch, value_to_latch, key_count, value_when_pressed, interval, max_events);
return MP_OBJ_FROM_PTR(self);
}
//| def deinit(self) -> None:
//| """Stop scanning and release the pins."""
//| ...
//|
STATIC mp_obj_t keypad_shiftregisterkeys_deinit(mp_obj_t self_in) {
keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_keypad_shiftregisterkeys_deinit(self);
return MP_ROM_NONE;
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_deinit_obj, keypad_shiftregisterkeys_deinit);
//| def __enter__(self) -> Keys:
//| """No-op used by Context Managers."""
//| ...
//|
// Provided by context manager helper.
//| def __exit__(self) -> None:
//| """Automatically deinitializes when exiting a context. See
//| :ref:`lifetime-and-contextmanagers` for more info."""
//| ...
//|
STATIC mp_obj_t keypad_shiftregisterkeys___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
common_hal_keypad_shiftregisterkeys_deinit(args[0]);
return MP_ROM_NONE;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_shiftregisterkeys___exit___obj, 4, 4, keypad_shiftregisterkeys___exit__);
STATIC void check_for_deinit(keypad_shiftregisterkeys_obj_t *self) {
if (common_hal_keypad_shiftregisterkeys_deinited(self)) {
raise_deinited_error();
}
}
//| def reset(self) -> None:
//| """Reset the internal state of the scanner to assume that all keys are now released.
//| Any key that is already pressed at the time of this call will therefore immediately cause
//| a new key-pressed event to occur.
//| """
//| ...
//|
STATIC mp_obj_t keypad_shiftregisterkeys_reset(mp_obj_t self_in) {
keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
common_hal_keypad_shiftregisterkeys_reset(self);
return MP_ROM_NONE;
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_reset_obj, keypad_shiftregisterkeys_reset);
//| key_count: int
//| """The number of keys that are being scanned. (read-only)
//| """
//|
STATIC mp_obj_t keypad_shiftregisterkeys_get_key_count(mp_obj_t self_in) {
keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_shiftregisterkeys_get_key_count(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_get_key_count_obj, keypad_shiftregisterkeys_get_key_count);
const mp_obj_property_t keypad_shiftregisterkeys_key_count_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_shiftregisterkeys_get_key_count_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
//| events: EventQueue
//| """The `EventQueue` associated with this `Keys` object. (read-only)
//| """
//|
STATIC mp_obj_t keypad_shiftregisterkeys_get_events(mp_obj_t self_in) {
keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return common_hal_keypad_shiftregisterkeys_get_events(self);
}
MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_get_events_obj, keypad_shiftregisterkeys_get_events);
const mp_obj_property_t keypad_shiftregisterkeys_events_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&keypad_shiftregisterkeys_get_events_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
STATIC const mp_rom_map_elem_t keypad_shiftregisterkeys_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_shiftregisterkeys_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_shiftregisterkeys___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_shiftregisterkeys_events_obj) },
{ MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_shiftregisterkeys_key_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_shiftregisterkeys_reset_obj) },
};
STATIC MP_DEFINE_CONST_DICT(keypad_shiftregisterkeys_locals_dict, keypad_shiftregisterkeys_locals_dict_table);
const mp_obj_type_t keypad_shiftregisterkeys_type = {
{ &mp_type_type },
.name = MP_QSTR_ShiftRegisterKeys,
.make_new = keypad_shiftregisterkeys_make_new,
.locals_dict = (mp_obj_t)&keypad_shiftregisterkeys_locals_dict,
};

View File

@ -0,0 +1,44 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H
#include "py/objlist.h"
#include "shared-module/keypad/ShiftRegisterKeys.h"
extern const mp_obj_type_t keypad_shiftregisterkeys_type;
void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events);
void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self);
bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t *self);
mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys_obj_t *self);
size_t common_hal_keypad_shiftregisterkeys_get_key_count(keypad_shiftregisterkeys_obj_t *self);
void common_hal_keypad_shiftregisterkeys_reset(keypad_shiftregisterkeys_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H

View File

@ -0,0 +1,59 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2011 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/obj.h"
#include "shared-bindings/keypad/__init__.h"
#include "shared-bindings/keypad/Event.h"
#include "shared-bindings/keypad/EventQueue.h"
#include "shared-bindings/keypad/KeyMatrix.h"
#include "shared-bindings/keypad/Keys.h"
#include "shared-bindings/keypad/ShiftRegisterKeys.h"
//| """Support for scanning keys and key matrices
//|
//| The `keypad` module provides native support to scan sets of keys or buttons,
//| connected independently to individual pins,
//| connected to a shift register,
//| or connected in a row-and-column matrix.
//| """
//|
STATIC mp_map_elem_t keypad_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) },
{ MP_ROM_QSTR(MP_QSTR_Event), MP_OBJ_FROM_PTR(&keypad_event_type) },
{ MP_ROM_QSTR(MP_QSTR_EventQueue), MP_OBJ_FROM_PTR(&keypad_eventqueue_type) },
{ MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_keymatrix_type) },
{ MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) },
{ MP_ROM_QSTR(MP_QSTR_ShiftRegisterKeys), MP_OBJ_FROM_PTR(&keypad_shiftregisterkeys_type) },
};
STATIC MP_DEFINE_MUTABLE_DICT(keypad_module_globals, keypad_module_globals_table);
const mp_obj_module_t keypad_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&keypad_module_globals,
};

View File

@ -0,0 +1,41 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SHARED_BINDINGS_KEYPAD_H
#define SHARED_BINDINGS_KEYPAD_H
#include "py/obj.h"
#include "py/objtuple.h"
#include "shared-module/keypad/__init__.h"
extern mp_obj_tuple_t common_hal_keypad_devices;
void keypad_set_devices(mp_obj_t devices);
bool common_hal_keypad_disable(void);
bool common_hal_keypad_enable(const mp_obj_t devices_seq);
#endif // SHARED_BINDINGS_KEYPAD_H

View File

@ -0,0 +1,44 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shared-module/keypad/Event.h"
void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_int_t key_number, bool pressed) {
self->key_number = key_number;
self->pressed = pressed;
}
mp_int_t common_hal_keypad_event_get_key_number(keypad_event_obj_t *self) {
return self->key_number;
}
bool common_hal_keypad_event_get_pressed(keypad_event_obj_t *self) {
return self->pressed;
}
bool common_hal_keypad_event_get_released(keypad_event_obj_t *self) {
return !self->pressed;
}

View File

@ -0,0 +1,39 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENT_H
#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENT_H
#include "py/obj.h"
typedef struct {
mp_obj_base_t base;
uint16_t key_number;
bool pressed;
} keypad_event_obj_t;
#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENT_H

View File

@ -0,0 +1,94 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shared-bindings/keypad/Event.h"
#include "shared-module/keypad/EventQueue.h"
// Key number is lower 15 bits of a 16-bit value.
#define EVENT_PRESSED (1 << 15)
#define EVENT_KEY_NUM_MASK ((1 << 15) - 1)
void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events) {
// Event queue is 16-bit values.
ringbuf_alloc(&self->encoded_events, max_events * 2, false);
self->overflowed = false;
}
mp_obj_t common_hal_keypad_eventqueue_get(keypad_eventqueue_obj_t *self) {
int encoded_event = ringbuf_get16(&self->encoded_events);
if (encoded_event == -1) {
return MP_ROM_NONE;
}
keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t);
event->base.type = &keypad_event_type;
common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED);
return MP_OBJ_FROM_PTR(event);
}
bool common_hal_keypad_eventqueue_get_into(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event) {
int encoded_event = ringbuf_get16(&self->encoded_events);
if (encoded_event == -1) {
return false;
}
// "Construct" using the existing event.
common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED);
return true;
}
bool common_hal_keypad_eventqueue_get_overflowed(keypad_eventqueue_obj_t *self) {
return self->overflowed;
}
void common_hal_keypad_eventqueue_set_overflowed(keypad_eventqueue_obj_t *self, bool overflowed) {
self->overflowed = overflowed;
}
void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self) {
ringbuf_clear(&self->encoded_events);
common_hal_keypad_eventqueue_set_overflowed(self, false);
}
size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self) {
return ringbuf_num_filled(&self->encoded_events);
}
bool keypad_eventqueue_record(keypad_eventqueue_obj_t *self, mp_uint_t key_number, bool pressed) {
if (ringbuf_num_empty(&self->encoded_events) == 0) {
// Queue is full. Set the overflow flag. The caller will decide what else to do.
common_hal_keypad_eventqueue_set_overflowed(self, true);
return false;
}
uint16_t encoded_event = key_number & EVENT_KEY_NUM_MASK;
if (pressed) {
encoded_event |= EVENT_PRESSED;
}
ringbuf_put16(&self->encoded_events, encoded_event);
return true;
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENTQUEUE_H
#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENTQUEUE_H
#include "py/obj.h"
#include "py/ringbuf.h"
typedef struct {
mp_obj_base_t base;
ringbuf_t encoded_events;
bool overflowed;
} keypad_eventqueue_obj_t;
bool keypad_eventqueue_record(keypad_eventqueue_obj_t *self, mp_uint_t key_number, bool pressed);
#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENTQUEUE_H

View File

@ -0,0 +1,182 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
#include "py/gc.h"
#include "py/runtime.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "shared-bindings/keypad/EventQueue.h"
#include "shared-bindings/keypad/KeyMatrix.h"
#include "shared-bindings/keypad/__init__.h"
#include "shared-bindings/util.h"
#include "supervisor/port.h"
#include "supervisor/shared/tick.h"
static mp_uint_t row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column) {
return row * self->column_digitalinouts->len + column;
}
void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events) {
mp_obj_t row_dios[num_row_pins];
for (size_t row = 0; row < num_row_pins; row++) {
digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t);
dio->base.type = &digitalio_digitalinout_type;
common_hal_digitalio_digitalinout_construct(dio, row_pins[row]);
common_hal_digitalio_digitalinout_switch_to_input(dio, columns_to_anodes ? PULL_UP : PULL_DOWN);
row_dios[row] = dio;
}
self->row_digitalinouts = mp_obj_new_tuple(num_row_pins, row_dios);
mp_obj_t column_dios[num_column_pins];
for (size_t column = 0; column < num_column_pins; column++) {
digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t);
dio->base.type = &digitalio_digitalinout_type;
common_hal_digitalio_digitalinout_construct(dio, column_pins[column]);
common_hal_digitalio_digitalinout_switch_to_input(dio, columns_to_anodes ? PULL_UP : PULL_DOWN);
column_dios[column] = dio;
}
self->column_digitalinouts = mp_obj_new_tuple(num_column_pins, column_dios);
self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_column_pins, false, false);
self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_column_pins, false, false);
self->columns_to_anodes = columns_to_anodes;
keypad_eventqueue_obj_t *events = m_new_obj(keypad_eventqueue_obj_t);
events->base.type = &keypad_eventqueue_type;
common_hal_keypad_eventqueue_construct(events, max_events);
self->events = events;
self->interval_ticks = (mp_uint_t)(interval * 1024); // interval * 1000 * (1024/1000)
self->last_scan_ticks = port_get_raw_ticks(NULL);
// Add self to the list of active keypad scanners.
keypad_register_scanner((keypad_scanner_obj_t *)self);
supervisor_enable_tick();
}
void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) {
if (common_hal_keypad_keymatrix_deinited(self)) {
return;
}
// Remove self from the list of active keypad scanners first.
keypad_deregister_scanner((keypad_scanner_obj_t *)self);
for (size_t row = 0; row < common_hal_keypad_keymatrix_get_row_count(self); row++) {
common_hal_digitalio_digitalinout_deinit(self->row_digitalinouts->items[row]);
}
self->row_digitalinouts = MP_ROM_NONE;
for (size_t column = 0; column < common_hal_keypad_keymatrix_get_column_count(self); column++) {
common_hal_digitalio_digitalinout_deinit(self->column_digitalinouts->items[column]);
}
self->column_digitalinouts = MP_ROM_NONE;
}
bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self) {
return self->row_digitalinouts == MP_ROM_NONE;
}
size_t common_hal_keypad_keymatrix_get_key_count(keypad_keymatrix_obj_t *self) {
return common_hal_keypad_keymatrix_get_row_count(self) * common_hal_keypad_keymatrix_get_column_count(self);
}
size_t common_hal_keypad_keymatrix_get_row_count(keypad_keymatrix_obj_t *self) {
return self->row_digitalinouts->len;
}
size_t common_hal_keypad_keymatrix_get_column_count(keypad_keymatrix_obj_t *self) {
return self->column_digitalinouts->len;
}
mp_uint_t common_hal_keypad_keymatrix_row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column) {
return row_column_to_key_number(self, row, column);
}
void common_hal_keypad_keymatrix_key_number_to_row_column(keypad_keymatrix_obj_t *self, mp_uint_t key_number, mp_uint_t *row, mp_uint_t *column) {
const size_t num_columns = common_hal_keypad_keymatrix_get_column_count(self);
*row = key_number / num_columns;
*column = key_number % num_columns;
}
mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self) {
return MP_OBJ_FROM_PTR(self->events);
}
void common_hal_keypad_keymatrix_reset(keypad_keymatrix_obj_t *self) {
const size_t key_count = common_hal_keypad_keymatrix_get_key_count(self);
supervisor_acquire_lock(&keypad_scanners_linked_list_lock);
memset(self->previously_pressed, false, key_count);
memset(self->currently_pressed, false, key_count);
supervisor_release_lock(&keypad_scanners_linked_list_lock);
}
void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) {
uint64_t now = port_get_raw_ticks(NULL);
if (now - self->last_scan_ticks < self->interval_ticks) {
// Too soon. Wait longer to debounce.
return;
}
self->last_scan_ticks = now;
// On entry, all pins are set to inputs with a pull-up or pull-down,
// depending on the diode orientation.
for (size_t row = 0; row < common_hal_keypad_keymatrix_get_row_count(self); row++) {
// Switch this row to an output and set level appropriately
// Set low if columns_to_anodes is true, else set high.
common_hal_digitalio_digitalinout_switch_to_output(
self->row_digitalinouts->items[row], !self->columns_to_anodes, DRIVE_MODE_PUSH_PULL);
for (size_t column = 0; column < common_hal_keypad_keymatrix_get_column_count(self); column++) {
mp_uint_t key_number = row_column_to_key_number(self, row, column);
const bool previous = self->currently_pressed[key_number];
self->previously_pressed[key_number] = previous;
// Get the current state, by reading whether the column got pulled to the row value or not.
// If low and columns_to_anodes is true, the key is pressed.
// If high and columns_to_anodes is false, the key is pressed.
const bool current =
common_hal_digitalio_digitalinout_get_value(self->column_digitalinouts->items[column]) !=
self->columns_to_anodes;
self->currently_pressed[key_number] = current;
// Record any transitions.
if (previous != current) {
keypad_eventqueue_record(self->events, key_number, current);
}
}
// Switch the row back to an input, pulled appropriately
common_hal_digitalio_digitalinout_switch_to_input(
self->row_digitalinouts->items[row], self->columns_to_anodes ? PULL_UP : PULL_DOWN);
}
}

View File

@ -0,0 +1,53 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H
#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H
#include "py/obj.h"
#include "py/objtuple.h"
#include "common-hal/digitalio/DigitalInOut.h"
#include "shared-module/keypad/__init__.h"
#include "shared-module/keypad/EventQueue.h"
typedef struct {
mp_obj_base_t base;
// All scanners have a next field here, to keep a linked list of active scanners.
keypad_scanner_obj_t *next;
mp_obj_tuple_t *row_digitalinouts;
mp_obj_tuple_t *column_digitalinouts;
mp_uint_t interval_ticks;
uint64_t last_scan_ticks;
bool *previously_pressed;
bool *currently_pressed;
keypad_eventqueue_obj_t *events;
bool columns_to_anodes;
} keypad_keymatrix_obj_t;
void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H

133
shared-module/keypad/Keys.c Normal file
View File

@ -0,0 +1,133 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
#include "py/gc.h"
#include "py/runtime.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "shared-bindings/keypad/EventQueue.h"
#include "shared-bindings/keypad/Keys.h"
#include "shared-bindings/keypad/__init__.h"
#include "supervisor/port.h"
#include "supervisor/shared/tick.h"
void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events) {
mp_obj_t dios[num_pins];
for (size_t i = 0; i < num_pins; i++) {
digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t);
dio->base.type = &digitalio_digitalinout_type;
common_hal_digitalio_digitalinout_construct(dio, pins[i]);
if (pull) {
common_hal_digitalio_digitalinout_set_pull(dio, value_when_pressed ? PULL_DOWN : PULL_UP);
}
dios[i] = dio;
}
self->digitalinouts = mp_obj_new_tuple(num_pins, dios);
self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false);
self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false);
self->value_when_pressed = value_when_pressed;
self->interval_ticks = (mp_uint_t)(interval * 1024); // interval * 1000 * (1024/1000)
self->last_scan_ticks = port_get_raw_ticks(NULL);
keypad_eventqueue_obj_t *events = m_new_obj(keypad_eventqueue_obj_t);
events->base.type = &keypad_eventqueue_type;
common_hal_keypad_eventqueue_construct(events, max_events);
self->events = events;
// Add self to the list of active keypad scanners.
keypad_register_scanner((keypad_scanner_obj_t *)self);
supervisor_enable_tick();
}
void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self) {
if (common_hal_keypad_keys_deinited(self)) {
return;
}
// Remove self from the list of active keypad scanners first.
keypad_deregister_scanner((keypad_scanner_obj_t *)self);
for (size_t key = 0; key < common_hal_keypad_keys_get_key_count(self); key++) {
common_hal_digitalio_digitalinout_deinit(self->digitalinouts->items[key]);
}
self->digitalinouts = MP_ROM_NONE;
}
bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self) {
return self->digitalinouts == MP_ROM_NONE;
}
size_t common_hal_keypad_keys_get_key_count(keypad_keys_obj_t *self) {
return self->digitalinouts->len;
}
mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self) {
return MP_OBJ_FROM_PTR(self->events);
}
void common_hal_keypad_keys_reset(keypad_keys_obj_t *self) {
const size_t key_count = common_hal_keypad_keys_get_key_count(self);
supervisor_acquire_lock(&keypad_scanners_linked_list_lock);
memset(self->previously_pressed, false, key_count);
memset(self->currently_pressed, false, key_count);
supervisor_release_lock(&keypad_scanners_linked_list_lock);
}
void keypad_keys_scan(keypad_keys_obj_t *self) {
uint64_t now = port_get_raw_ticks(NULL);
if (now - self->last_scan_ticks < self->interval_ticks) {
// Too soon. Wait longer to debounce.
return;
}
self->last_scan_ticks = now;
const size_t key_count = common_hal_keypad_keys_get_key_count(self);
for (mp_uint_t key_number = 0; key_number < key_count; key_number++) {
// Remember the previous up/down state.
const bool previous = self->currently_pressed[key_number];
self->previously_pressed[key_number] = previous;
// Get the current state.
const bool current =
common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_number]) ==
self->value_when_pressed;
self->currently_pressed[key_number] = current;
// Record any transitions.
if (previous != current) {
keypad_eventqueue_record(self->events, key_number, current);
}
}
}

View File

@ -0,0 +1,52 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H
#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H
#include "py/obj.h"
#include "py/objtuple.h"
#include "common-hal/digitalio/DigitalInOut.h"
#include "shared-module/keypad/__init__.h"
#include "shared-module/keypad/EventQueue.h"
typedef struct {
mp_obj_base_t base;
// All scanners have a next field here, to keep a linked list of active scanners.
keypad_scanner_obj_t *next;
mp_obj_tuple_t *digitalinouts;
mp_uint_t interval_ticks;
uint64_t last_scan_ticks;
bool *previously_pressed;
bool *currently_pressed;
keypad_eventqueue_obj_t *events;
bool value_when_pressed;
} keypad_keys_obj_t;
void keypad_keys_scan(keypad_keys_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H

View File

@ -0,0 +1,156 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
#include "py/gc.h"
#include "py/runtime.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "shared-bindings/keypad/EventQueue.h"
#include "shared-bindings/keypad/ShiftRegisterKeys.h"
#include "shared-bindings/keypad/__init__.h"
#include "supervisor/port.h"
#include "supervisor/shared/tick.h"
void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events) {
digitalio_digitalinout_obj_t *clock = m_new_obj(digitalio_digitalinout_obj_t);
clock->base.type = &digitalio_digitalinout_type;
common_hal_digitalio_digitalinout_construct(clock, clock_pin);
common_hal_digitalio_digitalinout_switch_to_output(clock, false, DRIVE_MODE_PUSH_PULL);
self->clock = clock;
digitalio_digitalinout_obj_t *data = m_new_obj(digitalio_digitalinout_obj_t);
data->base.type = &digitalio_digitalinout_type;
common_hal_digitalio_digitalinout_construct(data, data_pin);
common_hal_digitalio_digitalinout_switch_to_input(data, PULL_NONE);
self->data = data;
digitalio_digitalinout_obj_t *latch = m_new_obj(digitalio_digitalinout_obj_t);
latch->base.type = &digitalio_digitalinout_type;
common_hal_digitalio_digitalinout_construct(latch, latch_pin);
common_hal_digitalio_digitalinout_switch_to_output(latch, true, DRIVE_MODE_PUSH_PULL);
self->latch = latch;
self->value_to_latch = value_to_latch;
self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * key_count, false, false);
self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * key_count, false, false);
self->value_when_pressed = value_when_pressed;
self->key_count = key_count;
self->interval_ticks = (mp_uint_t)(interval * 1024); // interval * 1000 * (1024/1000)
self->last_scan_ticks = port_get_raw_ticks(NULL);
keypad_eventqueue_obj_t *events = m_new_obj(keypad_eventqueue_obj_t);
events->base.type = &keypad_eventqueue_type;
common_hal_keypad_eventqueue_construct(events, max_events);
self->events = events;
// Add self to the list of active keypad scanners.
keypad_register_scanner((keypad_scanner_obj_t *)self);
supervisor_enable_tick();
}
void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self) {
if (common_hal_keypad_shiftregisterkeys_deinited(self)) {
return;
}
// Remove self from the list of active keypad scanners first.
keypad_deregister_scanner((keypad_scanner_obj_t *)self);
common_hal_digitalio_digitalinout_deinit(self->clock);
self->clock = MP_ROM_NONE;
common_hal_digitalio_digitalinout_deinit(self->data);
self->data = MP_ROM_NONE;
common_hal_digitalio_digitalinout_deinit(self->latch);
self->latch = MP_ROM_NONE;
}
bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t *self) {
return self->clock == MP_ROM_NONE;
}
size_t common_hal_keypad_shiftregisterkeys_get_key_count(keypad_shiftregisterkeys_obj_t *self) {
return self->key_count;
}
mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys_obj_t *self) {
return MP_OBJ_FROM_PTR(self->events);
}
void common_hal_keypad_shiftregisterkeys_reset(keypad_shiftregisterkeys_obj_t *self) {
const size_t key_count = common_hal_keypad_shiftregisterkeys_get_key_count(self);
supervisor_acquire_lock(&keypad_scanners_linked_list_lock);
memset(self->previously_pressed, false, key_count);
memset(self->currently_pressed, false, key_count);
supervisor_release_lock(&keypad_scanners_linked_list_lock);
}
void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self) {
uint64_t now = port_get_raw_ticks(NULL);
if (now - self->last_scan_ticks < self->interval_ticks) {
// Too soon. Wait longer to debounce.
return;
}
self->last_scan_ticks = now;
// Latch (freeze) the current state of the input pins.
common_hal_digitalio_digitalinout_set_value(self->latch, self->value_to_latch);
const size_t key_count = common_hal_keypad_shiftregisterkeys_get_key_count(self);
for (mp_uint_t key_number = 0; key_number < key_count; key_number++) {
// Zero-th data appears on on the data pin immediately, without shifting.
common_hal_digitalio_digitalinout_set_value(self->clock, false);
// Remember the previous up/down state.
const bool previous = self->currently_pressed[key_number];
self->previously_pressed[key_number] = previous;
// Get the current state.
const bool current =
common_hal_digitalio_digitalinout_get_value(self->data) == self->value_when_pressed;
self->currently_pressed[key_number] = current;
// Trigger a shift to get the next bit.
common_hal_digitalio_digitalinout_set_value(self->clock, true);
// Record any transitions.
if (previous != current) {
keypad_eventqueue_record(self->events, key_number, current);
}
}
// Start reading the input pins again.
common_hal_digitalio_digitalinout_set_value(self->latch, !self->value_to_latch);
}

View File

@ -0,0 +1,56 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_SHIFTREGISTERKEYS_H
#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_SHIFTREGISTERKEYS_H
#include "py/obj.h"
#include "py/objtuple.h"
#include "common-hal/digitalio/DigitalInOut.h"
#include "shared-module/keypad/__init__.h"
#include "shared-module/keypad/EventQueue.h"
typedef struct {
mp_obj_base_t base;
// All scanners have a next field here, to keep a linked list of active scanners.
keypad_scanner_obj_t *next;
digitalio_digitalinout_obj_t *clock;
digitalio_digitalinout_obj_t *data;
digitalio_digitalinout_obj_t *latch;
size_t key_count;
mp_uint_t interval_ticks;
uint64_t last_scan_ticks;
bool *previously_pressed;
bool *currently_pressed;
keypad_eventqueue_obj_t *events;
bool value_when_pressed;
bool value_to_latch;
} keypad_shiftregisterkeys_obj_t;
void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_SHIFTREGISTERKEYS_H

View File

@ -0,0 +1,96 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shared-bindings/keypad/Keys.h"
#include "shared-bindings/keypad/KeyMatrix.h"
#include "shared-bindings/keypad/ShiftRegisterKeys.h"
#include "supervisor/shared/lock.h"
#include "supervisor/shared/tick.h"
supervisor_lock_t keypad_scanners_linked_list_lock;
void keypad_tick(void) {
// Fast path. Return immediately there are no scanners.
if (!MP_STATE_VM(keypad_scanners_linked_list)) {
return;
}
// Skip scanning if someone else has the lock. Don't wait for the lock.
if (supervisor_try_lock(&keypad_scanners_linked_list_lock)) {
mp_obj_t scanner = MP_STATE_VM(keypad_scanners_linked_list);
while (scanner) {
if (mp_obj_is_type(scanner, &keypad_keys_type)) {
keypad_keys_scan((keypad_keys_obj_t *)scanner);
} else if (mp_obj_is_type(scanner, &keypad_keymatrix_type)) {
keypad_keymatrix_scan((keypad_keymatrix_obj_t *)scanner);
} else if (mp_obj_is_type(scanner, &keypad_shiftregisterkeys_type)) {
keypad_shiftregisterkeys_scan((keypad_shiftregisterkeys_obj_t *)scanner);
}
scanner = ((keypad_scanner_obj_t *)scanner)->next;
}
supervisor_release_lock(&keypad_scanners_linked_list_lock);
}
}
void keypad_reset(void) {
if (MP_STATE_VM(keypad_scanners_linked_list)) {
supervisor_disable_tick();
}
MP_STATE_VM(keypad_scanners_linked_list) = NULL;
keypad_scanners_linked_list_lock = false;
}
// Register a Keys, KeyMatrix, etc. that will be scanned in the background
void keypad_register_scanner(keypad_scanner_obj_t *scanner) {
supervisor_acquire_lock(&keypad_scanners_linked_list_lock);
scanner->next = MP_STATE_VM(keypad_scanners_linked_list);
MP_STATE_VM(keypad_scanners_linked_list) = scanner;
supervisor_release_lock(&keypad_scanners_linked_list_lock);
}
// Remove scanner from the list of active scanners.
void keypad_deregister_scanner(keypad_scanner_obj_t *scanner) {
supervisor_acquire_lock(&keypad_scanners_linked_list_lock);
if (MP_STATE_VM(keypad_scanners_linked_list) == scanner) {
// Scanner is at the front; splice it out.
MP_STATE_VM(keypad_scanners_linked_list) = scanner->next;
scanner->next = NULL;
} else {
keypad_scanner_obj_t *current = MP_STATE_VM(keypad_scanners_linked_list);
while (current) {
if (current->next == scanner) {
// Splice myself out.
current->next = scanner->next;
scanner->next = NULL;
break;
}
current = current->next;
}
}
supervisor_release_lock(&keypad_scanners_linked_list_lock);
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SHARED_MODULE_KEYPAD_H
#define SHARED_MODULE_KEYPAD_H
#include "py/obj.h"
#include "supervisor/shared/lock.h"
// All scanners must have a next field immediately following base.
// This is an ad hoc "superclass" struct for scanners, though they do
// not actually have a superclass relationship.
typedef struct _keypad_scanner_obj_t {
mp_obj_base_t base;
struct _keypad_scanner_obj_t *next;
} keypad_scanner_obj_t;
extern supervisor_lock_t keypad_scanners_linked_list_lock;
void keypad_tick(void);
void keypad_reset(void);
void keypad_register_scanner(keypad_scanner_obj_t *scanner);
void keypad_deregister_scanner(keypad_scanner_obj_t *scanner);
#endif // SHARED_MODULE_KEYPAD_H

51
supervisor/shared/lock.c Normal file
View File

@ -0,0 +1,51 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shared-bindings/microcontroller/__init__.h"
#include "supervisor/shared/lock.h"
void supervisor_acquire_lock(supervisor_lock_t *lock) {
while (!supervisor_try_lock(lock)) {
RUN_BACKGROUND_TASKS;
}
}
bool supervisor_try_lock(supervisor_lock_t *lock) {
bool grabbed_lock = false;
common_hal_mcu_disable_interrupts();
if (!*lock) {
*lock = true;
grabbed_lock = true;
}
common_hal_mcu_enable_interrupts();
return grabbed_lock;
}
void supervisor_release_lock(supervisor_lock_t *lock) {
common_hal_mcu_disable_interrupts();
*lock = false;
common_hal_mcu_enable_interrupts();
}

36
supervisor/shared/lock.h Normal file
View File

@ -0,0 +1,36 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SUPERVISOR_LOCK_H
#define MICROPY_INCLUDED_SUPERVISOR_LOCK_H
typedef volatile bool supervisor_lock_t;
void supervisor_acquire_lock(supervisor_lock_t *lock);
bool supervisor_try_lock(supervisor_lock_t *lock);
void supervisor_release_lock(supervisor_lock_t *lock);
#endif // MICROPY_INCLUDED_SUPERVISOR_LOCK_H

View File

@ -53,6 +53,10 @@
#include "shared-module/gamepadshift/__init__.h"
#endif
#if CIRCUITPY_KEYPAD
#include "shared-module/keypad/__init__.h"
#endif
#if CIRCUITPY_NETWORK
#include "shared-module/network/__init__.h"
#endif
@ -108,9 +112,11 @@ void supervisor_tick(void) {
#if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0
filesystem_tick();
#endif
#ifdef CIRCUITPY_AUTORELOAD_DELAY_MS
autoreload_tick();
#endif
#ifdef CIRCUITPY_GAMEPAD_TICKS
if (!(port_get_raw_ticks(NULL) & CIRCUITPY_GAMEPAD_TICKS)) {
#if CIRCUITPY_GAMEPAD
@ -121,6 +127,11 @@ void supervisor_tick(void) {
#endif
}
#endif
#if CIRCUITPY_KEYPAD
keypad_tick();
#endif
background_callback_add(&tick_callback, supervisor_background_tasks, NULL);
}

View File

@ -7,7 +7,8 @@ SRC_SUPERVISOR = \
supervisor/shared/cpu.c \
supervisor/shared/filesystem.c \
supervisor/shared/flash.c \
supervisor/shared/memory.c \
supervisor/shared/lock.c \
supervisor/shared/memory.c \
supervisor/shared/micropython.c \
supervisor/shared/safe_mode.c \
supervisor/shared/stack.c \