Working version

This commit is contained in:
Philip Gladstone 2024-02-04 12:43:43 -05:00
parent 92f507562e
commit c3300a8fbb
2 changed files with 30 additions and 49 deletions

View File

@ -7,7 +7,7 @@
* Then we disable all the columns and then drive each column low in turn. Hopefully * 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. * 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. * 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. * If no key is pressed, run timer again. On timer expiry, re-enable interrupts.
* *
* Philip Gladstone, N1DQ * Philip Gladstone, N1DQ
@ -21,14 +21,8 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "driver/gpio.h" #include "driver/gpio.h"
#define M_DEBUG printf
#define MATRIX_PRESS_INDEX 0 #define MATRIX_PRESS_INDEX 0
#define MATRIX_RELEASE_INDEX 1 #define MATRIX_RELEASE_INDEX 1
@ -65,7 +59,6 @@ typedef struct {
uint32_t write_offset; // Accessed by ISR uint32_t write_offset; // Accessed by ISR
uint8_t last_character; uint8_t last_character;
matrix_event_t queue[QUEUE_SIZE]; matrix_event_t queue[QUEUE_SIZE];
void *callback_arg;
} DATA; } DATA;
static task_handle_t tasknumber; static task_handle_t tasknumber;
@ -93,24 +86,24 @@ static void lmatrix_timer_done(void *param);
d->read_offset++; \ 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, gpio_config_t config = {.pin_bit_mask = 1LL << pin,
.mode = GPIO_MODE_INPUT, .mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE, .pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = intr}; .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, gpio_config_t config = {.pin_bit_mask = 1LL << pin,
.mode = GPIO_MODE_OUTPUT_OD, .mode = GPIO_MODE_OUTPUT_OD,
.pull_up_en = GPIO_PULLUP_DISABLE, .pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE .pull_down_en = GPIO_PULLDOWN_DISABLE
}; };
gpio_config(&config); return gpio_config(&config);
} }
static void set_columns(DATA *d, int level) { 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++) { 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); set_columns(d, 0);
for (int i = 0; i < d->row_count; i++) { 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. // Just takes the channel number. Cleans up the resources used.
int matrix_close(DATA *d) { static int matrix_close(DATA *d) {
if (!d) { if (!d) {
return 0; return 0;
} }
@ -157,7 +154,7 @@ int matrix_close(DATA *d) {
} }
// Character returned is 0 .. max if pressed. -1 if not. // 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); set_columns(d, 1);
disable_row_interrupts(d); 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 // We are either waiting for a negative edge (keypress) or a positive edge
// (keyrelease) // (keyrelease)
//M_DEBUG("matrix_get_character called\n");
for (int i = 0; i < d->column_count && character < 0; i++) { for (int i = 0; i < d->column_count && character < 0; i++) {
gpio_set_level(d->columns[i], 0); gpio_set_level(d->columns[i], 0);
for (int j = 0; j < d->row_count && character < 0; j++) { for (int j = 0; j < d->row_count && character < 0; j++) {
if (gpio_get_level(d->rows[j]) == 0) { if (gpio_get_level(d->rows[j]) == 0) {
if (trace) {
//M_DEBUG("Found keypress at %d %d\n", i, j);
}
// We found a keypress // We found a keypress
character = j * d->column_count + i; 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); gpio_set_level(d->columns[i], 1);
} }
//M_DEBUG("returning %d\n", character);
return character; return character;
} }
static void matrix_queue_character(DATA *d, int character) static void matrix_queue_character(DATA *d, int character)
{ {
// If character is >= 0 then we have found the character -- so send it. // 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 ((d->state == WAITING_FOR_PRESS && character >= 0) || (d->state == WAITING_FOR_RELEASE && character < 0)) {
if (character >= 0) { if (character >= 0) {
@ -218,7 +207,7 @@ static void matrix_interrupt(void *arg) {
// This function runs with high priority // This function runs with high priority
DATA *d = (DATA *)arg; DATA *d = (DATA *)arg;
int character = matrix_get_character(d, false); int character = matrix_get_character(d);
matrix_queue_character(d, character); matrix_queue_character(d, character);
@ -226,7 +215,7 @@ static void matrix_interrupt(void *arg) {
esp_timer_start_once(d->timer_handle, 5000); 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) { if (!d) {
return false; return false;
} }
@ -321,7 +310,9 @@ static void callback_call(lua_State* L, DATA *d, int cbnum, int key, uint32_t ti
if (d) { if (d) {
lua_rawgeti(L, LUA_REGISTRYINDEX, d->character_ref); lua_rawgeti(L, LUA_REGISTRYINDEX, d->character_ref);
lua_rawgeti(L, -1, key); 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); 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}) // Lua: setup({cols}, {rows}, {characters})
static int lmatrix_setup( lua_State* L ) static int lmatrix_setup( lua_State* L )
{ {
// Get the sizes of the first two tables
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
luaL_checktype(L, 2, LUA_TTABLE); luaL_checktype(L, 2, LUA_TTABLE);
luaL_checktype(L, 3, 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 columns = lua_rawlen(L, 1);
size_t rows = lua_rawlen(L, 2); size_t rows = lua_rawlen(L, 2);
if (columns > 255 || rows > 255) { if (columns > 255 || rows > 255 || !rows || !columns) {
return luaL_error(L, "Too many rows or columns"); return luaL_error(L, "Number of rows or columns out of range");
} }
DATA *d = (DATA *)lua_newuserdata(L, sizeof(DATA) + rows + columns); DATA *d = (DATA *)lua_newuserdata(L, sizeof(DATA) + rows + columns);
@ -368,6 +359,8 @@ static int lmatrix_setup( lua_State* L )
.arg = d .arg = d
}; };
d->open = true;
esp_timer_create(&timer_args, &d->timer_handle); esp_timer_create(&timer_args, &d->timer_handle);
for (int i = 0; i < CALLBACK_COUNT; i++) { for (int i = 0; i < CALLBACK_COUNT; i++) {
@ -378,12 +371,10 @@ static int lmatrix_setup( lua_State* L )
lua_pushvalue(L, 3); lua_pushvalue(L, 3);
d->character_ref = luaL_ref(L, LUA_REGISTRYINDEX); d->character_ref = luaL_ref(L, LUA_REGISTRYINDEX);
d->open = true;
for (int i = 0; i < d->row_count; i++) { for (int i = 0; i < d->row_count; i++) {
gpio_isr_handler_add(d->rows[i], matrix_interrupt, d); gpio_isr_handler_add(d->rows[i], matrix_interrupt, d);
} }
initialize_pins(d); initialize_pins(L, d);
return 1; 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 // We need to see if the key is still pressed, and if so, enable rising edge interrupts
int character = matrix_get_character(d, true); int character = matrix_get_character(d);
//M_DEBUG("Timer fired with character %d (waiting for release %d)\n", character, d->state);
matrix_queue_character(d, character); matrix_queue_character(d, character);
@ -468,8 +457,6 @@ static void lmatrix_timer_done(void *param)
d->state = WAITING_FOR_PRESS; d->state = WAITING_FOR_PRESS;
} }
//M_DEBUG("Timer: Waiting for release is %d\n", d->state);
if (d->state == WAITING_FOR_PRESS) { if (d->state == WAITING_FOR_PRESS) {
for (int i = 0; i < d->row_count; i++) { for (int i = 0; i < d->row_count; i++) {
gpio_set_intr_type(d->rows[i], GPIO_INTR_NEGEDGE); 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; (void) prio;
//M_DEBUG("Task invoked\n");
bool need_to_post = false; bool need_to_post = false;
lua_State *L = lua_getstate(); 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 // If there is pending stuff, queue another task
task_post_medium(tasknumber, param); task_post_medium(tasknumber, param);
} }
//M_DEBUG("Task done\n");
} }

View File

@ -9,10 +9,8 @@ in all.
## Sources for parts ## 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. - Adafruit: [Matrix keypad](https://www.adafruit.com/search?q=matrix+keypad)
- 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) - Aliexpress: This [search](https://www.aliexpress.us/w/wholesale-matrix-keypad.html) reveals all sorts of shapes and sizes.
- 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.
## Constants ## Constants
- `matrix.PRESS = 1` The eventtype for a keyboard key press - `matrix.PRESS = 1` The eventtype for a keyboard key press
@ -36,7 +34,7 @@ The keyboard object.
#### Example #### 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 #### Notes
If an entry in the key characters table is nil, then that key press will not be reported. 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])` `keyboard:on(eventtype[, callback])`
#### Parameters #### 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. - `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. If the callback is None or omitted, then the registration is cancelled.