diff --git a/app/Kconfig b/app/Kconfig index f89d3279d1c..f04e612e1f4 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -171,6 +171,18 @@ rsource "src/split/Kconfig" #Basic Keyboard Setup endmenu +menu "Encoders" + +config ZMK_ENCODERS_DEFAULT_TRIGGERS_PER_ROTATION + int "Default behavior triggers per rotation" + help + Unless overridden for a specific behavior in the keymap/devicetree, this value + determines how many times to trigger the bound behavior per full rotation. + For tactile encoders with detents, this usually should match the number of + detents per rotation of the encoder. + default 30 + +endmenu menu "Display/LED Options" rsource "src/display/Kconfig" diff --git a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml index 1fc60fcf24e..ec2a9a3411c 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml @@ -9,6 +9,9 @@ properties: label: type: string required: true + triggers-per-rotation: + type: int + required: false "#sensor-binding-cells": type: int required: true diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h index fcb24f6fbbd..dd4eec9f213 100644 --- a/app/include/drivers/behavior.h +++ b/app/include/drivers/behavior.h @@ -12,6 +12,7 @@ #include #include #include +#include #include /** @@ -24,9 +25,9 @@ typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event); -typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, - const struct device *sensor, - int64_t timestamp); +typedef int (*behavior_sensor_keymap_binding_callback_t)( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + size_t channel_data_size, const struct zmk_sensor_channel_data channel_data[channel_data_size]); enum behavior_locality { BEHAVIOR_LOCALITY_CENTRAL, @@ -158,13 +159,13 @@ static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_bi * @retval 0 If successful. * @retval Negative errno code if failure. */ -__syscall int behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding, - const struct device *sensor, - int64_t timestamp); +__syscall int behavior_sensor_keymap_binding_triggered( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + size_t channel_data_size, const struct zmk_sensor_channel_data *channel_data); -static inline int -z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding, - const struct device *sensor, int64_t timestamp) { +static inline int z_impl_behavior_sensor_keymap_binding_triggered( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + size_t channel_data_size, const struct zmk_sensor_channel_data *channel_data) { const struct device *dev = device_get_binding(binding->behavior_dev); if (dev == NULL) { @@ -177,7 +178,7 @@ z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *bin return -ENOTSUP; } - return api->sensor_binding_triggered(binding, sensor, timestamp); + return api->sensor_binding_triggered(binding, event, channel_data_size, channel_data); } /** diff --git a/app/include/zmk/events/sensor_event.h b/app/include/zmk/events/sensor_event.h index f579bc398c0..0bd823aec91 100644 --- a/app/include/zmk/events/sensor_event.h +++ b/app/include/zmk/events/sensor_event.h @@ -7,11 +7,20 @@ #pragma once #include +#include #include +#include #include + +// TODO: Move to Kconfig when we need more than one channel +#define ZMK_SENSOR_EVENT_MAX_CHANNELS 1 + struct zmk_sensor_event { - uint8_t sensor_number; - const struct device *sensor; + uint8_t sensor_position; + + size_t channel_data_size; + struct zmk_sensor_channel_data channel_data[ZMK_SENSOR_EVENT_MAX_CHANNELS]; + int64_t timestamp; }; diff --git a/app/include/zmk/sensors.h b/app/include/zmk/sensors.h index 8c6c28b3848..96f44e5c84a 100644 --- a/app/include/zmk/sensors.h +++ b/app/include/zmk/sensors.h @@ -6,7 +6,19 @@ #pragma once +#include + +#define _SENSOR_CHILD_LEN(node) 1 + #define ZMK_KEYMAP_SENSORS_NODE DT_INST(0, zmk_keymap_sensors) -#define ZMK_KEYMAP_HAS_SENSORS DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_NODE, okay) +// #define ZMK_KEYMAP_SENSORS_FOREACH(fn) DT_FOREACH_CHILD(ZMK_KEYMAP_SENSORS_NODE, fn) +// #define ZMK_KEYMAP_SENSORS_FOREACH(fn) DT_FOREACH_CHILD(ZMK_KEYMAP_SENSORS_NODE, fn) #define ZMK_KEYMAP_SENSORS_LEN DT_PROP_LEN(ZMK_KEYMAP_SENSORS_NODE, sensors) + +// #define ZMK_KEYMAP_SENSORS_LEN (DT_FOREACH_CHILD(ZMK_KEYMAP_SENSORS_NODE, _SENSOR_CHILD_LEN) 0) +#define ZMK_KEYMAP_HAS_SENSORS DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_NODE, okay) #define ZMK_KEYMAP_SENSORS_BY_IDX(idx) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_SENSORS_NODE, sensors, idx) + +struct zmk_sensor_channel_data { + enum sensor_channel channel; + struct sensor_value value; +}; diff --git a/app/src/behaviors/behavior_sensor_rotate_key_press.c b/app/src/behaviors/behavior_sensor_rotate_key_press.c index c4a34a94088..ab8c26763dc 100644 --- a/app/src/behaviors/behavior_sensor_rotate_key_press.c +++ b/app/src/behaviors/behavior_sensor_rotate_key_press.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -18,48 +19,73 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +struct behavior_sensor_rotate_key_press_cfg { + uint8_t activation_resolution; +}; + +struct behavior_sensor_rotate_key_press_sensor_data { + int32_t remainder[ZMK_KEYMAP_SENSORS_LEN]; +}; + static int behavior_sensor_rotate_key_press_init(const struct device *dev) { return 0; }; static int on_sensor_binding_triggered(struct zmk_behavior_binding *binding, - const struct device *sensor, int64_t timestamp) { - struct sensor_value value; - int err; + struct zmk_behavior_binding_event event, + size_t channel_data_size, + const struct zmk_sensor_channel_data *channel_data) { + const struct device *behavior_dev = device_get_binding(binding->behavior_dev); + const struct sensor_value *value = &channel_data[0].value; + const struct behavior_sensor_rotate_key_press_cfg *cfg = behavior_dev->config; + struct behavior_sensor_rotate_key_press_sensor_data *data = behavior_dev->data; + uint32_t keycode; - LOG_DBG("inc keycode 0x%02X dec keycode 0x%02X", binding->param1, binding->param2); - err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value); + data->remainder[event.position] += value->val1; - if (err) { - LOG_WRN("Failed to ge sensor rotation value: %d", err); - return err; - } + int8_t triggers = data->remainder[event.position] / cfg->activation_resolution; + data->remainder[event.position] %= cfg->activation_resolution; - switch (value.val1) { - case 1: + LOG_DBG("value: %d, remainder: %d triggers: %d inc keycode 0x%02X dec keycode 0x%02X", + value->val1, data->remainder[event.position], triggers, binding->param1, + binding->param2); + + if (triggers > 0) { keycode = binding->param1; - break; - case -1: + } else if (triggers < 0) { keycode = binding->param2; - break; - default: - return -ENOTSUP; + triggers = -triggers; + } else { + return 0; } LOG_DBG("SEND %d", keycode); - ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(keycode, true, timestamp)); + for (int i = 0; i < triggers; i++) { + ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(keycode, true, event.timestamp)); + + // TODO: Better way to do this? + k_msleep(5); - // TODO: Better way to do this? - k_msleep(5); + ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(keycode, false, event.timestamp)); + } - return ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(keycode, false, timestamp)); + return 0; } static const struct behavior_driver_api behavior_sensor_rotate_key_press_driver_api = { .sensor_binding_triggered = on_sensor_binding_triggered}; #define KP_INST(n) \ - DEVICE_DT_INST_DEFINE(n, behavior_sensor_rotate_key_press_init, NULL, NULL, NULL, APPLICATION, \ + static const struct behavior_sensor_rotate_key_press_cfg \ + behavior_sensor_rotate_key_press_cfg_##n = { \ + .activation_resolution = \ + (360 / DT_INST_PROP_OR(n, triggers_per_rotation, \ + CONFIG_ZMK_ENCODERS_DEFAULT_TRIGGERS_PER_ROTATION))}; \ + static struct behavior_sensor_rotate_key_press_sensor_data \ + behavior_sensor_rotate_key_press_sensor_data_##n; \ + DEVICE_DT_INST_DEFINE(n, behavior_sensor_rotate_key_press_init, NULL, \ + &behavior_sensor_rotate_key_press_sensor_data_##n, \ + &behavior_sensor_rotate_key_press_cfg_##n, APPLICATION, \ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ &behavior_sensor_rotate_key_press_driver_api); diff --git a/app/src/keymap.c b/app/src/keymap.c index e586316f4f4..0e96d25d4e6 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -251,25 +251,33 @@ int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pr } #if ZMK_KEYMAP_HAS_SENSORS -int zmk_keymap_sensor_triggered(uint8_t sensor_number, const struct device *sensor, - int64_t timestamp) { +int zmk_keymap_sensor_triggered( + uint8_t sensor_position, size_t channel_data_size, + const struct zmk_sensor_channel_data channel_data[channel_data_size], int64_t timestamp) { for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { if (zmk_keymap_layer_active(layer) && zmk_sensor_keymap[layer] != NULL) { - struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_number]; + struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_position]; const struct device *behavior; int ret; - LOG_DBG("layer: %d sensor_number: %d, binding name: %s", layer, sensor_number, + LOG_DBG("layer: %d sensor_position: %d, binding name: %s", layer, sensor_position, log_strdup(binding->behavior_dev)); behavior = device_get_binding(binding->behavior_dev); if (!behavior) { - LOG_DBG("No behavior assigned to %d on layer %d", sensor_number, layer); + LOG_DBG("No behavior assigned to %d on layer %d", sensor_position, layer); continue; } - ret = behavior_sensor_keymap_binding_triggered(binding, sensor, timestamp); + struct zmk_behavior_binding_event event = { + .layer = layer, + .position = sensor_position, + .timestamp = timestamp, + }; + + ret = behavior_sensor_keymap_binding_triggered(binding, event, channel_data_size, + channel_data); if (ret > 0) { LOG_DBG("behavior processing to continue to next layer"); @@ -298,8 +306,8 @@ int keymap_listener(const zmk_event_t *eh) { #if ZMK_KEYMAP_HAS_SENSORS const struct zmk_sensor_event *sensor_ev; if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) { - return zmk_keymap_sensor_triggered(sensor_ev->sensor_number, sensor_ev->sensor, - sensor_ev->timestamp); + return zmk_keymap_sensor_triggered(sensor_ev->sensor_position, sensor_ev->channel_data_size, + sensor_ev->channel_data, sensor_ev->timestamp); } #endif /* ZMK_KEYMAP_HAS_SENSORS */ diff --git a/app/src/sensors.c b/app/src/sensors.c index dd5f4267b38..425fcb29ef6 100644 --- a/app/src/sensors.c +++ b/app/src/sensors.c @@ -18,25 +18,24 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if ZMK_KEYMAP_HAS_SENSORS -struct sensors_data_item { - uint8_t sensor_number; +struct sensors_item_cfg { + uint8_t sensor_position; const struct device *dev; struct sensor_trigger trigger; }; #define _SENSOR_ITEM(node) \ - {.dev = NULL, .trigger = {.type = SENSOR_TRIG_DELTA, .chan = SENSOR_CHAN_ROTATION}}, -#define SENSOR_ITEM(idx, _) \ - COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_BY_IDX(idx), okay), \ - (_SENSOR_ITEM(ZMK_KEYMAP_SENSORS_BY_IDX(idx))), ()) + {.dev = COND_CODE_0(DT_NODE_HAS_STATUS(node, okay), (NULL), (DEVICE_DT_GET(node))), \ + .trigger = {.type = SENSOR_TRIG_DELTA, .chan = SENSOR_CHAN_ROTATION}}, +#define SENSOR_ITEM(idx, _i) _SENSOR_ITEM(ZMK_KEYMAP_SENSORS_BY_IDX(idx)) -static struct sensors_data_item sensors[] = {UTIL_LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, 0)}; +static struct sensors_item_cfg sensors[] = {UTIL_LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, 0)}; static void zmk_sensors_trigger_handler(const struct device *dev, struct sensor_trigger *trigger) { int err; - struct sensors_data_item *item = CONTAINER_OF(trigger, struct sensors_data_item, trigger); + struct sensors_item_cfg *item = CONTAINER_OF(trigger, struct sensors_item_cfg, trigger); - LOG_DBG("sensor %d", item->sensor_number); + LOG_DBG("sensor %d", item->sensor_position); err = sensor_sample_fetch(dev); if (err) { @@ -44,37 +43,45 @@ static void zmk_sensors_trigger_handler(const struct device *dev, struct sensor_ return; } - ZMK_EVENT_RAISE(new_zmk_sensor_event((struct zmk_sensor_event){ - .sensor_number = item->sensor_number, .sensor = dev, .timestamp = k_uptime_get()})); + struct sensor_value value; + err = sensor_channel_get(dev, item->trigger.chan, &value); + + if (err) { + LOG_WRN("Failed to get channel data from device %d", err); + return; + } + + ZMK_EVENT_RAISE(new_zmk_sensor_event( + (struct zmk_sensor_event){.sensor_position = item->sensor_position, + .channel_data = {(struct zmk_sensor_channel_data){ + .value = value, .channel = item->trigger.chan}}, + .timestamp = k_uptime_get()})); } -static void zmk_sensors_init_item(const char *node, uint8_t i, uint8_t abs_i) { - LOG_DBG("Init %s at index %d with sensor_number %d", node, i, abs_i); +static void zmk_sensors_init_item(uint8_t i) { + LOG_DBG("Init sensor at index %d", i); - sensors[i].dev = device_get_binding(node); - sensors[i].sensor_number = abs_i; + sensors[i].sensor_position = i; if (!sensors[i].dev) { - LOG_WRN("Failed to find device for %s", node); + LOG_DBG("No local device for %d", i); return; } - sensor_trigger_set(sensors[i].dev, &sensors[i].trigger, zmk_sensors_trigger_handler); + int err = sensor_trigger_set(sensors[i].dev, &sensors[i].trigger, zmk_sensors_trigger_handler); + if (err) { + LOG_WRN("Failed to set sensor trigger (%d)", err); + } } -#define _SENSOR_INIT(node) zmk_sensors_init_item(DT_LABEL(node), local_index++, absolute_index++); -#define SENSOR_INIT(idx, _i) \ - COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_BY_IDX(idx), okay), \ - (_SENSOR_INIT(ZMK_KEYMAP_SENSORS_BY_IDX(idx))), (absolute_index++;)) +#define _SENSOR_INIT(idx, _t) zmk_sensors_init_item(idx); static int zmk_sensors_init(const struct device *_arg) { - int local_index = 0; - int absolute_index = 0; + UTIL_LISTIFY(ZMK_KEYMAP_SENSORS_LEN, _SENSOR_INIT, 0) - UTIL_LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_INIT, 0) return 0; } SYS_INIT(zmk_sensors_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); -#endif /* ZMK_KEYMAP_HAS_SENSORS */ \ No newline at end of file +#endif /* ZMK_KEYMAP_HAS_SENSORS */