From 44b876f7693ba181c90dd813692f65e4a05266f8 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 28 May 2021 23:00:07 -0400 Subject: [PATCH] Inital keypad work: Keys working: one pin per key keypad.Buttons and keypad.State Buttons -> Keys; further work wip wip wip: compiles about to try keypad.Keys working --- locale/circuitpython.pot | 5 +- py/circuitpy_defns.mk | 12 +- py/circuitpy_mpconfig.h | 24 ++-- py/circuitpy_mpconfig.mk | 9 +- shared-bindings/keypad/Keys.c | 175 ++++++++++++++++++++++++++++++ shared-bindings/keypad/Keys.h | 41 +++++++ shared-bindings/keypad/State.c | 75 +++++++++++++ shared-bindings/keypad/State.h | 44 ++++++++ shared-bindings/keypad/__init__.c | 53 +++++++++ shared-bindings/keypad/__init__.h | 41 +++++++ shared-module/keypad/Keys.c | 127 ++++++++++++++++++++++ shared-module/keypad/Keys.h | 44 ++++++++ shared-module/keypad/State.c | 0 shared-module/keypad/__init__.c | 0 shared-module/keypad/__init__.h | 30 +++++ 15 files changed, 664 insertions(+), 16 deletions(-) create mode 100644 shared-bindings/keypad/Keys.c create mode 100644 shared-bindings/keypad/Keys.h create mode 100644 shared-bindings/keypad/State.c create mode 100644 shared-bindings/keypad/State.h create mode 100644 shared-bindings/keypad/__init__.c create mode 100644 shared-bindings/keypad/__init__.h create mode 100644 shared-module/keypad/Keys.c create mode 100644 shared-module/keypad/Keys.h create mode 100644 shared-module/keypad/State.c create mode 100644 shared-module/keypad/__init__.c create mode 100644 shared-module/keypad/__init__.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index fbb6402051..f80bfd4eb3 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -116,7 +116,7 @@ msgid "%q must be a tuple of length 2" msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: shared-bindings/canio/Match.c +#: shared-bindings/canio/Match.c shared-bindings/keypad/Keys.c msgid "%q out of range" msgstr "" @@ -905,7 +905,8 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c py/enum.c #: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c -#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c +#: shared-bindings/busio/SPI.c shared-bindings/keypad/Keys.c +#: shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 41f8d71abd..6b3dd7f17a 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -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,9 @@ SRC_SHARED_MODULE_ALL = \ framebufferio/__init__.c \ ipaddress/IPv4Address.c \ ipaddress/__init__.c \ + keypad/__init__.c \ + keypad/Keys.c \ + keypad/State.c \ sdcardio/SDCard.c \ sdcardio/__init__.c \ gamepad/GamePad.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index c71cad6aeb..21c91bfac6 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -439,6 +439,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 }, @@ -522,6 +529,13 @@ 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 }, +#else +#define KEYPAD_MODULE +#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 }, @@ -529,13 +543,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 }, @@ -876,6 +883,7 @@ extern const struct _mp_obj_module_t msgpack_module; VECTORIO_MODULE \ ERRNO_MODULE \ ESPIDF_MODULE \ + _EVE_MODULE \ FRAMEBUFFERIO_MODULE \ FREQUENCYIO_MODULE \ GAMEPAD_MODULE \ @@ -885,8 +893,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 \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 077470d936..9c9e84321e 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -178,6 +178,9 @@ 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) @@ -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) diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c new file mode 100644 index 0000000000..118328abe9 --- /dev/null +++ b/shared-bindings/keypad/Keys.c @@ -0,0 +1,175 @@ +/* + * 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/enum.h" +#include "py/objproperty.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/State.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "py/runtime.h" + +//| class Keys: +//| """Manage a set of independent keys.""" +//| +//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True) -> 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. +//| +//| :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. +//| +//| Calls `scan()` once before returning, to initialize internal state. +//| """ +//| ... + +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 }; + 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_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; + const mp_uint_t num_pins = mp_obj_int_get_uint_checked(mp_obj_len(pins)); + const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; + + 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); + return MP_OBJ_FROM_PTR(self); +} + +//| def scan(self) -> None: +//| """Scan the keys and record which are newly pressed, still pressed, +//| newly released, and still released. For convenient activity checking, +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_scan(mp_obj_t self_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_keypad_keys_scan(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_scan_obj, keypad_keys_scan); + +//| def state(self, key_num: int) -> keypad.State: +//| """Return the state for the given ``key_num``, based +//| on the results of the most recent `scan()`. +//| +//| :param int key_num: Key number: corresponds to the sequence of pins +//| :return: state of key number ``key_num`` +//| :rtype: keypad.State: One of `State.JUST_PRESSED`, `State.STILL_PRESSED`, +//| `State.JUST_RELEASED`, or `State.STILL_RELEASED`. +//| The inclusive states `State.PRESSED` and `State.RELEASED` will *not* be returned. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_state(mp_obj_t self_in, mp_obj_t key_num_obj) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t key_num = mp_obj_int_get_checked(key_num_obj); + if (key_num < 0 || key_num >= common_hal_keypad_keys_length(self)) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); + } + + return cp_enum_find(&keypad_state_type, common_hal_keypad_keys_state(self, (mp_uint_t)key_num)); +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_state_obj, keypad_keys_state); + +//| def keys_with_state(self, state: State, into_list: List[Optional[int]]) -> None: +//| """Store key numbers of keys with state ``state`` in ``into_list``. +//| The states checked are based on the results of the most recent `scan()`. +//| +//| You can use the inclusive states `State.PRESSED` and `State.RELEASED`. +//| `State.PRESSED` includes states `State.JUST_PRESSED` and `State.STILL_PRESSED`. +//| `State.RELEASED` includes `State.JUST_RELEASED` and `State.STILL_RELEASED`. +//| +//| The key numbers are stored in ``into_list`` consecutively, up to ``len(into_list)``. +//| The ``into_list`` is not extended if there are more keys with the given +//| state than list slots. Instead, leftover key numbers are discarded. +//| If there are fewer keys with the given state, the rest of ``into_list`` +//| is padded with ``None``. For example, +//| if four keys are being monitored, and only key numbers 0 and 2 have the given state, +//| ``into_list`` will be set to ``[0, 2, None, None]``. You can iterate over +//| ``into_list`` and stop when you find the first ``None``. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_keys_with_state(mp_obj_t self_in, mp_obj_t state_in, mp_obj_t into_list_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (!mp_obj_is_type(state_in, &keypad_state_type)) { + mp_raise_ValueError_varg(translate("Expected a %q"), keypad_state_type.name); + } + + if (!mp_obj_is_type(into_list_in, &mp_type_list)) { + mp_raise_ValueError_varg(translate("Expected a %q"), mp_type_list.name); + } + + int state = cp_enum_value(&keypad_state_type, state_in); + mp_obj_list_t *into_list = MP_OBJ_TO_PTR(into_list_in); + + common_hal_keypad_keys_keys_with_state(self, state, into_list); + + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_3(keypad_keys_keys_with_state_obj, keypad_keys_keys_with_state); + +STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_keys_with_state), MP_ROM_PTR(&keypad_keys_keys_with_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&keypad_keys_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&keypad_keys_state_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, +}; diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h new file mode 100644 index 0000000000..f7d33a78c1 --- /dev/null +++ b/shared-bindings/keypad/Keys.h @@ -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_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); +void common_hal_keypad_keys_keys_with_state(keypad_keys_obj_t *self, mp_int_t state, mp_obj_list_t *into); +size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self); +void common_hal_keypad_keys_scan(keypad_keys_obj_t *self); +mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-bindings/keypad/State.c b/shared-bindings/keypad/State.c new file mode 100644 index 0000000000..8e35d09a83 --- /dev/null +++ b/shared-bindings/keypad/State.c @@ -0,0 +1,75 @@ +/* + * 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/enum.h" + +#include "shared-bindings/keypad/State.h" + +// Defines enum values like +// const cp_enum_obj_t state_JUST_PRESSED = ... +MAKE_ENUM_VALUE(keypad_state_type, state, JUST_PRESSED, STATE_JUST_PRESSED); +MAKE_ENUM_VALUE(keypad_state_type, state, STILL_PRESSED, STATE_STILL_PRESSED); +MAKE_ENUM_VALUE(keypad_state_type, state, PRESSED, STATE_PRESSED); +MAKE_ENUM_VALUE(keypad_state_type, state, JUST_RELEASED, STATE_JUST_RELEASED); +MAKE_ENUM_VALUE(keypad_state_type, state, STILL_RELEASED, STATE_STILL_RELEASED); +MAKE_ENUM_VALUE(keypad_state_type, state, RELEASED, STATE_RELEASED); + +//| class State: +//| """The state of a key, based on the last call to ``scan()``.""" +//| +//| JUST_PRESSED: State +//| """The key transitioned from released to pressed.""" +//| +//| STILL_PRESSED: State +//| """The key was already pressed, and continues to be pressed.""" +//| +//| PRESSED: State +//| """The key is now pressed. Used to indicate states `JUST_PRESSED` and `STILL_PRESSED` inclusively.""" +//| +//| JUST_RELEASED: State +//| """The key transitioned from pressed to released.""" +//| +//| STILL_RELEASED: State +//| """The key was already released, and continues to be released.""" +//| +//| RELEASED: State +//| """The key is now released. Used to indicate states `JUST_RELEASED` and `STILL_RELEASED` inclusively.""" +//| +MAKE_ENUM_MAP(keypad_state) { + MAKE_ENUM_MAP_ENTRY(state, JUST_PRESSED), + MAKE_ENUM_MAP_ENTRY(state, STILL_PRESSED), + MAKE_ENUM_MAP_ENTRY(state, PRESSED), + MAKE_ENUM_MAP_ENTRY(state, JUST_RELEASED), + MAKE_ENUM_MAP_ENTRY(state, STILL_RELEASED), + MAKE_ENUM_MAP_ENTRY(state, RELEASED), +}; +STATIC MP_DEFINE_CONST_DICT(keypad_state_locals_dict, keypad_state_locals_table); + +MAKE_PRINTER(keypad, keypad_state); + +// Defines keypad_state_type. +MAKE_ENUM_TYPE(keypad, State, keypad_state); diff --git a/shared-bindings/keypad/State.h b/shared-bindings/keypad/State.h new file mode 100644 index 0000000000..1b6316b001 --- /dev/null +++ b/shared-bindings/keypad/State.h @@ -0,0 +1,44 @@ +/* + * 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_STATE__H +#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H + +#include "py/obj.h" +#include "py/enum.h" + +typedef enum { + STATE_JUST_PRESSED, + STATE_STILL_PRESSED, + STATE_PRESSED, + STATE_JUST_RELEASED, + STATE_STILL_RELEASED, + STATE_RELEASED, +} keypad_state_t; + +extern const mp_obj_type_t keypad_state_type; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H diff --git a/shared-bindings/keypad/__init__.c b/shared-bindings/keypad/__init__.c new file mode 100644 index 0000000000..4ca66b531a --- /dev/null +++ b/shared-bindings/keypad/__init__.c @@ -0,0 +1,53 @@ +/* + * 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/KeyMatrix.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/State.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, 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_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_key_matrix_type) }, + { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) }, + { MP_ROM_QSTR(MP_QSTR_State), MP_OBJ_FROM_PTR(&keypad_state_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, +}; diff --git a/shared-bindings/keypad/__init__.h b/shared-bindings/keypad/__init__.h new file mode 100644 index 0000000000..5e484dc5ed --- /dev/null +++ b/shared-bindings/keypad/__init__.h @@ -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 diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c new file mode 100644 index 0000000000..ca1dca42ef --- /dev/null +++ b/shared-module/keypad/Keys.c @@ -0,0 +1,127 @@ +/* + * 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/gc.h" +#include "py/objproperty.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/State.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "py/runtime.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_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; + +} + +void common_hal_keypad_keys_keys_with_state(keypad_keys_obj_t *self, int state, mp_obj_list_t *list_into) { + const size_t list_length = list_into->len; + + size_t next_list_slot = 0; + + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { + if (next_list_slot >= list_length) { + // List is full. + break; + } + + bool store_key = false; + switch (state) { + case STATE_JUST_PRESSED: + store_key = !self->previously_pressed[key_num] && self->currently_pressed[key_num]; + break; + case STATE_STILL_PRESSED: + store_key = self->previously_pressed[key_num] && self->currently_pressed[key_num]; + break; + case STATE_PRESSED: + store_key = self->currently_pressed[key_num]; + break; + case STATE_JUST_RELEASED: + store_key = self->previously_pressed[key_num] && !self->currently_pressed[key_num]; + break; + case STATE_STILL_RELEASED: + store_key = !self->previously_pressed[key_num] && !self->currently_pressed[key_num]; + break; + case STATE_RELEASED: + store_key = !self->currently_pressed[key_num]; + break; + } + + if (store_key) { + mp_obj_list_store(list_into, MP_OBJ_NEW_SMALL_INT(next_list_slot), + MP_OBJ_NEW_SMALL_INT(key_num)); + next_list_slot++; + } + + for (size_t unused_slot = next_list_slot; unused_slot < list_length; unused_slot++) { + mp_obj_list_store(list_into, MP_OBJ_NEW_SMALL_INT(unused_slot), + MP_ROM_NONE); + } + } +} + +size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self) { + return self->digitalinouts->len; +} + +void common_hal_keypad_keys_scan(keypad_keys_obj_t *self) { + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { + self->previously_pressed[key_num] = self->currently_pressed[key_num]; + self->currently_pressed[key_num] = + common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == + self->value_when_pressed; + } +} + +mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num) { + if (self->currently_pressed[key_num]) { + if (self->previously_pressed[key_num]) { + return STATE_STILL_PRESSED; + } else { + return STATE_JUST_PRESSED; + } + } else { + if (self->previously_pressed[key_num]) { + return STATE_JUST_RELEASED; + } else { + return STATE_STILL_RELEASED; + } + } +} diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h new file mode 100644 index 0000000000..077b981dd6 --- /dev/null +++ b/shared-module/keypad/Keys.h @@ -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_MODULE_KEYPAD_KEYS_H +#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H + +#include "common-hal/digitalio/DigitalInOut.h" + +#include "py/obj.h" +#include "py/objtuple.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_tuple_t *digitalinouts; + bool value_when_pressed; + bool *previously_pressed; + bool *currently_pressed; +} keypad_keys_obj_t; + + +#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H diff --git a/shared-module/keypad/State.c b/shared-module/keypad/State.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/keypad/__init__.c b/shared-module/keypad/__init__.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/keypad/__init__.h b/shared-module/keypad/__init__.h new file mode 100644 index 0000000000..4220a3df63 --- /dev/null +++ b/shared-module/keypad/__init__.h @@ -0,0 +1,30 @@ +/* + * 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 + +#endif // SHARED_MODULE_KEYPAD_H