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 29, 2022
1 parent 6b0879a commit 3898db2
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 67 deletions.
12 changes: 12 additions & 0 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ properties:
label:
type: string
required: true
triggers-per-rotation:
type: int
required: false
"#sensor-binding-cells":
type: int
required: true
Expand Down
21 changes: 11 additions & 10 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 <device.h>
#include <zmk/keys.h>
#include <zmk/sensors.h>
#include <zmk/behavior.h>

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

/**
Expand Down
13 changes: 11 additions & 2 deletions app/include/zmk/events/sensor_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,20 @@
#pragma once

#include <zephyr.h>
#include <drivers/sensor.h>
#include <zmk/event_manager.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: 13 additions & 1 deletion app/include/zmk/sensors.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,19 @@

#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_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;
};
68 changes: 47 additions & 21 deletions app/src/behaviors/behavior_sensor_rotate_key_press.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,81 @@
#include <logging/log.h>

#include <drivers/sensor.h>
#include <zmk/sensors.h>
#include <zmk/event_manager.h>
#include <zmk/events/keycode_state_changed.h>

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

Expand Down
24 changes: 16 additions & 8 deletions app/src/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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 */

Expand Down
57 changes: 32 additions & 25 deletions app/src/sensors.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,63 +18,70 @@ 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) {
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(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 */
#endif /* ZMK_KEYMAP_HAS_SENSORS */

0 comments on commit 3898db2

Please sign in to comment.