From c3300a8fbb5f1994b743339ddeaa65b49d5d9156 Mon Sep 17 00:00:00 2001 From: Philip Gladstone Date: Sun, 4 Feb 2024 12:43:43 -0500 Subject: [PATCH] Working version --- components/modules/matrix.c | 69 ++++++++++++++----------------------- docs/modules/matrix.md | 10 +++--- 2 files changed, 30 insertions(+), 49 deletions(-) diff --git a/components/modules/matrix.c b/components/modules/matrix.c index 6850d12e..d0416bde 100644 --- a/components/modules/matrix.c +++ b/components/modules/matrix.c @@ -7,7 +7,7 @@ * Then we disable all the columns and then drive each column low in turn. Hopefully * one of the rows will go low. This is a keypress. We only report the first keypress found. * we start a timer to handle debounce. - * On timer expiry, see if any key is pressed, if so, just wait agin (maybe should use interrupts) + * On timer expiry, see if any key is pressed, if so, just wait again * If no key is pressed, run timer again. On timer expiry, re-enable interrupts. * * Philip Gladstone, N1DQ @@ -21,14 +21,8 @@ #include #include #include - - -#include - #include "driver/gpio.h" -#define M_DEBUG printf - #define MATRIX_PRESS_INDEX 0 #define MATRIX_RELEASE_INDEX 1 @@ -65,7 +59,6 @@ typedef struct { uint32_t write_offset; // Accessed by ISR uint8_t last_character; matrix_event_t queue[QUEUE_SIZE]; - void *callback_arg; } DATA; static task_handle_t tasknumber; @@ -93,24 +86,24 @@ static void lmatrix_timer_done(void *param); d->read_offset++; \ } -static void set_gpio_mode_input(int pin, gpio_int_type_t intr) { +static esp_err_t set_gpio_mode_input(int pin, gpio_int_type_t intr) { gpio_config_t config = {.pin_bit_mask = 1LL << pin, .mode = GPIO_MODE_INPUT, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = intr}; - gpio_config(&config); + return gpio_config(&config); } -static void set_gpio_mode_output(int pin) { +static esp_err_t set_gpio_mode_output(int pin) { gpio_config_t config = {.pin_bit_mask = 1LL << pin, .mode = GPIO_MODE_OUTPUT_OD, .pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE }; - gpio_config(&config); + return gpio_config(&config); } static void set_columns(DATA *d, int level) { @@ -119,15 +112,19 @@ static void set_columns(DATA *d, int level) { } } -static void initialize_pins(DATA *d) { +static void initialize_pins(lua_State *L, DATA *d) { for (int i = 0; i < d->column_count; i++) { - set_gpio_mode_output(d->columns[i]); + if (set_gpio_mode_output(d->columns[i]) != ESP_OK) { + luaL_error(L, "Unable to configure pins"); + } } set_columns(d, 0); for (int i = 0; i < d->row_count; i++) { - set_gpio_mode_input(d->rows[i], GPIO_INTR_NEGEDGE); + if (set_gpio_mode_input(d->rows[i], GPIO_INTR_NEGEDGE) != ESP_OK) { + luaL_error(L, "Unable to configure pins"); + } } } @@ -138,7 +135,7 @@ static void disable_row_interrupts(DATA *d) { } // Just takes the channel number. Cleans up the resources used. -int matrix_close(DATA *d) { +static int matrix_close(DATA *d) { if (!d) { return 0; } @@ -157,7 +154,7 @@ int matrix_close(DATA *d) { } // Character returned is 0 .. max if pressed. -1 if not. -static int matrix_get_character(DATA *d, bool trace) +static int matrix_get_character(DATA *d) { set_columns(d, 1); disable_row_interrupts(d); @@ -167,16 +164,11 @@ static int matrix_get_character(DATA *d, bool trace) // We are either waiting for a negative edge (keypress) or a positive edge // (keyrelease) - //M_DEBUG("matrix_get_character called\n"); - for (int i = 0; i < d->column_count && character < 0; i++) { gpio_set_level(d->columns[i], 0); for (int j = 0; j < d->row_count && character < 0; j++) { if (gpio_get_level(d->rows[j]) == 0) { - if (trace) { - //M_DEBUG("Found keypress at %d %d\n", i, j); - } // We found a keypress character = j * d->column_count + i; } @@ -185,15 +177,12 @@ static int matrix_get_character(DATA *d, bool trace) gpio_set_level(d->columns[i], 1); } - //M_DEBUG("returning %d\n", character); - return character; } static void matrix_queue_character(DATA *d, int character) { // If character is >= 0 then we have found the character -- so send it. - // M_DEBUG("Skipping queuing\n"); if ((d->state == WAITING_FOR_PRESS && character >= 0) || (d->state == WAITING_FOR_RELEASE && character < 0)) { if (character >= 0) { @@ -218,7 +207,7 @@ static void matrix_interrupt(void *arg) { // This function runs with high priority DATA *d = (DATA *)arg; - int character = matrix_get_character(d, false); + int character = matrix_get_character(d); matrix_queue_character(d, character); @@ -226,7 +215,7 @@ static void matrix_interrupt(void *arg) { esp_timer_start_once(d->timer_handle, 5000); } -bool matrix_has_queued_event(DATA *d) { +static bool matrix_has_queued_event(DATA *d) { if (!d) { return false; } @@ -321,7 +310,9 @@ static void callback_call(lua_State* L, DATA *d, int cbnum, int key, uint32_t ti if (d) { lua_rawgeti(L, LUA_REGISTRYINDEX, d->character_ref); lua_rawgeti(L, -1, key); - callback_callOne(L, d->callback[cbnum], 1 << cbnum, -1, time); + if (lua_type(L, -1) != LUA_TNIL) { + callback_callOne(L, d->callback[cbnum], 1 << cbnum, -1, time); + } lua_pop(L, 2); } } @@ -338,16 +329,16 @@ static void getpins(lua_State *L, int argno, int count, uint8_t *dest) // Lua: setup({cols}, {rows}, {characters}) static int lmatrix_setup( lua_State* L ) { - // Get the sizes of the first two tables luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 2, LUA_TTABLE); luaL_checktype(L, 3, LUA_TTABLE); + // Get the sizes of the first two tables size_t columns = lua_rawlen(L, 1); size_t rows = lua_rawlen(L, 2); - if (columns > 255 || rows > 255) { - return luaL_error(L, "Too many rows or columns"); + if (columns > 255 || rows > 255 || !rows || !columns) { + return luaL_error(L, "Number of rows or columns out of range"); } DATA *d = (DATA *)lua_newuserdata(L, sizeof(DATA) + rows + columns); @@ -368,6 +359,8 @@ static int lmatrix_setup( lua_State* L ) .arg = d }; + d->open = true; + esp_timer_create(&timer_args, &d->timer_handle); for (int i = 0; i < CALLBACK_COUNT; i++) { @@ -378,12 +371,10 @@ static int lmatrix_setup( lua_State* L ) lua_pushvalue(L, 3); d->character_ref = luaL_ref(L, LUA_REGISTRYINDEX); - d->open = true; - for (int i = 0; i < d->row_count; i++) { gpio_isr_handler_add(d->rows[i], matrix_interrupt, d); } - initialize_pins(d); + initialize_pins(L, d); return 1; } @@ -454,9 +445,7 @@ static void lmatrix_timer_done(void *param) // We need to see if the key is still pressed, and if so, enable rising edge interrupts - int character = matrix_get_character(d, true); - - //M_DEBUG("Timer fired with character %d (waiting for release %d)\n", character, d->state); + int character = matrix_get_character(d); matrix_queue_character(d, character); @@ -468,8 +457,6 @@ static void lmatrix_timer_done(void *param) d->state = WAITING_FOR_PRESS; } - //M_DEBUG("Timer: Waiting for release is %d\n", d->state); - if (d->state == WAITING_FOR_PRESS) { for (int i = 0; i < d->row_count; i++) { gpio_set_intr_type(d->rows[i], GPIO_INTR_NEGEDGE); @@ -484,8 +471,6 @@ static void lmatrix_task(task_param_t param, task_prio_t prio) { (void) prio; - //M_DEBUG("Task invoked\n"); - bool need_to_post = false; lua_State *L = lua_getstate(); @@ -500,8 +485,6 @@ static void lmatrix_task(task_param_t param, task_prio_t prio) // If there is pending stuff, queue another task task_post_medium(tasknumber, param); } - - //M_DEBUG("Task done\n"); } diff --git a/docs/modules/matrix.md b/docs/modules/matrix.md index defac1af..edf803a1 100644 --- a/docs/modules/matrix.md +++ b/docs/modules/matrix.md @@ -9,10 +9,8 @@ in all. ## Sources for parts -- Amazon: This [search](http://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Dindustrial&field-keywords=rotary+encoder+push+button&rh=n%3A16310091%2Ck%3Arotary+encoder+push+button) shows a variety. -- Ebay: Somewhat cheaper in this [search](http://www.ebay.com/sch/i.html?_from=R40&_trksid=p2050601.m570.l1313.TR0.TRC0.H0.Xrotary+encoder+push+button.TRS0&_nkw=rotary+encoder+push+button&_sacat=0) -- Adafruit: [rotary encoder](https://www.adafruit.com/products/377) -- Aliexpress: This [search](http://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20160217173657&SearchText=rotary+encoder+push+button) reveals all sorts of shapes and sizes. +- Adafruit: [Matrix keypad](https://www.adafruit.com/search?q=matrix+keypad) +- Aliexpress: This [search](https://www.aliexpress.us/w/wholesale-matrix-keypad.html) reveals all sorts of shapes and sizes. ## Constants - `matrix.PRESS = 1` The eventtype for a keyboard key press @@ -36,7 +34,7 @@ The keyboard object. #### Example - keyboard = matrix.setup({5,6,7}, {8,9,10,11}, { "1", "2", "3", "4", "5", "6", "7", "8", "9", "#", "0", "*"}) + keyboard = matrix.setup({17, 4, 18}, {16, 21, 19, 5}, { "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#"}) #### Notes If an entry in the key characters table is nil, then that key press will not be reported. @@ -48,7 +46,7 @@ Sets a callback on specific events. `keyboard:on(eventtype[, callback])` #### Parameters -- `eventtype` This defines the type of event being registered. This can be one or more of `matrix.PRESS` and `matrix.RELEASE`. +- `eventtype` This defines the type of event being registered. This can be one or more of `matrix.PRESS` and `matrix.RELEASE`. `matrix.ALL` covers all the event types. - `callback` This is a function that will be invoked when the specified event happens. If the callback is None or omitted, then the registration is cancelled.