Skip to content

Commit

Permalink
feat(rpc): Tons more RPC work.
Browse files Browse the repository at this point in the history
* Add full  notification support, including mapping local events to RPC
  notifications by a given subsystem.
* New meta responses for "no response" and "unlock needed".
* Initial basic lock state support in a new core section, and allow specifying
  if a given RPC callback requires unlocked state or not.
* Add behavior subsystem with full metadata support and examples of
  using callback to serialize a repeated field without extra stack space needed.
  • Loading branch information
petejohanson committed Mar 27, 2024
1 parent 0f0f3dd commit 5e408c5
Show file tree
Hide file tree
Showing 20 changed files with 494 additions and 138 deletions.
5 changes: 0 additions & 5 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ endif()
zephyr_linker_sources(SECTIONS include/linker/zmk-behaviors.ld)
zephyr_linker_sources(RODATA include/linker/zmk-events.ld)

if(CONFIG_ZMK_STUDIO)
zephyr_linker_sources(DATA_SECTIONS include/linker/zmk-rpc-subsystems.ld)
zephyr_linker_sources(SECTIONS include/linker/zmk-rpc-subsystem-handlers.ld)
endif()

zephyr_syscall_header(${APPLICATION_SOURCE_DIR}/include/drivers/behavior.h)
zephyr_syscall_header(${APPLICATION_SOURCE_DIR}/include/drivers/ext_power.h)

Expand Down
9 changes: 9 additions & 0 deletions app/include/linker/zmk-rpc-event-mappers.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#include <zephyr/linker/linker-defs.h>

ITERABLE_SECTION_ROM(zmk_rpc_event_mapper, 4)
23 changes: 23 additions & 0 deletions app/include/zmk/studio/core.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

#pragma once

#include <zmk/event_manager.h>

enum zmk_studio_core_lock_state {
ZMK_STUDIO_CORE_LOCK_STATE_LOCKED = 0,
ZMK_STUDIO_CORE_LOCK_STATE_UNLOCKING = 1,
ZMK_STUDIO_CORE_LOCK_STATE_UNLOCKED = 2,
};

struct zmk_studio_core_lock_state_changed {
enum zmk_studio_core_lock_state state;
};

ZMK_EVENT_DECLARE(zmk_studio_core_lock_state_changed);

enum zmk_studio_core_lock_state zmk_studio_core_get_lock_state(void);

void zmk_studio_core_unlock();
void zmk_studio_core_lock();
void zmk_studio_core_initiate_unlock();
void zmk_studio_core_complete_unlock();
64 changes: 62 additions & 2 deletions app/include/zmk/studio/rpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@

#include <proto/zmk/studio.pb.h>

#include <zmk/event_manager.h>
#include <zmk/studio/core.h>

struct zmk_studio_rpc_notification {
zmk_Notification notification;
};

ZMK_EVENT_DECLARE(zmk_studio_rpc_notification);

struct zmk_rpc_subsystem;

typedef zmk_Response(subsystem_func)(const struct zmk_rpc_subsystem *subsys,
Expand All @@ -23,8 +32,11 @@ struct zmk_rpc_subsystem_handler {
rpc_func *func;
uint8_t subsystem_choice;
uint8_t request_choice;
bool secured;
};

#define ZMK_RPC_NO_RESPONSE() ZMK_RPC_RESPONSE(meta, no_response, true)

#define ZMK_RPC_SUBSYSTEM(prefix) \
zmk_Response subsystem_func_##prefix(const struct zmk_rpc_subsystem *subsys, \
const zmk_Request *req) { \
Expand All @@ -35,6 +47,11 @@ struct zmk_rpc_subsystem_handler {
struct zmk_rpc_subsystem_handler *sub_handler; \
STRUCT_SECTION_GET(zmk_rpc_subsystem_handler, i, &sub_handler); \
if (sub_handler->request_choice == which_req) { \
if (sub_handler->secured && \
zmk_studio_core_get_lock_state() != ZMK_STUDIO_CORE_LOCK_STATE_UNLOCKED) { \
return ZMK_RPC_RESPONSE(meta, simple_error, \
zmk_meta_ErrorConditions_UNLOCK_REQUIRED); \
} \
return sub_handler->func(req); \
} \
} \
Expand All @@ -46,14 +63,28 @@ struct zmk_rpc_subsystem_handler {
.subsystem_choice = zmk_Request_##prefix##_tag, \
};

#define ZMK_RPC_SUBSYSTEM_HANDLER(prefix, request_id) \
#define ZMK_RPC_SUBSYSTEM_HANDLER(prefix, request_id, _secured) \
STRUCT_SECTION_ITERABLE(zmk_rpc_subsystem_handler, \
prefix##_subsystem_handler_##request_id) = { \
.func = request_id, \
.subsystem_choice = zmk_Request_##prefix##_tag, \
.request_choice = zmk_##prefix##_Response_##request_id##_tag, \
.request_choice = zmk_##prefix##_Request_##request_id##_tag, \
.secured = _secured, \
};

#define ZMK_RPC_NOTIFICATION(subsys, _type, ...) \
((zmk_Notification){ \
.which_subsystem = zmk_Notification_##subsys##_tag, \
.subsystem = \
{ \
.subsys = \
{ \
.which_notification_type = zmk_##subsys##_Notification_##_type##_tag, \
.notification_type = {._type = __VA_ARGS__}, \
}, \
}, \
})

#define ZMK_RPC_RESPONSE(subsys, _type, ...) \
((zmk_Response){ \
.which_type = zmk_Response_request_response_tag, \
Expand All @@ -75,4 +106,33 @@ struct zmk_rpc_subsystem_handler {
}, \
})

#define ZMK_RPC_NOTIFICATION_PUBLISHER(name, _cb) \
static int name##_listener_cb(const zmk_event_t *eh) { \
struct zmk_studio_rpc_notification *notif = as_zmk_studio_rpc_notification(eh); \
__ASSERT(notif, "Only notification events should be received"); \
\
zmk_Response resp = zmk_Response_init_zero; \
resp.which_type = zmk_Response_notification_tag; \
resp.type.notification = notif->notification; \
_cb(&resp); \
\
return ZMK_EV_EVENT_BUBBLE; \
}; \
ZMK_LISTENER(name##_listener, name##_listener_cb); \
ZMK_SUBSCRIPTION(name##_listener, zmk_studio_rpc_notification);

typedef int(zmk_rpc_event_mapper_cb)(const zmk_event_t *ev, zmk_Notification *n);

struct zmk_rpc_event_mapper {
zmk_rpc_event_mapper_cb *func;
};

#define ZMK_RPC_EVENT_MAPPER_ADD_LISTENER(_t) ZMK_SUBSCRIPTION(studio_rpc, _t)

#define ZMK_RPC_EVENT_MAPPER(name, _func, ...) \
FOR_EACH_NONEMPTY_TERM(ZMK_RPC_EVENT_MAPPER_ADD_LISTENER, (;), __VA_ARGS__) \
STRUCT_SECTION_ITERABLE(zmk_rpc_event_mapper, name) = { \
.func = _func, \
};

zmk_Response zmk_rpc_handle_request(const zmk_Request *req);
3 changes: 0 additions & 3 deletions app/proto/zmk/behaviors.options

This file was deleted.

3 changes: 3 additions & 0 deletions app/proto/zmk/behaviors.options.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
zmk.behaviors.GetBehaviorDetailsResponse.friendly_name max_size:20
zmk.behaviors.BehaviorBindingParameterStandard.name max_size:20
zmk.behaviors.BehaviorParameterValueDescription.name max_size:32
55 changes: 38 additions & 17 deletions app/proto/zmk/behaviors.proto
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,54 @@ message ListAllBehaviorsResponse {
message GetBehaviorDetailsResponse {
uint32 id = 1;
string friendly_name = 2;
behavior_binding_parameter_details param1 = 3;
behavior_binding_parameter_details param2 = 4;
BehaviorBindingParameters parameters = 3;
}

message behavior_binding_parameter_details {
behavior_binding_parameter_domain domain = 1;
string name = 2;
}

message behavior_binding_parameter_domain {
oneof type {
behavior_binding_parameter_domain_standard standard = 1;
behavior_binding_parameter_domain_custom custom = 2;
message BehaviorBindingParameters {
oneof parameter_types {
BehaviorBindingParametersStandard standard = 1;
BehaviorBindingParametersCustom custom = 2;
}
}

message behavior_binding_parameter_domain_custom {
repeated behavior_binding_parameter_value_description values = 1;
message BehaviorBindingParametersStandard {
BehaviorBindingParameterStandard param1 = 1;
BehaviorBindingParameterStandard param2 = 2;

}

message behavior_binding_parameter_value_description {
int32 value = 1;
message BehaviorBindingParameterStandard {
BehaviorBindingParameterStandardDomain domain = 1;
string name = 2;
}

enum behavior_binding_parameter_domain_standard {
enum BehaviorBindingParameterStandardDomain {
NIL = 0;
HID_USAGE = 1;
LAYER_INDEX = 2;
}
HSV_VALUE = 3;
}

message BehaviorBindingParametersCustom {
repeated BehaviorBindingParametersCustomSet param_sets = 1;
}

message BehaviorBindingParametersCustomSet {
repeated BehaviorParameterValueDescription param1 = 1;
repeated BehaviorParameterValueDescription param2 = 2;
}

message BehaviorParameterValueDescriptionRange {
uint32 min = 1;
uint32 max = 2;
}

message BehaviorParameterValueDescription {
string name = 1;

oneof value_type {
uint32 constant = 2;
BehaviorParameterValueDescriptionRange range = 3;
BehaviorBindingParameterStandardDomain standard = 4;
}
}
24 changes: 16 additions & 8 deletions app/proto/zmk/core.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,28 @@ syntax = "proto3";

package zmk.core;

enum LockState {
ZMK_STUDIO_CORE_LOCK_STATE_LOCKED = 0;
ZMK_STUDIO_CORE_LOCK_STATE_UNLOCKING = 1;
ZMK_STUDIO_CORE_LOCK_STATE_UNLOCKED = 2;
}

message Request {
oneof request_type {
bool get_lock_status = 1;
bool unlock_request = 2;
bool lock_request = 3;
bool get_lock_state = 1;
bool request_unlock = 2;
bool lock = 3;
}
}

message GetLockStatusResponse {
bool locked = 1;
}

message Response {
oneof response_type {
GetLockStatusResponse get_lock_status = 1;
LockState get_lock_state = 1;
}
}

message Notification {
oneof notification_type {
LockState lock_state_changed = 1;
}
}
10 changes: 6 additions & 4 deletions app/proto/zmk/meta.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ package zmk.meta;

enum ErrorConditions {
GENERIC = 0;
RPC_NOT_FOUND = 1;
MSG_DECODE_FAILED = 2;
MSG_ENCODE_FAILED = 3;
UNLOCK_REQUIRED = 1;
RPC_NOT_FOUND = 2;
MSG_DECODE_FAILED = 3;
MSG_ENCODE_FAILED = 4;
}

message Response {
oneof response_type {
ErrorConditions simple_error = 1;
bool no_response = 1;
ErrorConditions simple_error = 2;
}
}
54 changes: 0 additions & 54 deletions app/proto/zmk/studio-msgs.cddl

This file was deleted.

4 changes: 3 additions & 1 deletion app/proto/zmk/studio.proto
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,7 @@ message RequestResponse {
}

message Notification {
uint32 notification_type = 1;
oneof subsystem {
zmk.core.Notification core = 2;
}
}
6 changes: 6 additions & 0 deletions app/src/studio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@

zephyr_linker_sources(DATA_SECTIONS ../../include/linker/zmk-rpc-subsystems.ld)
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-subsystem-handlers.ld)
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-event-mappers.ld)

target_sources(app PRIVATE common.c)
target_sources(app PRIVATE rpc.c)
target_sources(app PRIVATE core.c)
target_sources(app PRIVATE behavior_subsystem.c)
target_sources(app PRIVATE core_subsystem.c)
target_sources_ifdef(CONFIG_ZMK_STUDIO_INTERFACE_UART app PRIVATE uart_rpc_interface.c)
target_sources_ifdef(CONFIG_ZMK_STUDIO_INTERFACE_BLE app PRIVATE gatt_rpc_interface.c)
Loading

0 comments on commit 5e408c5

Please sign in to comment.