Initial work to refactor persistence outside of just keymaps.

This commit is contained in:
Peter Johanson 2025-11-17 16:04:36 -07:00
parent cd27866c95
commit bd2fc145c7
9 changed files with 131 additions and 43 deletions

View File

@ -6,4 +6,4 @@
#include <zephyr/linker/linker-defs.h>
ITERABLE_SECTION_ROM(zmk_rpc_subsystem_settings_reset, 4)
ITERABLE_SECTION_ROM(zmk_rpc_subsystem_persistence, 4)

View File

@ -73,10 +73,10 @@ int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t
/**
* @brief Check if there are any unsaved keymap changes.
*
* @retval 0 if there are no changes.
* @retval 1 if there are changes.
* @retval true if there are no changes.
* @retval false if there are changes.
*/
int zmk_keymap_check_unsaved_changes(void);
bool zmk_keymap_check_unsaved_changes(void);
int zmk_keymap_save_changes(void);
int zmk_keymap_discard_changes(void);

View File

@ -48,7 +48,7 @@ size_t zmk_physical_layouts_get_list(struct zmk_physical_layout const *const **p
int zmk_physical_layouts_select(uint8_t index);
int zmk_physical_layouts_get_selected(void);
int zmk_physical_layouts_check_unsaved_selection(void);
bool zmk_physical_layouts_check_unsaved_selection(void);
int zmk_physical_layouts_save_selected(void);
int zmk_physical_layouts_revert_selected(void);

View File

@ -56,10 +56,16 @@ struct zmk_rpc_subsystem_handler {
enum zmk_studio_rpc_handler_security security;
};
typedef int (*zmk_rpc_subsystem_settings_reset_func)(void);
typedef int (*zmk_rpc_subsystem_reset_settings_func_t)(void);
typedef int (*zmk_rpc_subsystem_discard_changes_func_t)(void);
typedef bool (*zmk_rpc_subsystem_check_unsaved_changes_func_t)(void);
typedef int (*zmk_rpc_subsystem_save_changes_func_t)(void);
struct zmk_rpc_subsystem_settings_reset {
zmk_rpc_subsystem_settings_reset_func callback;
struct zmk_rpc_subsystem_persistence {
zmk_rpc_subsystem_reset_settings_func_t reset_settings;
zmk_rpc_subsystem_check_unsaved_changes_func_t check_unsaved_changes;
zmk_rpc_subsystem_save_changes_func_t save_changes;
zmk_rpc_subsystem_discard_changes_func_t discard_changes;
};
/**
@ -109,13 +115,12 @@ struct zmk_rpc_subsystem_settings_reset {
.security = _security, \
};
#define ZMK_RPC_SUBSYSTEM_SETTINGS_RESET(prefix, _callback) \
STRUCT_SECTION_ITERABLE(zmk_rpc_subsystem_settings_reset, _##prefix##_settings_reset) = { \
.callback = _callback, \
};
#define ZMK_RPC_SUBSYSTEM_PERSISTENCE(prefix, ...) \
STRUCT_SECTION_ITERABLE(zmk_rpc_subsystem_persistence, \
_##prefix##_settings_reset) = {__VA_ARGS__};
#define ZMK_RPC_SUBSYSTEM_SETTINGS_RESET_FOREACH(_var) \
STRUCT_SECTION_FOREACH(zmk_rpc_subsystem_settings_reset, _var)
#define ZMK_RPC_SUBSYSTEM_PERSISTENCE_FOREACH(_var) \
STRUCT_SECTION_FOREACH(zmk_rpc_subsystem_persistence, _var)
/**
* @brief Create a zmk_studio_Notification struct for the given subsystem and type, including

View File

@ -472,23 +472,23 @@ struct zmk_behavior_binding_setting {
uint32_t param2;
} __packed;
int zmk_keymap_check_unsaved_changes(void) {
bool zmk_keymap_check_unsaved_changes(void) {
for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) {
uint8_t *pending = zmk_keymap_layer_pending_changes[l];
for (int kp = 0; kp < ZMK_KEYMAP_LEN; kp++) {
if (pending[kp / 8] & BIT(kp % 8)) {
return 1;
return true;
}
}
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
if (settings_layer_orders[l] != keymap_layer_orders[l]) {
return 1;
return true;
}
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
}
return 0;
return false;
}
#define LAYER_ORDER_SETTINGS_KEY "keymap/layer_order"

View File

@ -416,14 +416,12 @@ int zmk_physical_layouts_select_initial(void) {
return ret;
}
int zmk_physical_layouts_check_unsaved_selection(void) {
bool zmk_physical_layouts_check_unsaved_selection(void) {
#if IS_ENABLED(CONFIG_SETTINGS)
return saved_selected_index < 0 ||
saved_selected_index == (uint8_t)zmk_physical_layouts_get_selected()
? 0
: 1;
return !(saved_selected_index < 0 ||
saved_selected_index == (uint8_t)zmk_physical_layouts_get_selected());
#else
return -ENOTSUP;
return false;
#endif
}

View File

@ -3,7 +3,7 @@
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-subsystem-settings-reset.ld)
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-subsystem-persistence.ld)
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-event-mappers.ld)
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-transport.ld)

View File

@ -65,8 +65,8 @@ zmk_studio_Response get_lock_state(const zmk_studio_Request *req) {
zmk_studio_Response reset_settings(const zmk_studio_Request *req) {
LOG_DBG("");
ZMK_RPC_SUBSYSTEM_SETTINGS_RESET_FOREACH(sub) {
int ret = sub->callback();
ZMK_RPC_SUBSYSTEM_PERSISTENCE_FOREACH(sub) {
int ret = sub->reset_settings();
if (ret < 0) {
LOG_ERR("Failed to reset settings: %d", ret);
return CORE_RESPONSE(reset_settings, false);
@ -76,9 +76,68 @@ zmk_studio_Response reset_settings(const zmk_studio_Request *req) {
return CORE_RESPONSE(reset_settings, true);
}
static zmk_studio_Response check_unsaved_changes(const zmk_studio_Request *req) {
LOG_DBG("");
bool unsaved = false;
ZMK_RPC_SUBSYSTEM_PERSISTENCE_FOREACH(p) {
unsaved = p->check_unsaved_changes();
if (unsaved) {
break;
}
}
return CORE_RESPONSE(check_unsaved_changes, unsaved);
}
static zmk_studio_Response save_changes(const zmk_studio_Request *req) {
LOG_DBG("");
zmk_core_SaveChangesResponse resp = zmk_core_SaveChangesResponse_init_zero;
resp.which_result = zmk_core_SaveChangesResponse_ok_tag;
resp.result.ok = true;
ZMK_RPC_SUBSYSTEM_PERSISTENCE_FOREACH(p) {
int ret = p->save_changes();
if (ret < 0) {
resp.which_result = zmk_core_SaveChangesResponse_err_tag;
switch (ret) {
case -ENOTSUP:
resp.result.err = zmk_core_SaveChangesErrorCode_SAVE_CHANGES_ERR_NOT_SUPPORTED;
break;
case -ENOSPC:
resp.result.err = zmk_core_SaveChangesErrorCode_SAVE_CHANGES_ERR_NO_SPACE;
break;
default:
resp.result.err = zmk_core_SaveChangesErrorCode_SAVE_CHANGES_ERR_GENERIC;
break;
}
break;
}
}
return CORE_RESPONSE(save_changes, resp);
}
static zmk_studio_Response discard_changes(const zmk_studio_Request *req) {
LOG_DBG("");
int ret = 0;
ZMK_RPC_SUBSYSTEM_PERSISTENCE_FOREACH(p) {
ret = p->discard_changes();
if (ret < 0) {
LOG_ERR("Failed to discard changes for subsystem %p: %d", p, ret);
break;
}
}
return CORE_RESPONSE(discard_changes, ret >= 0);
}
ZMK_RPC_SUBSYSTEM_HANDLER(core, get_device_info, ZMK_STUDIO_RPC_HANDLER_UNSECURED);
ZMK_RPC_SUBSYSTEM_HANDLER(core, get_lock_state, ZMK_STUDIO_RPC_HANDLER_UNSECURED);
ZMK_RPC_SUBSYSTEM_HANDLER(core, reset_settings, ZMK_STUDIO_RPC_HANDLER_SECURED);
ZMK_RPC_SUBSYSTEM_HANDLER(core, check_unsaved_changes, ZMK_STUDIO_RPC_HANDLER_SECURED);
ZMK_RPC_SUBSYSTEM_HANDLER(core, save_changes, ZMK_STUDIO_RPC_HANDLER_SECURED);
ZMK_RPC_SUBSYSTEM_HANDLER(core, discard_changes, ZMK_STUDIO_RPC_HANDLER_SECURED);
static int core_event_mapper(const zmk_event_t *eh, zmk_studio_Notification *n) {
struct zmk_studio_core_lock_state_changed *lock_ev = as_zmk_studio_core_lock_state_changed(eh);

View File

@ -172,12 +172,15 @@ zmk_studio_Response set_layer_binding(const zmk_studio_Request *req) {
zmk_keymap_SetLayerBindingResponse_SET_LAYER_BINDING_RESP_OK);
}
static bool keymap_check_unsaved_changes(void) {
return zmk_physical_layouts_check_unsaved_selection() || zmk_keymap_check_unsaved_changes();
}
zmk_studio_Response check_unsaved_changes(const zmk_studio_Request *req) {
LOG_DBG("");
int layout_changes = zmk_physical_layouts_check_unsaved_selection();
int keymap_changes = zmk_keymap_check_unsaved_changes();
bool unsaved = keymap_check_unsaved_changes();
return KEYMAP_RESPONSE(check_unsaved_changes, layout_changes > 0 || keymap_changes > 0);
return KEYMAP_RESPONSE(check_unsaved_changes, unsaved);
}
static void map_errno_to_save_resp(int err, zmk_keymap_SaveChangesResponse *resp) {
@ -196,23 +199,32 @@ static void map_errno_to_save_resp(int err, zmk_keymap_SaveChangesResponse *resp
}
}
static int keymap_subsys_save_changes(void) {
int ret = zmk_physical_layouts_save_selected();
if (ret < 0) {
LOG_WRN("Failed to save selected physical layout (%d)", ret);
return ret;
}
ret = zmk_keymap_save_changes();
if (ret < 0) {
LOG_WRN("Failed to save keymap changes (%d)", ret);
return ret;
}
return 0;
}
zmk_studio_Response save_changes(const zmk_studio_Request *req) {
zmk_keymap_SaveChangesResponse resp = zmk_keymap_SaveChangesResponse_init_zero;
resp.which_result = zmk_keymap_SaveChangesResponse_ok_tag;
resp.result.ok = true;
LOG_DBG("");
int ret = zmk_physical_layouts_save_selected();
int ret = keymap_subsys_save_changes();
if (ret < 0) {
LOG_WRN("Failed to save selected physical layout (%d)", ret);
map_errno_to_save_resp(ret, &resp);
return KEYMAP_RESPONSE(save_changes, resp);
}
ret = zmk_keymap_save_changes();
if (ret < 0) {
LOG_WRN("Failed to save keymap changes (%d)", ret);
map_errno_to_save_resp(ret, &resp);
return KEYMAP_RESPONSE(save_changes, resp);
}
@ -223,14 +235,25 @@ zmk_studio_Response save_changes(const zmk_studio_Request *req) {
return KEYMAP_RESPONSE(save_changes, resp);
}
zmk_studio_Response discard_changes(const zmk_studio_Request *req) {
LOG_DBG("");
static int keymap_subsys_discard_changes(void) {
int ret = zmk_physical_layouts_revert_selected();
if (ret < 0) {
return ZMK_RPC_SIMPLE_ERR(GENERIC);
LOG_ERR("Failed to discard physical layout changes (%d)", ret);
return ret;
}
ret = zmk_keymap_discard_changes();
if (ret < 0) {
LOG_ERR("Failed to discard keymap changes (%d)", ret);
return ret;
}
return 0;
}
zmk_studio_Response discard_changes(const zmk_studio_Request *req) {
LOG_DBG("");
int ret = keymap_subsys_discard_changes();
if (ret < 0) {
return ZMK_RPC_SIMPLE_ERR(GENERIC);
}
@ -243,7 +266,10 @@ zmk_studio_Response discard_changes(const zmk_studio_Request *req) {
static int keymap_settings_reset(void) { return zmk_keymap_reset_settings(); }
ZMK_RPC_SUBSYSTEM_SETTINGS_RESET(keymap, keymap_settings_reset);
ZMK_RPC_SUBSYSTEM_PERSISTENCE(keymap, .reset_settings = keymap_settings_reset,
.check_unsaved_changes = keymap_check_unsaved_changes,
.save_changes = keymap_subsys_save_changes,
.discard_changes = keymap_subsys_discard_changes, );
static bool encode_layout_name(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) {
struct zmk_physical_layout *layout = (struct zmk_physical_layout *)*arg;