Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor events API to avoid heap/dynamic allocations #1722

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ endmenu
endmenu

config HEAP_MEM_POOL_SIZE
default 8192
default 8192 if ZMK_DISPLAY

config KERNEL_BIN_NAME
default "zmk"
Expand Down
31 changes: 18 additions & 13 deletions app/include/zmk/event_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,23 @@ struct zmk_event_subscription {
zmk_event_t header; \
struct event_type data; \
}; \
struct event_type##_event *new_##event_type(struct event_type); \
struct event_type##_event copy_raised_##event_type(const struct event_type *ev); \
int raise_##event_type(struct event_type); \
struct event_type *as_##event_type(const zmk_event_t *eh); \
extern const struct zmk_event_type zmk_event_##event_type;

#define ZMK_EVENT_IMPL(event_type) \
const struct zmk_event_type zmk_event_##event_type = {.name = STRINGIFY(event_type)}; \
const struct zmk_event_type *zmk_event_ref_##event_type __used \
__attribute__((__section__(".event_type"))) = &zmk_event_##event_type; \
struct event_type##_event *new_##event_type(struct event_type data) { \
struct event_type##_event *ev = \
(struct event_type##_event *)k_malloc(sizeof(struct event_type##_event)); \
ev->header.event = &zmk_event_##event_type; \
ev->data = data; \
return ev; \
struct event_type##_event copy_raised_##event_type(const struct event_type *ev) { \
struct event_type##_event *outer = CONTAINER_OF(ev, struct event_type##_event, data); \
return *outer; \
}; \
int raise_##event_type(struct event_type data) { \
struct event_type##_event ev = {.data = data, \
.header = {.event = &zmk_event_##event_type}}; \
return ZMK_EVENT_RAISE(ev); \
}; \
struct event_type *as_##event_type(const zmk_event_t *eh) { \
return (eh->event == &zmk_event_##event_type) ? &((struct event_type##_event *)eh)->data \
Expand All @@ -68,17 +71,19 @@ struct zmk_event_subscription {
.listener = &zmk_listener_##mod, \
};

#define ZMK_EVENT_RAISE(ev) zmk_event_manager_raise((zmk_event_t *)ev);
#define ZMK_ASSERT_EVENT_LIKE(ev) \
(__ASSERT((uint8_t *)&(ev).header - (uint8_t *)&ev == 0, \
"header must be first element of event"))

#define ZMK_EVENT_RAISE(ev) (ZMK_ASSERT_EVENT_LIKE(ev), zmk_event_manager_raise(&(ev).header))

#define ZMK_EVENT_RAISE_AFTER(ev, mod) \
zmk_event_manager_raise_after((zmk_event_t *)ev, &zmk_listener_##mod);
(ZMK_ASSERT_EVENT_LIKE(ev), zmk_event_manager_raise_after(&(ev).header, &zmk_listener_##mod))

#define ZMK_EVENT_RAISE_AT(ev, mod) \
zmk_event_manager_raise_at((zmk_event_t *)ev, &zmk_listener_##mod);

#define ZMK_EVENT_RELEASE(ev) zmk_event_manager_release((zmk_event_t *)ev);
(ZMK_ASSERT_EVENT_LIKE(ev), zmk_event_manager_raise_at(&(ev).header, &zmk_listener_##mod))

#define ZMK_EVENT_FREE(ev) k_free((void *)ev);
#define ZMK_EVENT_RELEASE(ev) (ZMK_ASSERT_EVENT_LIKE(ev), zmk_event_manager_release(&(ev).header))

int zmk_event_manager_raise(zmk_event_t *event);
int zmk_event_manager_raise_after(zmk_event_t *event, const struct zmk_listener *listener);
Expand Down
21 changes: 13 additions & 8 deletions app/include/zmk/events/keycode_state_changed.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct zmk_keycode_state_changed {

ZMK_EVENT_DECLARE(zmk_keycode_state_changed);

static inline struct zmk_keycode_state_changed_event *
static inline struct zmk_keycode_state_changed
zmk_keycode_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) {
uint16_t page = ZMK_HID_USAGE_PAGE(encoded);
uint16_t id = ZMK_HID_USAGE_ID(encoded);
Expand All @@ -38,11 +38,16 @@ zmk_keycode_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t t
implicit_modifiers = SELECT_MODS(encoded);
}

return new_zmk_keycode_state_changed(
(struct zmk_keycode_state_changed){.usage_page = page,
.keycode = id,
.implicit_modifiers = implicit_modifiers,
.explicit_modifiers = explicit_modifiers,
.state = pressed,
.timestamp = timestamp});
return (struct zmk_keycode_state_changed){.usage_page = page,
.keycode = id,
.implicit_modifiers = implicit_modifiers,
.explicit_modifiers = explicit_modifiers,
.state = pressed,
.timestamp = timestamp};
}

static inline int raise_zmk_keycode_state_changed_from_encoded(uint32_t encoded, bool pressed,
int64_t timestamp) {
return raise_zmk_keycode_state_changed(
zmk_keycode_state_changed_from_encoded(encoded, pressed, timestamp));
}
5 changes: 2 additions & 3 deletions app/include/zmk/events/layer_state_changed.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ struct zmk_layer_state_changed {

ZMK_EVENT_DECLARE(zmk_layer_state_changed);

static inline struct zmk_layer_state_changed_event *create_layer_state_changed(uint8_t layer,
bool state) {
return new_zmk_layer_state_changed((struct zmk_layer_state_changed){
static inline int raise_layer_state_changed(uint8_t layer, bool state) {
return raise_zmk_layer_state_changed((struct zmk_layer_state_changed){
.layer = layer, .state = state, .timestamp = k_uptime_get()});
}
6 changes: 3 additions & 3 deletions app/include/zmk/events/mouse_button_state_changed.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ struct zmk_mouse_button_state_changed {

ZMK_EVENT_DECLARE(zmk_mouse_button_state_changed);

static inline struct zmk_mouse_button_state_changed_event *
zmk_mouse_button_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) {
return new_zmk_mouse_button_state_changed((struct zmk_mouse_button_state_changed){
static inline int raise_zmk_mouse_button_state_changed_from_encoded(uint32_t encoded, bool pressed,
petejohanson marked this conversation as resolved.
Show resolved Hide resolved
int64_t timestamp) {
return raise_zmk_mouse_button_state_changed((struct zmk_mouse_button_state_changed){
.buttons = ZMK_HID_USAGE_ID(encoded), .state = pressed, .timestamp = timestamp});
}
4 changes: 2 additions & 2 deletions app/src/activity.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ static uint32_t activity_last_uptime;
#endif

int raise_event(void) {
return ZMK_EVENT_RAISE(new_zmk_activity_state_changed(
(struct zmk_activity_state_changed){.state = activity_state}));
return raise_zmk_activity_state_changed(
(struct zmk_activity_state_changed){.state = activity_state});
}

int set_state(enum zmk_activity_state state) {
Expand Down
4 changes: 2 additions & 2 deletions app/src/battery.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ static int zmk_battery_update(const struct device *battery) {
return rc;
}
#endif
rc = ZMK_EVENT_RAISE(new_zmk_battery_state_changed(
(struct zmk_battery_state_changed){.state_of_charge = last_state_of_charge}));
rc = raise_zmk_battery_state_changed(
(struct zmk_battery_state_changed){.state_of_charge = last_state_of_charge});
}

return rc;
Expand Down
90 changes: 61 additions & 29 deletions app/src/behaviors/behavior_hold_tap.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,24 @@ struct active_hold_tap {
struct active_hold_tap *undecided_hold_tap = NULL;
struct active_hold_tap active_hold_taps[ZMK_BHV_HOLD_TAP_MAX_HELD] = {};
// We capture most position_state_changed events and some modifiers_state_changed events.
const zmk_event_t *captured_events[ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS] = {};

enum captured_event_tag {
ET_NONE,
ET_POS_CHANGED,
ET_CODE_CHANGED,
};

union captured_event_data {
struct zmk_position_state_changed_event position;
struct zmk_keycode_state_changed_event keycode;
};

struct captured_event {
enum captured_event_tag tag;
union captured_event_data data;
};

struct captured_event captured_events[ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS] = {};

// Keep track of which key was tapped most recently for the standard, if it is a hold-tap
// a position, will be given, if not it will just be INT32_MIN
Expand Down Expand Up @@ -122,33 +139,32 @@ static bool is_quick_tap(struct active_hold_tap *hold_tap) {
}
}

static int capture_event(const zmk_event_t *event) {
static int capture_event(struct captured_event *data) {
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) {
if (captured_events[i] == NULL) {
captured_events[i] = event;
if (captured_events[i].tag == ET_NONE) {
captured_events[i] = *data;
return 0;
}
}
return -ENOMEM;
}

static struct zmk_position_state_changed *find_captured_keydown_event(uint32_t position) {
struct zmk_position_state_changed *last_match = NULL;
static bool have_captured_keydown_event(uint32_t position) {
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) {
const zmk_event_t *eh = captured_events[i];
if (eh == NULL) {
return last_match;
struct captured_event *ev = &captured_events[i];
if (ev->tag == ET_NONE) {
return false;
}
struct zmk_position_state_changed *position_event = as_zmk_position_state_changed(eh);
if (position_event == NULL) {

if (ev->tag != ET_POS_CHANGED) {
continue;
}

if (position_event->position == position && position_event->state) {
last_match = position_event;
if (ev->data.position.data.position == position && ev->data.position.data.state) {
return true;
}
}
return last_match;
return false;
}

const struct zmk_listener zmk_listener_behavior_hold_tap;
Expand Down Expand Up @@ -184,25 +200,35 @@ static void release_captured_events() {
// [k1_down, k1_up, null, null, null, ...]
// now mt2 will start releasing it's own captured positions.
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) {
const zmk_event_t *captured_event = captured_events[i];
if (captured_event == NULL) {
struct captured_event *captured_event = &captured_events[i];
enum captured_event_tag tag = captured_event->tag;

if (tag == ET_NONE) {
return;
}
captured_events[i] = NULL;

captured_events[i].tag = ET_NONE;
if (undecided_hold_tap != NULL) {
k_msleep(10);
}

struct zmk_position_state_changed *position_event;
struct zmk_keycode_state_changed *modifier_event;
if ((position_event = as_zmk_position_state_changed(captured_event)) != NULL) {
LOG_DBG("Releasing key position event for position %d %s", position_event->position,
(position_event->state ? "pressed" : "released"));
} else if ((modifier_event = as_zmk_keycode_state_changed(captured_event)) != NULL) {
LOG_DBG("Releasing mods changed event 0x%02X %s", modifier_event->keycode,
(modifier_event->state ? "pressed" : "released"));
switch (tag) {
case ET_CODE_CHANGED:
LOG_DBG("Releasing mods changed event 0x%02X %s",
captured_event->data.keycode.data.keycode,
(captured_event->data.keycode.data.state ? "pressed" : "released"));
ZMK_EVENT_RAISE_AT(captured_event->data.keycode, behavior_hold_tap);
break;
case ET_POS_CHANGED:
LOG_DBG("Releasing key position event for position %d %s",
captured_event->data.position.data.position,
(captured_event->data.position.data.state ? "pressed" : "released"));
ZMK_EVENT_RAISE_AT(captured_event->data.position, behavior_hold_tap);
break;
default:
LOG_ERR("Unhandled captured event type");
break;
}
ZMK_EVENT_RAISE_AT(captured_event, behavior_hold_tap);
}
}

Expand Down Expand Up @@ -622,7 +648,7 @@ static int position_state_changed_listener(const zmk_event_t *eh) {
return ZMK_EV_EVENT_BUBBLE;
}

if (!ev->state && find_captured_keydown_event(ev->position) == NULL) {
if (!ev->state && !have_captured_keydown_event(ev->position)) {
// no keydown event has been captured, let it bubble.
// we'll catch modifiers later in modifier_state_changed_listener
LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->position, ev->position,
Expand All @@ -632,7 +658,11 @@ static int position_state_changed_listener(const zmk_event_t *eh) {

LOG_DBG("%d capturing %d %s event", undecided_hold_tap->position, ev->position,
ev->state ? "down" : "up");
capture_event(eh);
struct captured_event capture = {
.tag = ET_POS_CHANGED,
.data = {.position = copy_raised_zmk_position_state_changed(ev)},
};
capture_event(&capture);
decide_hold_tap(undecided_hold_tap, ev->state ? HT_OTHER_KEY_DOWN : HT_OTHER_KEY_UP);
return ZMK_EV_EVENT_CAPTURED;
}
Expand All @@ -659,7 +689,9 @@ static int keycode_state_changed_listener(const zmk_event_t *eh) {
// if a undecided_hold_tap is active.
LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->position, ev->keycode,
ev->state ? "down" : "up");
capture_event(eh);
struct captured_event capture = {
.tag = ET_CODE_CHANGED, .data = {.keycode = copy_raised_zmk_keycode_state_changed(ev)}};
capture_event(&capture);
return ZMK_EV_EVENT_CAPTURED;
}

Expand Down
6 changes: 2 additions & 4 deletions app/src/behaviors/behavior_key_press.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,13 @@ static int behavior_key_press_init(const struct device *dev) { return 0; };
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
return ZMK_EVENT_RAISE(
zmk_keycode_state_changed_from_encoded(binding->param1, true, event.timestamp));
return raise_zmk_keycode_state_changed_from_encoded(binding->param1, true, event.timestamp);
}

static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
return ZMK_EVENT_RAISE(
zmk_keycode_state_changed_from_encoded(binding->param1, false, event.timestamp));
return raise_zmk_keycode_state_changed_from_encoded(binding->param1, false, event.timestamp);
}

static const struct behavior_driver_api behavior_key_press_driver_api = {
Expand Down
4 changes: 2 additions & 2 deletions app/src/behaviors/behavior_key_repeat.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ static int on_key_repeat_binding_pressed(struct zmk_behavior_binding *binding,
sizeof(struct zmk_keycode_state_changed));
data->current_keycode_pressed.timestamp = k_uptime_get();

ZMK_EVENT_RAISE(new_zmk_keycode_state_changed(data->current_keycode_pressed));
raise_zmk_keycode_state_changed(data->current_keycode_pressed);

return ZMK_BEHAVIOR_OPAQUE;
}
Expand All @@ -60,7 +60,7 @@ static int on_key_repeat_binding_released(struct zmk_behavior_binding *binding,
data->current_keycode_pressed.timestamp = k_uptime_get();
data->current_keycode_pressed.state = false;

ZMK_EVENT_RAISE(new_zmk_keycode_state_changed(data->current_keycode_pressed));
raise_zmk_keycode_state_changed(data->current_keycode_pressed);
return ZMK_BEHAVIOR_OPAQUE;
}

Expand Down
3 changes: 1 addition & 2 deletions app/src/behaviors/behavior_key_toggle.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
bool pressed = zmk_hid_is_pressed(binding->param1);
return ZMK_EVENT_RAISE(
zmk_keycode_state_changed_from_encoded(binding->param1, !pressed, event.timestamp));
return raise_zmk_keycode_state_changed_from_encoded(binding->param1, !pressed, event.timestamp);
}

static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
Expand Down
8 changes: 4 additions & 4 deletions app/src/behaviors/behavior_mouse_key_press.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);

return ZMK_EVENT_RAISE(
zmk_mouse_button_state_changed_from_encoded(binding->param1, true, event.timestamp));
return raise_zmk_mouse_button_state_changed_from_encoded(binding->param1, true,
event.timestamp);
}

static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
return ZMK_EVENT_RAISE(
zmk_mouse_button_state_changed_from_encoded(binding->param1, false, event.timestamp));
return raise_zmk_mouse_button_state_changed_from_encoded(binding->param1, false,
event.timestamp);
}

static const struct behavior_driver_api behavior_mouse_key_press_driver_api = {
Expand Down
4 changes: 3 additions & 1 deletion app/src/behaviors/behavior_sticky_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) {
if (sticky_key->config->quick_release) {
// immediately release the sticky key after the key press is handled.
if (!event_reraised) {
ZMK_EVENT_RAISE_AFTER(eh, behavior_sticky_key);
struct zmk_keycode_state_changed_event dupe_ev =
copy_raised_zmk_keycode_state_changed(ev);
ZMK_EVENT_RAISE_AFTER(dupe_ev, behavior_sticky_key);
event_reraised = true;
}
release_sticky_key_behavior(sticky_key, ev_copy.timestamp);
Expand Down
4 changes: 2 additions & 2 deletions app/src/ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ static bt_addr_le_t peripheral_addrs[ZMK_SPLIT_BLE_PERIPHERAL_COUNT];
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */

static void raise_profile_changed_event(void) {
ZMK_EVENT_RAISE(new_zmk_ble_active_profile_changed((struct zmk_ble_active_profile_changed){
.index = active_profile, .profile = &profiles[active_profile]}));
raise_zmk_ble_active_profile_changed((struct zmk_ble_active_profile_changed){
.index = active_profile, .profile = &profiles[active_profile]});
}

static void raise_profile_changed_event_callback(struct k_work *work) {
Expand Down
Loading