diff --git a/app/module/drivers/sensor/CMakeLists.txt b/app/module/drivers/sensor/CMakeLists.txt index cd1a1c45066..370fe15a617 100644 --- a/app/module/drivers/sensor/CMakeLists.txt +++ b/app/module/drivers/sensor/CMakeLists.txt @@ -4,3 +4,5 @@ add_subdirectory_ifdef(CONFIG_ZMK_BATTERY battery) add_subdirectory_ifdef(CONFIG_EC11 ec11) add_subdirectory_ifdef(CONFIG_ZMK_MAX17048 max17048) + +add_subdirectory_ifdef(CONFIG_ZMK_SENSOR_ENCODER_MOCK encoder_mock) diff --git a/app/module/drivers/sensor/Kconfig b/app/module/drivers/sensor/Kconfig index ad570c58c94..c5f4a721fb9 100644 --- a/app/module/drivers/sensor/Kconfig +++ b/app/module/drivers/sensor/Kconfig @@ -7,4 +7,6 @@ rsource "battery/Kconfig" rsource "ec11/Kconfig" rsource "max17048/Kconfig" +rsource "encoder_mock/Kconfig" + endif # SENSOR diff --git a/app/module/drivers/sensor/encoder_mock/CMakeLists.txt b/app/module/drivers/sensor/encoder_mock/CMakeLists.txt new file mode 100644 index 00000000000..8271067eaed --- /dev/null +++ b/app/module/drivers/sensor/encoder_mock/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2024 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_include_directories(.) + +zephyr_library() + +zephyr_library_sources(encoder_mock.c) \ No newline at end of file diff --git a/app/module/drivers/sensor/encoder_mock/Kconfig b/app/module/drivers/sensor/encoder_mock/Kconfig new file mode 100644 index 00000000000..9b9dd00ad05 --- /dev/null +++ b/app/module/drivers/sensor/encoder_mock/Kconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2024 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config ZMK_SENSOR_ENCODER_MOCK + bool "Mock Encoder Sensor" + default y + depends on DT_HAS_ZMK_SENSOR_ENCODER_MOCK_ENABLED diff --git a/app/module/drivers/sensor/encoder_mock/encoder_mock.c b/app/module/drivers/sensor/encoder_mock/encoder_mock.c new file mode 100644 index 00000000000..283ee916185 --- /dev/null +++ b/app/module/drivers/sensor/encoder_mock/encoder_mock.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_sensor_encoder_mock + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +struct enc_mock_config { + uint16_t startup_delay; + uint16_t event_period; + bool exit_after; + const int16_t *events; + size_t events_len; +}; + +struct enc_mock_data { + const struct sensor_trigger *trigger; + sensor_trigger_handler_t handler; + + size_t event_index; + struct k_work_delayable work; + const struct device *dev; +}; + +static void enc_mock_work_cb(struct k_work *work) { + struct k_work_delayable *dwork = CONTAINER_OF(work, struct k_work_delayable, work); + struct enc_mock_data *data = CONTAINER_OF(dwork, struct enc_mock_data, work); + + const struct device *dev = data->dev; + + data->handler(dev, data->trigger); +} + +static int enc_mock_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) { + struct enc_mock_data *drv_data = dev->data; + const struct enc_mock_config *drv_cfg = dev->config; + + drv_data->trigger = trig; + drv_data->handler = handler; + + int ret = k_work_schedule(&drv_data->work, K_MSEC(drv_cfg->startup_delay)); + if (ret < 0) { + LOG_WRN("Failed to schedule next mock sensor event %d", ret); + return ret; + } + + return 0; +} + +static int enc_mock_sample_fetch(const struct device *dev, enum sensor_channel chan) { + struct enc_mock_data *drv_data = dev->data; + const struct enc_mock_config *drv_cfg = dev->config; + + drv_data->event_index++; + + if (drv_data->event_index < drv_cfg->events_len - 1) { + k_work_schedule(&drv_data->work, K_MSEC(drv_cfg->event_period)); + } else if (drv_cfg->exit_after) { + exit(0); + } + return 0; +} + +static int enc_mock_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + struct enc_mock_data *drv_data = dev->data; + const struct enc_mock_config *drv_cfg = dev->config; + + val->val1 = drv_cfg->events[drv_data->event_index]; + + return 0; +} + +static const struct sensor_driver_api enc_mock_driver_api = { + .trigger_set = enc_mock_trigger_set, + .sample_fetch = enc_mock_sample_fetch, + .channel_get = enc_mock_channel_get, +}; + +int enc_mock_init(const struct device *dev) { + struct enc_mock_data *drv_data = dev->data; + + drv_data->dev = dev; + drv_data->event_index = -1; + + k_work_init_delayable(&drv_data->work, enc_mock_work_cb); + + return 0; +} + +#define ENC_MOCK_INST(n) \ + struct enc_mock_data enc_mock_data_##n = {}; \ + const int16_t mock_data_##n[] = DT_INST_PROP(n, events); \ + const struct enc_mock_config enc_mock_cfg_##n = { \ + .events = mock_data_##n, \ + .events_len = DT_INST_PROP_LEN(n, events), \ + .startup_delay = DT_INST_PROP(n, event_startup_delay), \ + .event_period = DT_INST_PROP(n, event_period), \ + .exit_after = DT_INST_PROP(n, exit_after), \ + }; \ + DEVICE_DT_INST_DEFINE(n, enc_mock_init, NULL, &enc_mock_data_##n, &enc_mock_cfg_##n, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &enc_mock_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(ENC_MOCK_INST) diff --git a/app/module/dts/bindings/sensor/zmk,sensor-encoder-mock.yaml b/app/module/dts/bindings/sensor/zmk,sensor-encoder-mock.yaml new file mode 100644 index 00000000000..1739508a35d --- /dev/null +++ b/app/module/dts/bindings/sensor/zmk,sensor-encoder-mock.yaml @@ -0,0 +1,18 @@ +description: | + Allows defining a mock sensor driver that simulates periodic encoder rotation events. + +compatible: "zmk,sensor-encoder-mock" + +properties: + event-startup-delay: + type: int + default: 0 + description: Milliseconds to delay before starting generating the events + event-period: + type: int + description: Milliseconds between each generated event + events: + type: array + description: List of angle events to generate + exit-after: + type: boolean