Skip to content

Commit

Permalink
refactor(sensors): Sensor event channel data, resolution tweaks.
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
petejohanson committed Jun 19, 2023
1 parent dcf5e75 commit 2244bd3
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 79 deletions.
20 changes: 20 additions & 0 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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

Expand Down
12 changes: 11 additions & 1 deletion app/dts/bindings/zmk,keymap-sensors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
28 changes: 16 additions & 12 deletions app/include/drivers/behavior.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <string.h>
#include <zephyr/device.h>
#include <zmk/keys.h>
#include <zmk/sensors.h>
#include <zmk/behavior.h>

/**
Expand All @@ -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,
Expand Down Expand Up @@ -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);

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) {
__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, 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) {
Expand All @@ -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);
}

/**
Expand Down
17 changes: 13 additions & 4 deletions app/include/zmk/events/sensor_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
14 changes: 14 additions & 0 deletions app/include/zmk/sensors.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
};
5 changes: 5 additions & 0 deletions app/include/zmk/virtual_key_position.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
8 changes: 5 additions & 3 deletions app/src/behaviors/behavior_sensor_rotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
59 changes: 43 additions & 16 deletions app/src/behaviors/behavior_sensor_rotate_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
16 changes: 14 additions & 2 deletions app/src/behaviors/behavior_sensor_rotate_common.h
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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);
6 changes: 4 additions & 2 deletions app/src/behaviors/behavior_sensor_rotate_var.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
25 changes: 16 additions & 9 deletions app/src/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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 */

Expand Down
Loading

0 comments on commit 2244bd3

Please sign in to comment.