refactor(sensors): Sensor event channel data, resolution tweaks.

* Refactor sensor events to include channel data,
  necessary for prop split encoders, and avoiding duplicate calls,
  to fetch channel data twice, etc.
* More consistent behavior driver API.
* Allow setting triggers per resolution at the behavior level optionally.
This commit is contained in:
Peter Johanson 2021-09-01 03:49:18 +00:00 committed by Pete Johanson
parent dcf5e75fa6
commit 2244bd3d81
12 changed files with 258 additions and 83 deletions

View file

@ -194,6 +194,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"
@ -523,6 +535,14 @@ config ZMK_WPM
config SENSOR
default y
if ZMK_KEYMAP_SENSORS
config ZMK_KEYMAP_SENSORS_DEFAULT_TRIGGERS_PER_ROTATION
int "Default triggers per rotation"
default 20
endif # ZMK_KEYMAP_SENSORS
choice CBPRINTF_IMPLEMENTATION
default CBPRINTF_NANO

View file

@ -9,4 +9,14 @@ compatible: "zmk,keymap-sensors"
properties:
sensors:
type: phandles
required: true
required: false
triggers-per-rotation:
type: int
required: false
child-binding:
description: Per-sensor configuration settings
properties:
triggers-per-rotation:
type: int
required: false

View file

@ -12,6 +12,7 @@
#include <string.h>
#include <zephyr/device.h>
#include <zmk/keys.h>
#include <zmk/sensors.h>
#include <zmk/behavior.h>
/**
@ -24,9 +25,10 @@
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,
struct zmk_behavior_binding_event event);
typedef int (*behavior_sensor_keymap_binding_callback_t)(
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
const struct zmk_sensor_channel_data channel_data[channel_data_size]);
enum behavior_locality {
BEHAVIOR_LOCALITY_CENTRAL,
@ -158,14 +160,15 @@ 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,
struct zmk_behavior_binding_event event);
__syscall int behavior_sensor_keymap_binding_triggered(
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
const struct zmk_sensor_config *sensor_config, 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,
struct zmk_behavior_binding_event event) {
static inline int z_impl_behavior_sensor_keymap_binding_triggered(
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
const struct zmk_sensor_config *sensor_config, 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) {
@ -178,7 +181,8 @@ z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *bin
return -ENOTSUP;
}
return api->sensor_binding_triggered(binding, sensor, event);
return api->sensor_binding_triggered(binding, event, sensor_config, channel_data_size,
channel_data);
}
/**

View file

@ -6,12 +6,21 @@
#pragma once
#include <zephyr/kernel.h>
#include <zephyr/drivers/sensor.h>
#include <zmk/event_manager.h>
#include <zephyr/device.h>
#include <zmk/sensors.h>
#include <device.h>
// 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;
};

View file

@ -6,6 +6,9 @@
#pragma once
#include <drivers/sensor.h>
#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_BY_IDX(idx) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_SENSORS_NODE, sensors, idx)
@ -15,3 +18,14 @@
#else
#define ZMK_KEYMAP_SENSORS_LEN 0
#endif
const struct zmk_sensor_config *zmk_sensors_get_config_at_position(uint8_t sensor_position);
struct zmk_sensor_config {
uint16_t triggers_per_rotation;
};
struct zmk_sensor_channel_data {
enum sensor_channel channel;
struct sensor_value value;
};

View file

@ -14,6 +14,11 @@
*/
#define ZMK_VIRTUAL_KEY_POSITION_SENSOR(index) (ZMK_KEYMAP_LEN + (index))
/**
* Gets the sensor number from the virtual key position.
*/
#define ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(vkp) ((vkp)-ZMK_KEYMAP_LEN)
/**
* Gets the virtual key position to use for the combo with the given index.
*/

View file

@ -33,8 +33,10 @@ static int behavior_sensor_rotate_init(const struct device *dev) { return 0; };
.tap_ms = DT_INST_PROP_OR(n, tap_ms, 5), \
.override_params = false, \
}; \
DEVICE_DT_INST_DEFINE( \
n, behavior_sensor_rotate_init, NULL, NULL, &behavior_sensor_rotate_config_##n, \
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sensor_rotate_driver_api);
static struct behavior_sensor_rotate_data behavior_sensor_rotate_data_##n = {}; \
DEVICE_DT_INST_DEFINE(n, behavior_sensor_rotate_init, NULL, &behavior_sensor_rotate_data_##n, \
&behavior_sensor_rotate_config_##n, APPLICATION, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
&behavior_sensor_rotate_driver_api);
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_INST)

View file

@ -5,48 +5,75 @@
#include <zephyr/kernel.h>
#include <zmk/behavior_queue.h>
#include <zmk/virtual_key_position.h>
#include "behavior_sensor_rotate_common.h"
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
int zmk_behavior_sensor_rotate_common_trigger(struct zmk_behavior_binding *binding,
const struct device *sensor,
struct zmk_behavior_binding_event event) {
struct zmk_behavior_binding_event event,
const struct zmk_sensor_config *sensor_config,
size_t channel_data_size,
const struct zmk_sensor_channel_data *channel_data) {
const struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_sensor_rotate_config *cfg = dev->config;
struct behavior_sensor_rotate_data *data = dev->data;
struct sensor_value value;
const struct sensor_value value = channel_data[0].value;
int triggers;
int sensor_position = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position);
const int err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value);
// Some funky special casing for "old encoder behavior" where ticks where reported in val2 only,
// instead of rotational degrees in val1.
// REMOVE ME: Remove after a grace period of old ec11 sensor behavior
if (value.val1 == 0) {
triggers = value.val2;
} else {
struct sensor_value remainder = data->remainder[sensor_position];
if (err < 0) {
LOG_WRN("Failed to get sensor rotation value: %d", err);
return err;
remainder.val1 += value.val1;
remainder.val2 += value.val2;
if (remainder.val2 >= 1000000 || remainder.val2 <= 1000000) {
remainder.val1 += remainder.val2 / 1000000;
remainder.val2 %= 1000000;
}
int trigger_degrees = 360 / sensor_config->triggers_per_rotation;
triggers = remainder.val1 / trigger_degrees;
remainder.val1 %= trigger_degrees;
data->remainder[sensor_position] = remainder;
}
LOG_DBG(
"val1: %d, val2: %d, remainder: %d/%d triggers: %d inc keycode 0x%02X dec keycode 0x%02X",
value.val1, value.val2, data->remainder[sensor_position].val1,
data->remainder[sensor_position].val2, triggers, binding->param1, binding->param2);
struct zmk_behavior_binding triggered_binding;
switch (value.val1) {
case 1:
if (triggers > 0) {
triggered_binding = cfg->cw_binding;
if (cfg->override_params) {
triggered_binding.param1 = binding->param1;
}
break;
case -1:
} else if (triggers < 0) {
triggers = -triggers;
triggered_binding = cfg->ccw_binding;
if (cfg->override_params) {
triggered_binding.param1 = binding->param2;
}
break;
default:
return -ENOTSUP;
} else {
return 0;
}
LOG_DBG("Sensor binding: %s", binding->behavior_dev);
zmk_behavior_queue_add(event.position, triggered_binding, true, cfg->tap_ms);
zmk_behavior_queue_add(event.position, triggered_binding, false, 0);
for (int i = 0; i < triggers; i++) {
zmk_behavior_queue_add(event.position, triggered_binding, true, cfg->tap_ms);
zmk_behavior_queue_add(event.position, triggered_binding, false, 0);
}
return ZMK_BEHAVIOR_OPAQUE;
}

View file

@ -1,5 +1,11 @@
/*
* Copyright (c) 2023 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <zmk/behavior.h>
#include <zmk/sensors.h>
struct behavior_sensor_rotate_config {
struct zmk_behavior_binding cw_binding;
@ -8,6 +14,12 @@ struct behavior_sensor_rotate_config {
bool override_params;
};
struct behavior_sensor_rotate_data {
struct sensor_value remainder[ZMK_KEYMAP_SENSORS_LEN];
};
int zmk_behavior_sensor_rotate_common_trigger(struct zmk_behavior_binding *binding,
const struct device *sensor,
struct zmk_behavior_binding_event event);
struct zmk_behavior_binding_event event,
const struct zmk_sensor_config *sensor_config,
size_t channel_data_size,
const struct zmk_sensor_channel_data *channel_data);

View file

@ -24,8 +24,10 @@ static int behavior_sensor_rotate_var_init(const struct device *dev) { return 0;
.tap_ms = DT_INST_PROP(n, tap_ms), \
.override_params = true, \
}; \
static struct behavior_sensor_rotate_data behavior_sensor_rotate_var_data_##n = {}; \
DEVICE_DT_INST_DEFINE( \
n, behavior_sensor_rotate_var_init, NULL, NULL, &behavior_sensor_rotate_var_config_##n, \
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sensor_rotate_var_driver_api);
n, behavior_sensor_rotate_var_init, NULL, &behavior_sensor_rotate_var_data_##n, \
&behavior_sensor_rotate_var_config_##n, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
&behavior_sensor_rotate_var_driver_api);
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_VAR_INST)

View file

@ -252,27 +252,34 @@ 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)) {
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,
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;
}
struct zmk_behavior_binding_event event = {
.position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_number), .timestamp = timestamp};
ret = behavior_sensor_keymap_binding_triggered(binding, sensor, event);
.layer = layer,
.position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_position),
.timestamp = timestamp,
};
ret = behavior_sensor_keymap_binding_triggered(
binding, event, zmk_sensors_get_config_at_position(sensor_position),
channel_data_size, channel_data);
if (ret > 0) {
LOG_DBG("behavior processing to continue to next layer");
@ -301,8 +308,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 */

View file

@ -18,65 +18,128 @@ 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 zmk_sensor_config *config;
const struct device *dev;
struct sensor_trigger trigger;
};
#define _SENSOR_ITEM(node) \
#define _SENSOR_ITEM(idx, node) \
{ \
.dev = NULL, .trigger = {.type = SENSOR_TRIG_DELTA, .chan = SENSOR_CHAN_ROTATION } \
.dev = DEVICE_DT_GET_OR_NULL(node), \
.trigger = {.type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_ROTATION}, \
.config = &configs[idx] \
}
#define SENSOR_ITEM(idx, _i) _SENSOR_ITEM(idx, ZMK_KEYMAP_SENSORS_BY_IDX(idx))
#define PLUS_ONE(n) +1
#define ZMK_KEYMAP_SENSORS_CHILD_COUNT (0 DT_FOREACH_CHILD(ZMK_KEYMAP_SENSORS_NODE, PLUS_ONE))
#define SENSOR_CHILD_ITEM(node) \
{ \
.triggers_per_rotation = \
DT_PROP_OR(node, triggers_per_rotation, \
DT_PROP_OR(ZMK_KEYMAP_SENSORS_NODE, triggers_per_rotation, \
CONFIG_ZMK_KEYMAP_SENSORS_DEFAULT_TRIGGERS_PER_ROTATION)) \
}
#define SENSOR_CHILD_DEFAULTS(idx, arg) \
{ .triggers_per_rotation = DT_PROP_OR(ZMK_KEYMAP_SENSORS_NODE, triggers_per_rotation, 20) }
static struct zmk_sensor_config configs[] = {
#if ZMK_KEYMAP_SENSORS_CHILD_COUNT > 0
DT_FOREACH_CHILD_SEP(ZMK_KEYMAP_SENSORS_NODE, SENSOR_CHILD_ITEM, (, ))
#else
LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_CHILD_DEFAULTS, (, ), 0)
#endif
};
static struct sensors_item_cfg sensors[] = {LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, (, ), 0)};
static ATOMIC_DEFINE(pending_sensors, ZMK_KEYMAP_SENSORS_LEN);
const struct zmk_sensor_config *zmk_sensors_get_config_at_position(uint8_t sensor_position) {
if (sensor_position > ARRAY_SIZE(configs)) {
return NULL;
}
#define SENSOR_ITEM(idx, _node) \
COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_BY_IDX(idx), okay), \
(_SENSOR_ITEM(ZMK_KEYMAP_SENSORS_BY_IDX(idx))), ({}))
return &configs[sensor_position];
}
static struct sensors_data_item sensors[] = {LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, (, ), 0)};
static void zmk_sensors_trigger_handler(const struct device *dev,
const struct sensor_trigger *trigger) {
static void trigger_sensor_data_for_position(uint32_t sensor_position) {
int err;
const struct sensors_data_item *item = CONTAINER_OF(trigger, struct sensors_data_item, trigger);
const struct sensors_item_cfg *item = &sensors[sensor_position];
LOG_DBG("sensor %d", item->sensor_number);
err = sensor_sample_fetch(dev);
err = sensor_sample_fetch(item->dev);
if (err) {
LOG_WRN("Failed to fetch sample from device %d", err);
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(item->dev, item->trigger.chan, &value);
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);
sensors[i].dev = device_get_binding(node);
sensors[i].sensor_number = abs_i;
if (!sensors[i].dev) {
LOG_WRN("Failed to find device for %s", node);
if (err) {
LOG_WRN("Failed to get channel data from device %d", err);
return;
}
sensor_trigger_set(sensors[i].dev, &sensors[i].trigger, zmk_sensors_trigger_handler);
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()}));
}
#define _SENSOR_INIT(node) \
zmk_sensors_init_item(DT_PROP(node, label), 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++;))
static void run_sensors_data_trigger(struct k_work *work) {
for (int i = 0; i < ARRAY_SIZE(sensors); i++) {
if (atomic_test_and_clear_bit(pending_sensors, i)) {
trigger_sensor_data_for_position(i);
}
}
}
K_WORK_DEFINE(sensor_data_work, run_sensors_data_trigger);
static void zmk_sensors_trigger_handler(const struct device *dev,
const struct sensor_trigger *trigger) {
const struct sensors_item_cfg *test_item =
CONTAINER_OF(trigger, struct sensors_item_cfg, trigger);
int sensor_index = test_item - sensors;
if (sensor_index < 0 || sensor_index >= ARRAY_SIZE(sensors)) {
LOG_ERR("Invalid sensor item triggered our callback");
return;
}
if (k_is_in_isr()) {
atomic_set_bit(pending_sensors, sensor_index);
k_work_submit(&sensor_data_work);
} else {
trigger_sensor_data_for_position(sensor_index);
}
}
static void zmk_sensors_init_item(uint8_t i) {
LOG_DBG("Init sensor at index %d", i);
sensors[i].sensor_position = i;
if (!sensors[i].dev) {
LOG_DBG("No local device for %d", i);
return;
}
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(idx, _t) zmk_sensors_init_item(idx);
static int zmk_sensors_init(const struct device *_arg) {
int local_index = 0;
int absolute_index = 0;
LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_INIT, (), 0)
return 0;
}