fix(kscan): kscan round robin matrix is now functional

This commit is contained in:
down 2022-07-19 00:56:54 +07:00
parent 405192e164
commit 223e202477
2 changed files with 93 additions and 27 deletions

View file

@ -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

View file

@ -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);