|
| 1 | +/* |
| 2 | + * This file is part of the Micro Python project, http://micropython.org/ |
| 3 | + * |
| 4 | + * The MIT License (MIT) |
| 5 | + * |
| 6 | + * Copyright (c) 2024 CDarius |
| 7 | + * |
| 8 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 9 | + * of this software and associated documentation files (the "Software"), to deal |
| 10 | + * in the Software without restriction, including without limitation the rights |
| 11 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 12 | + * copies of the Software, and to permit persons to whom the Software is |
| 13 | + * furnished to do so, subject to the following conditions: |
| 14 | + * |
| 15 | + * The above copyright notice and this permission notice shall be included in |
| 16 | + * all copies or substantial portions of the Software. |
| 17 | + * |
| 18 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 19 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 20 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 21 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 22 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 23 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 24 | + * THE SOFTWARE. |
| 25 | + */ |
| 26 | + |
| 27 | +#include "shared/runtime/context_manager_helpers.h" |
| 28 | +#include "py/binary.h" |
| 29 | +#include "py/objproperty.h" |
| 30 | +#include "py/runtime.h" |
| 31 | +#include "shared-bindings/keypad/__init__.h" |
| 32 | +#include "shared-bindings/keypad/Event.h" |
| 33 | +#include "shared-bindings/keypad_demux/DemuxKeyMatrix.h" |
| 34 | +#include "shared-bindings/microcontroller/Pin.h" |
| 35 | +#include "shared-bindings/util.h" |
| 36 | + |
| 37 | +//| class DemuxKeyMatrix: |
| 38 | +//| """Manage Cardputer 2D matrix of keys with a demultiplexer to drive rows and pins on columns. |
| 39 | +//| |
| 40 | +//| .. raw:: html |
| 41 | +//| |
| 42 | +//| <p> |
| 43 | +//| <details> |
| 44 | +//| <summary>Available on these boards</summary> |
| 45 | +//| <ul> |
| 46 | +//| {% for board in support_matrix_reverse["keypad_demux.DemuxKeyMatrix"] %} |
| 47 | +//| <li> {{ board }} |
| 48 | +//| {% endfor %} |
| 49 | +//| </ul> |
| 50 | +//| </details> |
| 51 | +//| </p> |
| 52 | +//| |
| 53 | +//| """ |
| 54 | +//| |
| 55 | +//| def __init__( |
| 56 | +//| self, |
| 57 | +//| row_addr_pins: Sequence[microcontroller.Pin], |
| 58 | +//| column_pins: Sequence[microcontroller.Pin], |
| 59 | +//| interval: float = 0.020, |
| 60 | +//| max_events: int = 64, |
| 61 | +//| ) -> None: |
| 62 | +//| """ |
| 63 | +//| Create a `keypad.Keys` object that will scan the key matrix attached to the given row and column pins. |
| 64 | +//| There should not be any external pull-ups or pull-downs on the matrix: |
| 65 | +//| ``DemuxKeyMatrix`` enables internal pull-ups or pull-downs on the pins as necessary. |
| 66 | +//| |
| 67 | +//| The keys are numbered sequentially from zero. A key number can be computed |
| 68 | +//| by ``row * len(column_pins) + column``. |
| 69 | +//| |
| 70 | +//| An `keypad.EventQueue` is created when this object is created and is available in the `events` attribute. |
| 71 | +//| |
| 72 | +//| :param Sequence[microcontroller.Pin] row_addr_pins: The pins attached to the rows demultiplexer. |
| 73 | +//| :param Sequence[microcontroller.Pin] column_pins: The pins attached to the columns. |
| 74 | +//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing. |
| 75 | +//| ``interval`` is in float seconds. The default is 0.020 (20 msecs). |
| 76 | +//| :param int max_events: maximum size of `events` `keypad.EventQueue`: |
| 77 | +//| maximum number of key transition events that are saved. |
| 78 | +//| Must be >= 1. |
| 79 | +//| If a new event arrives when the queue is full, the oldest event is discarded. |
| 80 | +//| """ |
| 81 | +//| ... |
| 82 | + |
| 83 | +STATIC mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { |
| 84 | + keypad_demux_demuxkeymatrix_obj_t *self = mp_obj_malloc(keypad_demux_demuxkeymatrix_obj_t, &keypad_demux_demuxkeymatrix_type); |
| 85 | + enum { ARG_row_addr_pins, ARG_column_pins, ARG_interval, ARG_max_events }; |
| 86 | + static const mp_arg_t allowed_args[] = { |
| 87 | + { MP_QSTR_row_addr_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, |
| 88 | + { MP_QSTR_column_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, |
| 89 | + { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, |
| 90 | + { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, |
| 91 | + }; |
| 92 | + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
| 93 | + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
| 94 | + |
| 95 | + mp_obj_t row_addr_pins = args[ARG_row_addr_pins].u_obj; |
| 96 | + // mp_obj_len() will be >= 0. |
| 97 | + const size_t num_row_addr_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(row_addr_pins)); |
| 98 | + |
| 99 | + mp_obj_t column_pins = args[ARG_column_pins].u_obj; |
| 100 | + const size_t num_column_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(column_pins)); |
| 101 | + |
| 102 | + const mp_float_t interval = |
| 103 | + mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval); |
| 104 | + const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); |
| 105 | + |
| 106 | + const mcu_pin_obj_t *row_addr_pins_array[num_row_addr_pins]; |
| 107 | + const mcu_pin_obj_t *column_pins_array[num_column_pins]; |
| 108 | + |
| 109 | + validate_no_duplicate_pins_2(row_addr_pins, column_pins, MP_QSTR_row_addr_pins, MP_QSTR_column_pins); |
| 110 | + |
| 111 | + for (size_t row_addr = 0; row_addr < num_row_addr_pins; row_addr++) { |
| 112 | + const mcu_pin_obj_t *pin = |
| 113 | + validate_obj_is_free_pin(mp_obj_subscr(row_addr_pins, MP_OBJ_NEW_SMALL_INT(row_addr), MP_OBJ_SENTINEL), MP_QSTR_pin); |
| 114 | + row_addr_pins_array[row_addr] = pin; |
| 115 | + } |
| 116 | + |
| 117 | + for (size_t column = 0; column < num_column_pins; column++) { |
| 118 | + const mcu_pin_obj_t *pin = |
| 119 | + validate_obj_is_free_pin(mp_obj_subscr(column_pins, MP_OBJ_NEW_SMALL_INT(column), MP_OBJ_SENTINEL), MP_QSTR_pin); |
| 120 | + column_pins_array[column] = pin; |
| 121 | + } |
| 122 | + |
| 123 | + common_hal_keypad_demux_demuxkeymatrix_construct(self, num_row_addr_pins, row_addr_pins_array, num_column_pins, column_pins_array, interval, max_events); |
| 124 | + return MP_OBJ_FROM_PTR(self); |
| 125 | +} |
| 126 | + |
| 127 | +//| def deinit(self) -> None: |
| 128 | +//| """Stop scanning and release the pins.""" |
| 129 | +//| ... |
| 130 | +STATIC mp_obj_t keypad_demux_demuxkeymatrix_deinit(mp_obj_t self_in) { |
| 131 | + keypad_demux_demuxkeymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 132 | + common_hal_keypad_demux_demuxkeymatrix_deinit(self); |
| 133 | + return MP_ROM_NONE; |
| 134 | +} |
| 135 | +MP_DEFINE_CONST_FUN_OBJ_1(keypad_demux_demuxkeymatrix_deinit_obj, keypad_demux_demuxkeymatrix_deinit); |
| 136 | + |
| 137 | +//| def __enter__(self) -> DemuxKeyMatrix: |
| 138 | +//| """No-op used by Context Managers.""" |
| 139 | +//| ... |
| 140 | +// Provided by context manager helper. |
| 141 | + |
| 142 | +//| def __exit__(self) -> None: |
| 143 | +//| """Automatically deinitializes when exiting a context. See |
| 144 | +//| :ref:`lifetime-and-contextmanagers` for more info.""" |
| 145 | +//| ... |
| 146 | +STATIC mp_obj_t keypad_demux_demuxkeymatrix___exit__(size_t n_args, const mp_obj_t *args) { |
| 147 | + (void)n_args; |
| 148 | + common_hal_keypad_demux_demuxkeymatrix_deinit(args[0]); |
| 149 | + return MP_ROM_NONE; |
| 150 | +} |
| 151 | +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_demux_demuxkeymatrix___exit___obj, 4, 4, keypad_demux_demuxkeymatrix___exit__); |
| 152 | + |
| 153 | +STATIC void check_for_deinit(keypad_demux_demuxkeymatrix_obj_t *self) { |
| 154 | + if (common_hal_keypad_deinited(self)) { |
| 155 | + raise_deinited_error(); |
| 156 | + } |
| 157 | +} |
| 158 | + |
| 159 | +//| def reset(self) -> None: |
| 160 | +//| """Reset the internal state of the scanner to assume that all keys are now released. |
| 161 | +//| Any key that is already pressed at the time of this call will therefore immediately cause |
| 162 | +//| a new key-pressed event to occur. |
| 163 | +//| """ |
| 164 | +//| ... |
| 165 | + |
| 166 | +//| key_count: int |
| 167 | +//| """The number of keys that are being scanned. (read-only) |
| 168 | +//| """ |
| 169 | + |
| 170 | +//| def key_number_to_row_column(self, key_number: int) -> Tuple[int]: |
| 171 | +//| """Return the row and column for the given key number. |
| 172 | +//| The row is ``key_number // len(column_pins)``. |
| 173 | +//| The column is ``key_number % len(column_pins)``. |
| 174 | +//| |
| 175 | +//| :return: ``(row, column)`` |
| 176 | +//| :rtype: Tuple[int] |
| 177 | +//| """ |
| 178 | +//| ... |
| 179 | +STATIC mp_obj_t keypad_demux_demuxkeymatrix_key_number_to_row_column(mp_obj_t self_in, mp_obj_t key_number_in) { |
| 180 | + keypad_demux_demuxkeymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 181 | + check_for_deinit(self); |
| 182 | + |
| 183 | + const mp_uint_t key_number = (mp_uint_t)mp_arg_validate_int_range( |
| 184 | + mp_obj_get_int(key_number_in), |
| 185 | + 0, (mp_int_t)common_hal_keypad_generic_get_key_count(self), |
| 186 | + MP_QSTR_key_number); |
| 187 | + |
| 188 | + mp_uint_t row; |
| 189 | + mp_uint_t column; |
| 190 | + common_hal_keypad_demux_demuxkeymatrix_key_number_to_row_column(self, key_number, &row, &column); |
| 191 | + |
| 192 | + mp_obj_t row_column[2]; |
| 193 | + row_column[0] = MP_OBJ_NEW_SMALL_INT(row); |
| 194 | + row_column[1] = MP_OBJ_NEW_SMALL_INT(column); |
| 195 | + |
| 196 | + return mp_obj_new_tuple(2, row_column); |
| 197 | +} |
| 198 | +MP_DEFINE_CONST_FUN_OBJ_2(keypad_demux_demuxkeymatrix_key_number_to_row_column_obj, keypad_demux_demuxkeymatrix_key_number_to_row_column); |
| 199 | + |
| 200 | +//| def row_column_to_key_number(self, row: int, column: int) -> int: |
| 201 | +//| """Return the key number for a given row and column. |
| 202 | +//| The key number is ``row * len(column_pins) + column``. |
| 203 | +//| """ |
| 204 | +//| ... |
| 205 | +STATIC mp_obj_t keypad_demux_demuxkeymatrix_row_column_to_key_number(mp_obj_t self_in, mp_obj_t row_in, mp_obj_t column_in) { |
| 206 | + keypad_demux_demuxkeymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 207 | + check_for_deinit(self); |
| 208 | + |
| 209 | + const mp_uint_t row = (mp_uint_t)mp_arg_validate_int_range( |
| 210 | + mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_demux_demuxkeymatrix_get_row_count(self), MP_QSTR_row); |
| 211 | + |
| 212 | + const mp_int_t column = (mp_uint_t)mp_arg_validate_int_range( |
| 213 | + mp_obj_get_int(column_in), 0, (mp_int_t)common_hal_keypad_demux_demuxkeymatrix_get_column_count(self), MP_QSTR_column); |
| 214 | + |
| 215 | + return MP_OBJ_NEW_SMALL_INT( |
| 216 | + (mp_int_t)common_hal_keypad_demux_demuxkeymatrix_row_column_to_key_number(self, row, column)); |
| 217 | +} |
| 218 | +MP_DEFINE_CONST_FUN_OBJ_3(keypad_demux_demuxkeymatrix_row_column_to_key_number_obj, keypad_demux_demuxkeymatrix_row_column_to_key_number); |
| 219 | + |
| 220 | +//| events: keypad.EventQueue |
| 221 | +//| """The `keypad.EventQueue` associated with this `keypad.Keys` object. (read-only) |
| 222 | +//| """ |
| 223 | +//| |
| 224 | + |
| 225 | +STATIC const mp_rom_map_elem_t keypad_demux_demuxkeymatrix_locals_dict_table[] = { |
| 226 | + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_demux_demuxkeymatrix_deinit_obj) }, |
| 227 | + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, |
| 228 | + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_demux_demuxkeymatrix___exit___obj) }, |
| 229 | + |
| 230 | + { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_generic_events_obj) }, |
| 231 | + { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_generic_key_count_obj) }, |
| 232 | + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_generic_reset_obj) }, |
| 233 | + { MP_ROM_QSTR(MP_QSTR_key_number_to_row_column), MP_ROM_PTR(&keypad_demux_demuxkeymatrix_key_number_to_row_column_obj) }, |
| 234 | + { MP_ROM_QSTR(MP_QSTR_row_column_to_key_number), MP_ROM_PTR(&keypad_demux_demuxkeymatrix_row_column_to_key_number_obj) }, |
| 235 | +}; |
| 236 | + |
| 237 | +STATIC MP_DEFINE_CONST_DICT(keypad_demux_demuxkeymatrix_locals_dict, keypad_demux_demuxkeymatrix_locals_dict_table); |
| 238 | + |
| 239 | +MP_DEFINE_CONST_OBJ_TYPE( |
| 240 | + keypad_demux_demuxkeymatrix_type, |
| 241 | + MP_QSTR_DemuxKeyMatrix, |
| 242 | + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, |
| 243 | + make_new, keypad_demux_demuxkeymatrix_make_new, |
| 244 | + locals_dict, &keypad_demux_demuxkeymatrix_locals_dict |
| 245 | + ); |
0 commit comments