Skip to content

Commit

Permalink
feature(split): behavior locality support.
Browse files Browse the repository at this point in the history
* GATT characteristic allowing passng data + behavior
  label to invoke the behavior on the peripheral side.
* Behaviors have a locality setting to specify where they run.
* Build reset/power/RGB on peripheral.
  • Loading branch information
petejohanson committed Jan 9, 2021
1 parent 0c6686f commit 7af2e6e
Show file tree
Hide file tree
Showing 16 changed files with 235 additions and 17 deletions.
4 changes: 2 additions & 2 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ target_sources(app PRIVATE src/events/sensor_event.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/battery_state_changed.c)
target_sources_ifdef(CONFIG_USB app PRIVATE src/events/usb_conn_state_changed.c)
target_sources(app PRIVATE src/behaviors/behavior_reset.c)
target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c)
if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
target_sources(app PRIVATE src/behaviors/behavior_reset.c)
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c)
target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)
Expand All @@ -51,7 +52,6 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
target_sources(app PRIVATE src/behaviors/behavior_none.c)
target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c)
target_sources(app PRIVATE src/keymap.c)
endif()
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c)
Expand Down
2 changes: 1 addition & 1 deletion app/dts/behaviors/reset.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

bootloader: behavior_reset_dfu {
compatible = "zmk,behavior-reset";
label = "BOOTLOADER_RESET";
label = "BOOTLOAD";
type = <RST_UF2>;
#binding-cells = <0>;
};
Expand Down
2 changes: 1 addition & 1 deletion app/dts/behaviors/rgb_underglow.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
behaviors {
rgb_ug: behavior_rgb_underglow {
compatible = "zmk,behavior-rgb-underglow";
label = "RGB_UNDERGLOW";
label = "RGB_UG";
#binding-cells = <2>;
};
};
Expand Down
46 changes: 46 additions & 0 deletions app/include/drivers/behavior.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include <zephyr/types.h>
#include <stddef.h>
#include <sys/util.h>
#include <string.h>
#include <device.h>
#include <zmk/keys.h>
#include <zmk/behavior.h>
Expand All @@ -26,7 +28,14 @@ typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_bin
const struct device *sensor,
int64_t timestamp);

enum behavior_locality {
BEHAVIOR_LOCALITY_CENTRAL,
BEHAVIOR_LOCALITY_EVENT_SOURCE,
BEHAVIOR_LOCALITY_GLOBAL
};

__subsystem struct behavior_driver_api {
enum behavior_locality locality;
behavior_keymap_binding_callback_t binding_pressed;
behavior_keymap_binding_callback_t binding_released;
behavior_sensor_keymap_binding_callback_t sensor_binding_triggered;
Expand All @@ -35,6 +44,28 @@ __subsystem struct behavior_driver_api {
* @endcond
*/

/**
* @brief Determine where the behavior should be run
* @param behavior Pointer to the device structure for the driver instance.
*
* @retval Zero if successful.
* @retval Negative errno code if failure.
*/
__syscall int behavior_get_locality(const struct device *behavior,
enum behavior_locality *locality);

static inline int z_impl_behavior_get_locality(const struct device *behavior,
enum behavior_locality *locality) {
if (behavior == NULL) {
return -EINVAL;
}

const struct behavior_driver_api *api = (const struct behavior_driver_api *)behavior->api;
*locality = api->locality;

return 0;
}

/**
* @brief Handle the keymap binding being pressed
* @param dev Pointer to the device structure for the driver instance.
Expand All @@ -50,6 +81,11 @@ __syscall int behavior_keymap_binding_pressed(struct zmk_behavior_binding *bindi
static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
const struct device *dev = device_get_binding(binding->behavior_dev);

if (dev == NULL) {
return -EINVAL;
}

const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;

if (api->binding_pressed == NULL) {
Expand All @@ -73,6 +109,11 @@ __syscall int behavior_keymap_binding_released(struct zmk_behavior_binding *bind
static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
const struct device *dev = device_get_binding(binding->behavior_dev);

if (dev == NULL) {
return -EINVAL;
}

const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;

if (api->binding_released == NULL) {
Expand Down Expand Up @@ -100,6 +141,11 @@ static inline int
z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding,
const struct device *sensor, int64_t timestamp) {
const struct device *dev = device_get_binding(binding->behavior_dev);

if (dev == NULL) {
return -EINVAL;
}

const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;

if (api->sensor_binding_triggered == NULL) {
Expand Down
10 changes: 9 additions & 1 deletion app/include/zmk/events/position_state_changed.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,20 @@

#include <zephyr.h>
#include <zmk/event_manager.h>
#include <bluetooth/addr.h>

#if IS_ENABLED(CONFIG_ZMK_BLE)
typedef const bt_addr_le_t *zmk_position_state_changed_source_t;
#else
typedef void *zmk_position_state_changed_source_t;
#endif

struct position_state_changed {
struct zmk_event_header header;
zmk_position_state_changed_source_t source;
uint32_t position;
bool state;
int64_t timestamp;
};

ZMK_EVENT_DECLARE(position_state_changed);
ZMK_EVENT_DECLARE(position_state_changed);
5 changes: 4 additions & 1 deletion app/include/zmk/keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#pragma once

#include <zmk/events/position_state_changed.h>

typedef uint32_t zmk_keymap_layers_state_t;

uint8_t zmk_keymap_layer_default();
Expand All @@ -18,4 +20,5 @@ int zmk_keymap_layer_toggle(uint8_t layer);
int zmk_keymap_layer_to(uint8_t layer);
const char *zmk_keymap_layer_label(uint8_t layer);

int zmk_keymap_position_state_changed(uint32_t position, bool pressed, int64_t timestamp);
int zmk_keymap_position_state_changed(zmk_position_state_changed_source_t source, uint32_t position,
bool pressed, int64_t timestamp);
8 changes: 8 additions & 0 deletions app/include/zmk/split/bluetooth/central.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

#pragma once

#include <bluetooth/addr.h>
#include <zmk/behavior.h>

int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event, bool state);
14 changes: 14 additions & 0 deletions app/include/zmk/split/bluetooth/service.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,19 @@

#pragma once

#define ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN 9

struct zmk_split_run_behavior_data {
uint8_t position;
uint8_t state;
uint32_t param1;
uint32_t param2;
} __packed;

struct zmk_split_run_behavior_payload {
struct zmk_split_run_behavior_data data;
char behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN];
} __packed;

int zmk_split_bt_position_pressed(uint8_t position);
int zmk_split_bt_position_released(uint8_t position);
1 change: 1 addition & 0 deletions app/include/zmk/split/bluetooth/uuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
#define ZMK_BT_SPLIT_UUID(num) BT_UUID_128_ENCODE(num, 0x0096, 0x7107, 0xc967, 0xc5cfb1c2482a)
#define ZMK_SPLIT_BT_SERVICE_UUID ZMK_BT_SPLIT_UUID(0x00000000)
#define ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000001)
#define ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID ZMK_BT_SPLIT_UUID(0x00000002)
1 change: 1 addition & 0 deletions app/src/behaviors/behavior_ext_power.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ static int behavior_ext_power_init(const struct device *dev) { return 0; };
static const struct behavior_driver_api behavior_ext_power_driver_api = {
.binding_pressed = on_keymap_binding_pressed,
.binding_released = on_keymap_binding_released,
.locality = BEHAVIOR_LOCALITY_GLOBAL,
};

DEVICE_AND_API_INIT(behavior_ext_power, DT_INST_LABEL(0), behavior_ext_power_init, NULL, NULL,
Expand Down
1 change: 1 addition & 0 deletions app/src/behaviors/behavior_reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,

static const struct behavior_driver_api behavior_reset_driver_api = {
.binding_pressed = on_keymap_binding_pressed,
.locality = BEHAVIOR_LOCALITY_EVENT_SOURCE,
};

#define RST_INST(n) \
Expand Down
1 change: 1 addition & 0 deletions app/src/behaviors/behavior_rgb_underglow.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
static const struct behavior_driver_api behavior_rgb_underglow_driver_api = {
.binding_pressed = on_keymap_binding_pressed,
.binding_released = on_keymap_binding_released,
.locality = BEHAVIOR_LOCALITY_GLOBAL,
};

DEVICE_AND_API_INIT(behavior_rgb_underglow, DT_INST_LABEL(0), behavior_rgb_underglow_init, NULL,
Expand Down
62 changes: 53 additions & 9 deletions app/src/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
* SPDX-License-Identifier: MIT
*/

#define IS_BLE_CENTRAL \
(IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_BLE) && \
IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL))

#include <sys/util.h>
#include <bluetooth/bluetooth.h>
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

Expand All @@ -14,6 +19,10 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <drivers/behavior.h>
#include <zmk/behavior.h>

#if IS_BLE_CENTRAL
#include <zmk/split/bluetooth/central.h>
#endif

#include <zmk/event_manager.h>
#include <zmk/events/position_state_changed.h>
#include <zmk/events/layer_state_changed.h>
Expand Down Expand Up @@ -160,7 +169,17 @@ const char *zmk_keymap_layer_label(uint8_t layer) {
return zmk_keymap_layer_names[layer];
}

int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, int64_t timestamp) {
int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
bool pressed) {
if (pressed) {
return behavior_keymap_binding_pressed(binding, event);
} else {
return behavior_keymap_binding_released(binding, event);
}
}

int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source, int layer,
uint32_t position, bool pressed, int64_t timestamp) {
struct zmk_behavior_binding *binding = &zmk_keymap[layer][position];
const struct device *behavior;
struct zmk_behavior_binding_event event = {
Expand All @@ -175,24 +194,48 @@ int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed,
behavior = device_get_binding(binding->behavior_dev);

if (!behavior) {
LOG_DBG("No behavior assigned to %d on layer %d", position, layer);
LOG_WRN("No behavior assigned to %d on layer %d", position, layer);
return 1;
}

if (pressed) {
return behavior_keymap_binding_pressed(binding, event);
} else {
return behavior_keymap_binding_released(binding, event);
enum behavior_locality locality = BEHAVIOR_LOCALITY_CENTRAL;
int err = behavior_get_locality(behavior, &locality);
if (err) {
LOG_ERR("Failed to get behavior locality %d", err);
return err;
}

switch (locality) {
case BEHAVIOR_LOCALITY_CENTRAL:
return invoke_locally(binding, event, pressed);
case BEHAVIOR_LOCALITY_EVENT_SOURCE:
#if IS_BLE_CENTRAL
if (!bt_addr_le_cmp(source, BT_ADDR_LE_NONE)) {
return invoke_locally(binding, event, pressed);
} else {
return zmk_split_bt_invoke_behavior(source, binding, event, pressed);
}
#else
return invoke_locally(binding, event, pressed);
#endif
case BEHAVIOR_LOCALITY_GLOBAL:
#if IS_BLE_CENTRAL
zmk_split_bt_invoke_behavior(BT_ADDR_LE_ANY, binding, event, pressed);
#endif
return invoke_locally(binding, event, pressed);
}

return -ENOTSUP;
}

int zmk_keymap_position_state_changed(uint32_t position, bool pressed, int64_t timestamp) {
int zmk_keymap_position_state_changed(zmk_position_state_changed_source_t source, uint32_t position,
bool pressed, int64_t timestamp) {
if (pressed) {
zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state;
}
for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) {
if (zmk_keymap_layer_active_with_state(layer, zmk_keymap_active_behavior_layer[position])) {
int ret = zmk_keymap_apply_position_state(layer, position, pressed, timestamp);
int ret = zmk_keymap_apply_position_state(source, layer, position, pressed, timestamp);
if (ret > 0) {
LOG_DBG("behavior processing to continue to next layer");
continue;
Expand Down Expand Up @@ -249,7 +292,8 @@ int zmk_keymap_sensor_triggered(uint8_t sensor_number, const struct device *sens
int keymap_listener(const struct zmk_event_header *eh) {
if (is_position_state_changed(eh)) {
const struct position_state_changed *ev = cast_position_state_changed(eh);
return zmk_keymap_position_state_changed(ev->position, ev->state, ev->timestamp);
return zmk_keymap_position_state_changed(ev->source, ev->position, ev->state,
ev->timestamp);
#if ZMK_KEYMAP_HAS_SENSORS
} else if (is_sensor_event(eh)) {
const struct sensor_event *ev = cast_sensor_event(eh);
Expand Down
4 changes: 4 additions & 0 deletions app/src/kscan.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <zephyr.h>
#include <device.h>
#include <bluetooth/addr.h>
#include <drivers/kscan.h>
#include <logging/log.h>

Expand Down Expand Up @@ -51,6 +52,9 @@ void zmk_kscan_process_msgq(struct k_work *item) {
LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s\n", ev.row, ev.column, position,
(pressed ? "true" : "false"));
pos_ev = new_position_state_changed();
#if IS_ENABLED(CONFIG_ZMK_BLE)
pos_ev->source = BT_ADDR_LE_NONE;
#endif
pos_ev->state = pressed;
pos_ev->position = position;
pos_ev->timestamp = k_uptime_get();
Expand Down
Loading

0 comments on commit 7af2e6e

Please sign in to comment.