From 223e20247752a467f2f7d070247b359b68268543 Mon Sep 17 00:00:00 2001 From: down Date: Tue, 19 Jul 2022 00:56:54 +0700 Subject: [PATCH] fix(kscan): kscan round robin matrix is now functional --- app/drivers/kscan/Kconfig | 2 +- .../kscan/kscan_gpio_round_robin_matrix.c | 118 ++++++++++++++---- 2 files changed, 93 insertions(+), 27 deletions(-) diff --git a/app/drivers/kscan/Kconfig b/app/drivers/kscan/Kconfig index 5cff73e0..5fd766c5 100644 --- a/app/drivers/kscan/Kconfig +++ b/app/drivers/kscan/Kconfig @@ -5,7 +5,7 @@ DT_COMPAT_ZMK_KSCAN_COMPOSITE := zmk,kscan-composite DT_COMPAT_ZMK_KSCAN_GPIO_DEMUX := zmk,kscan-gpio-demux DT_COMPAT_ZMK_KSCAN_GPIO_DIRECT := zmk,kscan-gpio-direct DT_COMPAT_ZMK_KSCAN_GPIO_MATRIX := zmk,kscan-gpio-matrix -DT_CONPAT_ZMK_KSCAN_GPIO_ROUND_ROBIN_MATRIX := zmk,kscan-gpio-round-robin-matrix +DT_COMPAT_ZMK_KSCAN_GPIO_ROUND_ROBIN_MATRIX := zmk,kscan-gpio-round-robin-matrix DT_COMPAT_ZMK_KSCAN_MOCK := zmk,kscan-mock config ZMK_KSCAN_COMPOSITE_DRIVER diff --git a/app/drivers/kscan/kscan_gpio_round_robin_matrix.c b/app/drivers/kscan/kscan_gpio_round_robin_matrix.c index 6c0d31ef..6eaa43e4 100644 --- a/app/drivers/kscan/kscan_gpio_round_robin_matrix.c +++ b/app/drivers/kscan/kscan_gpio_round_robin_matrix.c @@ -19,9 +19,9 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #define DT_DRV_COMPAT zmk_kscan_gpio_round_robin_matrix -#define INST_INPUT_LEN(n) DT_INST_PROP_LEN(n, input_gpios) +#define INST_INPUTS_LEN(n) DT_INST_PROP_LEN(n, input_gpios) #define INST_OUTPUTS_LEN(n) DT_INST_PROP_LEN(n, output_gpios) -#define INST_MATRIX_LEN(n) (INST_INPUT_LEN(n) * INST_OUTPUTS_LEN(n)) +#define INST_MATRIX_LEN(n) (INST_INPUTS_LEN(n) * INST_OUTPUTS_LEN(n)) #if CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS >= 0 #define INST_DEBOUNCE_PRESS_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS @@ -62,15 +62,15 @@ struct kscan_round_robin_matrix_config { struct kscan_gpio_list outputs; struct kscan_gpio_list inputs; struct debounce_config debounce_config; - int32_t poll_period_us; + int32_t poll_period_ms; }; -static int state_index_io(const struct kscan_round_robin_matrix *config, const int input_idx, +static int state_index_io(const struct kscan_round_robin_matrix_config *config, const int input_idx, const int output_idx) { __ASSERT(input_idx < config->inputs.len, "Invalid input %i", input_idx); __ASSERT(output_idx < config->outputs.len, "Invalid output %i", output_idx); - return (input_idx * config->outputs.len) + output_idx); + return ((input_idx * config->outputs.len) + output_idx); } static int kscan_round_robin_matrix_read(const struct device *dev) { @@ -81,7 +81,41 @@ static int kscan_round_robin_matrix_read(const struct device *dev) { for (int o = 0; o < len; o++) { const struct gpio_dt_spec *out_gpio = &config->outputs.gpios[o]; - int err = gpio_pin_set_dt(out_gpio, 1); + // Init output/input + if (!device_is_ready(out_gpio->port)) { + LOG_ERR("GPIO is not ready: %s", out_gpio->port->name); + return -ENODEV; + } + + // Init output + int err = gpio_pin_configure_dt(out_gpio, GPIO_OUTPUT); + if (err) { + LOG_ERR("Unable to configure pin %u on %s for output", out_gpio->pin, + out_gpio->port->name); + return err; + } + + LOG_DBG("Configured pin %u on %s for output", out_gpio->pin, out_gpio->port->name); + + // Init input + for (int i = (o + 1) % len; i != o; i = (i + 1) % len) { + const struct gpio_dt_spec *in_gpio = &config->inputs.gpios[i]; + + if (!device_is_ready(in_gpio->port)) { + LOG_ERR("GPIO is not ready: %s", in_gpio->port->name); + return -ENODEV; + } + + err = gpio_pin_configure_dt(in_gpio, GPIO_INPUT); + if (err) { + LOG_ERR("Unable to configure pin %u on %s for input", in_gpio->pin, in_gpio->port->name); + return err; + } + + LOG_DBG("Configured pin %u on %s for input", in_gpio->pin, in_gpio->port->name); + } + + err = gpio_pin_set_dt(out_gpio, 1); if (err) { LOG_ERR("Failed to set output %i active: %i", o, err); return err; @@ -94,13 +128,13 @@ static int kscan_round_robin_matrix_read(const struct device *dev) { const bool is_active = gpio_pin_get_dt(in_gpio); struct debounce_state *state = &data->matrix_state[index]; - debounce_update(state, is_active, config->debounce_scan_period_ms, + debounce_update(state, is_active, config->poll_period_ms, &config->debounce_config); if (debounce_get_changed(state)) { const bool is_pressed = debounce_is_pressed(state); - LOG_DBG("Sending event at %i,%i state %s", r, c, is_pressed ? "on" : "off"); + LOG_DBG("Sending event at %i,%i state %s", i, o, is_pressed ? "on" : "off"); data->callback(dev, i, o, is_pressed); } } @@ -121,24 +155,54 @@ static int kscan_round_robin_matrix_read(const struct device *dev) { static void kscan_matrix_work_handler(struct k_work *work) { struct k_work_delayable *dwork = CONTAINER_OF(work, struct k_work_delayable, work); - struct kscan_round_robin_matrix_data *data = CONTAINER_OF(dwork, struct kscan_round_robin_matrix_data, work); + struct kscan_round_robin_matrix_data *data = CONTAINER_OF(dwork, + struct kscan_round_robin_matrix_data, + work); kscan_round_robin_matrix_read(data->dev); } +static int kscan_matrix_configure(const struct device *dev, const kscan_callback_t callback) { + struct kscan_round_robin_matrix_data *data = dev->data; + + if (!callback) { + return -EINVAL; + } + + data->callback = callback; + return 0; +} + +static int kscan_matrix_enable(const struct device *dev) { + struct kscan_round_robin_matrix_data *data = dev->data; + + data->scan_time = k_uptime_get(); + + // Read will automatically start interrupts/polling once done. + return kscan_round_robin_matrix_read(dev); +} + +static int kscan_matrix_disable(const struct device *dev) { + struct kscan_round_robin_matrix_data *data = dev->data; + + k_work_cancel_delayable(&data->work); + + return 0; +} + static int kscan_round_robin_matrix_init(const struct device *dev) { struct kscan_round_robin_matrix_data *data = dev->data; data->dev = dev; - k_work_init_delayable(&data->work, kscan_round_robin_matrix_work_handler); + k_work_init_delayable(&data->work, kscan_matrix_work_handler); return 0; } static const struct kscan_driver_api kscan_round_robin_matrix_api = { - .config = kscan_round_robin_matrix_configure, - .enable_callback = kscan_round_robin_matrix_enable, - .disable_callback = kscan_round_robin_matrix_disable, + .config = kscan_matrix_configure, + .enable_callback = kscan_matrix_enable, + .disable_callback = kscan_matrix_disable, }; #define KSCAN_ROUND_ROBIN_MATRIX_INIT(n) \ @@ -147,29 +211,31 @@ static const struct kscan_driver_api kscan_round_robin_matrix_api = { BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(n) <= DEBOUNCE_COUNTER_MAX, \ "ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \ \ - static const struct gpio_dt_spec kscan_round_robin_matrix_outputs_##n[] = { \ - UTIL_LISTIFY(INST_OUTPUTS_LEN(n), KSCAN_GPIO_OUTPUT_CFG_INIT, n)}; \ - \ static const struct gpio_dt_spec kscan_round_robin_matrix_inputs_##n[] = { \ UTIL_LISTIFY(INST_INPUTS_LEN(n), KSCAN_GPIO_INPUT_CFG_INIT, n)}; \ \ + static const struct gpio_dt_spec kscan_round_robin_matrix_outputs_##n[] = { \ + UTIL_LISTIFY(INST_OUTPUTS_LEN(n), KSCAN_GPIO_OUTPUT_CFG_INIT, n)}; \ + \ static struct debounce_state kscan_round_robin_matrix_state_##n[INST_MATRIX_LEN(n)]; \ - \ - static struct kscan_round_robin_matrix_data kscan_round_robin_matrix_data_##n = { \ - .matrix_state = kscan_round_robin_matrix_state_##n, }; \ - \ - static struct kscan_round_robin_matrix_config kscan_round_robin_matrix_config_##n = { \ - .outputs = KSCAN_GPIO_LIST(kscan_round_robin_matrix_outputs_##n) \ - .inputs = KSCAN_GPIO_LIST(kscan_round_robin_matrix_inputs_##n) \ + \ + static struct kscan_round_robin_matrix_data kscan_round_robin_matrix_data_##n = { \ + .matrix_state = kscan_round_robin_matrix_state_##n, }; \ + \ + static struct kscan_round_robin_matrix_config kscan_round_robin_matrix_config_##n = { \ + .outputs = KSCAN_GPIO_LIST(kscan_round_robin_matrix_outputs_##n), \ + .inputs = KSCAN_GPIO_LIST(kscan_round_robin_matrix_inputs_##n), \ .debounce_config = \ { \ .debounce_press_ms = INST_DEBOUNCE_PRESS_MS(n), \ .debounce_release_ms = INST_DEBOUNCE_RELEASE_MS(n), \ }, \ .poll_period_ms = DT_INST_PROP(n, poll_period_ms), \ - }; \ - DEVICE_DT_INST_DEFINE(n, &kscan_round_robin_matrix_init, NULL, &kscan_round_robin_matrix_data_##n, \ - &kscan_round_robin_matrix_config_##n, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, \ + }; \ + DEVICE_DT_INST_DEFINE(n, &kscan_round_robin_matrix_init, NULL, \ + &kscan_round_robin_matrix_data_##n, \ + &kscan_round_robin_matrix_config_##n, \ + APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, \ &kscan_round_robin_matrix_api); DT_INST_FOREACH_STATUS_OKAY(KSCAN_ROUND_ROBIN_MATRIX_INIT);