Non-volatile memory data repository pattern (#24356)
* First batch of eeconfig conversions. * Offset and length for datablocks. * `via`, `dynamic_keymap`. * Fix filename. * Commentary. * wilba leds * satisfaction75 * satisfaction75 * more keyboard whack-a-mole * satisfaction75 * omnikeyish * more whack-a-mole * `generic_features.mk` to automatically pick up nvm repositories * thievery * deferred variable resolve * whitespace * convert api to structs/unions * convert api to structs/unions * convert api to structs/unions * fixups * code-side docs * code size fix * rollback * nvm_xxxxx_erase * Updated location of eeconfig magic numbers so non-EEPROM nvm drivers can use them too. * Fixup build. * Fixup compilation error with encoders. * Build fixes. * Add `via_ci` keymap to onekey to exercise VIA bindings (and thus dynamic keymap et.al.), fixup compilation errors based on preprocessor+sizeof. * Build failure rectification.
This commit is contained in:
parent
c9d62ddc78
commit
2b00b846dc
87 changed files with 1464 additions and 839 deletions
|
@ -1,4 +1,5 @@
|
|||
/* Copyright 2017 Jason Williams (Wilba)
|
||||
* Copyright 2024-2025 Nick Brassel (@tzarc)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -21,14 +22,7 @@
|
|||
#include "progmem.h"
|
||||
#include "send_string.h"
|
||||
#include "keycodes.h"
|
||||
|
||||
#ifdef VIA_ENABLE
|
||||
# include "via.h"
|
||||
# define DYNAMIC_KEYMAP_EEPROM_START (VIA_EEPROM_CONFIG_END)
|
||||
#else
|
||||
# include "eeconfig.h"
|
||||
# define DYNAMIC_KEYMAP_EEPROM_START (EECONFIG_SIZE)
|
||||
#endif
|
||||
#include "nvm_dynamic_keymap.h"
|
||||
|
||||
#ifdef ENCODER_ENABLE
|
||||
# include "encoder.h"
|
||||
|
@ -36,67 +30,6 @@
|
|||
# define NUM_ENCODERS 0
|
||||
#endif
|
||||
|
||||
#ifndef DYNAMIC_KEYMAP_LAYER_COUNT
|
||||
# define DYNAMIC_KEYMAP_LAYER_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifndef DYNAMIC_KEYMAP_MACRO_COUNT
|
||||
# define DYNAMIC_KEYMAP_MACRO_COUNT 16
|
||||
#endif
|
||||
|
||||
#ifndef TOTAL_EEPROM_BYTE_COUNT
|
||||
# error Unknown total EEPROM size. Cannot derive maximum for dynamic keymaps.
|
||||
#endif
|
||||
|
||||
#ifndef DYNAMIC_KEYMAP_EEPROM_MAX_ADDR
|
||||
# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR (TOTAL_EEPROM_BYTE_COUNT - 1)
|
||||
#endif
|
||||
|
||||
#if DYNAMIC_KEYMAP_EEPROM_MAX_ADDR > (TOTAL_EEPROM_BYTE_COUNT - 1)
|
||||
# pragma message STR(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) " > " STR((TOTAL_EEPROM_BYTE_COUNT - 1))
|
||||
# error DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is configured to use more space than what is available for the selected EEPROM driver
|
||||
#endif
|
||||
|
||||
// Due to usage of uint16_t check for max 65535
|
||||
#if DYNAMIC_KEYMAP_EEPROM_MAX_ADDR > 65535
|
||||
# pragma message STR(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) " > 65535"
|
||||
# error DYNAMIC_KEYMAP_EEPROM_MAX_ADDR must be less than 65536
|
||||
#endif
|
||||
|
||||
// If DYNAMIC_KEYMAP_EEPROM_ADDR not explicitly defined in config.h,
|
||||
#ifndef DYNAMIC_KEYMAP_EEPROM_ADDR
|
||||
# define DYNAMIC_KEYMAP_EEPROM_ADDR DYNAMIC_KEYMAP_EEPROM_START
|
||||
#endif
|
||||
|
||||
// Dynamic encoders starts after dynamic keymaps
|
||||
#ifndef DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR
|
||||
# define DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR (DYNAMIC_KEYMAP_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2))
|
||||
#endif
|
||||
|
||||
// Dynamic macro starts after dynamic encoders, but only when using ENCODER_MAP
|
||||
#ifdef ENCODER_MAP_ENABLE
|
||||
# ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
|
||||
# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * NUM_ENCODERS * 2 * 2))
|
||||
# endif // DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
|
||||
#else // ENCODER_MAP_ENABLE
|
||||
# ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
|
||||
# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR)
|
||||
# endif // DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
|
||||
#endif // ENCODER_MAP_ENABLE
|
||||
|
||||
// Sanity check that dynamic keymaps fit in available EEPROM
|
||||
// If there's not 100 bytes available for macros, then something is wrong.
|
||||
// The keyboard should override DYNAMIC_KEYMAP_LAYER_COUNT to reduce it,
|
||||
// or DYNAMIC_KEYMAP_EEPROM_MAX_ADDR to increase it, *only if* the microcontroller has
|
||||
// more than the default.
|
||||
_Static_assert((DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) - (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR) >= 100, "Dynamic keymaps are configured to use more EEPROM than is available.");
|
||||
|
||||
// Dynamic macros are stored after the keymaps and use what is available
|
||||
// up to and including DYNAMIC_KEYMAP_EEPROM_MAX_ADDR.
|
||||
#ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE
|
||||
# define DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR - DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + 1)
|
||||
#endif
|
||||
|
||||
#ifndef DYNAMIC_KEYMAP_MACRO_DELAY
|
||||
# define DYNAMIC_KEYMAP_MACRO_DELAY TAP_CODE_DELAY
|
||||
#endif
|
||||
|
@ -105,52 +38,28 @@ uint8_t dynamic_keymap_get_layer_count(void) {
|
|||
return DYNAMIC_KEYMAP_LAYER_COUNT;
|
||||
}
|
||||
|
||||
void *dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t column) {
|
||||
// TODO: optimize this with some left shifts
|
||||
return ((void *)DYNAMIC_KEYMAP_EEPROM_ADDR) + (layer * MATRIX_ROWS * MATRIX_COLS * 2) + (row * MATRIX_COLS * 2) + (column * 2);
|
||||
}
|
||||
|
||||
uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column) {
|
||||
if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return KC_NO;
|
||||
void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column);
|
||||
// Big endian, so we can read/write EEPROM directly from host if we want
|
||||
uint16_t keycode = eeprom_read_byte(address) << 8;
|
||||
keycode |= eeprom_read_byte(address + 1);
|
||||
return keycode;
|
||||
return nvm_dynamic_keymap_read_keycode(layer, row, column);
|
||||
}
|
||||
|
||||
void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode) {
|
||||
if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return;
|
||||
void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column);
|
||||
// Big endian, so we can read/write EEPROM directly from host if we want
|
||||
eeprom_update_byte(address, (uint8_t)(keycode >> 8));
|
||||
eeprom_update_byte(address + 1, (uint8_t)(keycode & 0xFF));
|
||||
nvm_dynamic_keymap_update_keycode(layer, row, column, keycode);
|
||||
}
|
||||
|
||||
#ifdef ENCODER_MAP_ENABLE
|
||||
void *dynamic_keymap_encoder_to_eeprom_address(uint8_t layer, uint8_t encoder_id) {
|
||||
return ((void *)DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR) + (layer * NUM_ENCODERS * 2 * 2) + (encoder_id * 2 * 2);
|
||||
}
|
||||
|
||||
uint16_t dynamic_keymap_get_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise) {
|
||||
if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return KC_NO;
|
||||
void *address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id);
|
||||
// Big endian, so we can read/write EEPROM directly from host if we want
|
||||
uint16_t keycode = ((uint16_t)eeprom_read_byte(address + (clockwise ? 0 : 2))) << 8;
|
||||
keycode |= eeprom_read_byte(address + (clockwise ? 0 : 2) + 1);
|
||||
return keycode;
|
||||
return nvm_dynamic_keymap_read_encoder(layer, encoder_id, clockwise);
|
||||
}
|
||||
|
||||
void dynamic_keymap_set_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise, uint16_t keycode) {
|
||||
if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return;
|
||||
void *address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id);
|
||||
// Big endian, so we can read/write EEPROM directly from host if we want
|
||||
eeprom_update_byte(address + (clockwise ? 0 : 2), (uint8_t)(keycode >> 8));
|
||||
eeprom_update_byte(address + (clockwise ? 0 : 2) + 1, (uint8_t)(keycode & 0xFF));
|
||||
nvm_dynamic_keymap_update_encoder(layer, encoder_id, clockwise, keycode);
|
||||
}
|
||||
#endif // ENCODER_MAP_ENABLE
|
||||
|
||||
void dynamic_keymap_reset(void) {
|
||||
// Erase the keymaps, if necessary.
|
||||
nvm_dynamic_keymap_erase();
|
||||
|
||||
// Reset the keymaps in EEPROM to what is in flash.
|
||||
for (int layer = 0; layer < DYNAMIC_KEYMAP_LAYER_COUNT; layer++) {
|
||||
for (int row = 0; row < MATRIX_ROWS; row++) {
|
||||
|
@ -168,31 +77,11 @@ void dynamic_keymap_reset(void) {
|
|||
}
|
||||
|
||||
void dynamic_keymap_get_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
|
||||
uint16_t dynamic_keymap_eeprom_size = DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2;
|
||||
void * source = (void *)(DYNAMIC_KEYMAP_EEPROM_ADDR + offset);
|
||||
uint8_t *target = data;
|
||||
for (uint16_t i = 0; i < size; i++) {
|
||||
if (offset + i < dynamic_keymap_eeprom_size) {
|
||||
*target = eeprom_read_byte(source);
|
||||
} else {
|
||||
*target = 0x00;
|
||||
}
|
||||
source++;
|
||||
target++;
|
||||
}
|
||||
nvm_dynamic_keymap_read_buffer(offset, size, data);
|
||||
}
|
||||
|
||||
void dynamic_keymap_set_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
|
||||
uint16_t dynamic_keymap_eeprom_size = DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2;
|
||||
void * target = (void *)(DYNAMIC_KEYMAP_EEPROM_ADDR + offset);
|
||||
uint8_t *source = data;
|
||||
for (uint16_t i = 0; i < size; i++) {
|
||||
if (offset + i < dynamic_keymap_eeprom_size) {
|
||||
eeprom_update_byte(target, *source);
|
||||
}
|
||||
source++;
|
||||
target++;
|
||||
}
|
||||
nvm_dynamic_keymap_update_buffer(offset, size, data);
|
||||
}
|
||||
|
||||
uint16_t keycode_at_keymap_location(uint8_t layer_num, uint8_t row, uint8_t column) {
|
||||
|
@ -216,53 +105,38 @@ uint8_t dynamic_keymap_macro_get_count(void) {
|
|||
}
|
||||
|
||||
uint16_t dynamic_keymap_macro_get_buffer_size(void) {
|
||||
return DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE;
|
||||
return (uint16_t)nvm_dynamic_keymap_macro_size();
|
||||
}
|
||||
|
||||
void dynamic_keymap_macro_get_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
|
||||
void * source = (void *)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + offset);
|
||||
uint8_t *target = data;
|
||||
for (uint16_t i = 0; i < size; i++) {
|
||||
if (offset + i < DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE) {
|
||||
*target = eeprom_read_byte(source);
|
||||
} else {
|
||||
*target = 0x00;
|
||||
}
|
||||
source++;
|
||||
target++;
|
||||
}
|
||||
nvm_dynamic_keymap_macro_read_buffer(offset, size, data);
|
||||
}
|
||||
|
||||
void dynamic_keymap_macro_set_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
|
||||
void * target = (void *)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + offset);
|
||||
uint8_t *source = data;
|
||||
for (uint16_t i = 0; i < size; i++) {
|
||||
if (offset + i < DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE) {
|
||||
eeprom_update_byte(target, *source);
|
||||
}
|
||||
source++;
|
||||
target++;
|
||||
}
|
||||
nvm_dynamic_keymap_macro_update_buffer(offset, size, data);
|
||||
}
|
||||
|
||||
typedef struct send_string_eeprom_state_t {
|
||||
const uint8_t *ptr;
|
||||
} send_string_eeprom_state_t;
|
||||
static uint8_t dynamic_keymap_read_byte(uint32_t offset) {
|
||||
uint8_t d;
|
||||
nvm_dynamic_keymap_macro_read_buffer(offset, 1, &d);
|
||||
return d;
|
||||
}
|
||||
|
||||
char send_string_get_next_eeprom(void *arg) {
|
||||
send_string_eeprom_state_t *state = (send_string_eeprom_state_t *)arg;
|
||||
char ret = eeprom_read_byte(state->ptr);
|
||||
state->ptr++;
|
||||
typedef struct send_string_nvm_state_t {
|
||||
uint32_t offset;
|
||||
} send_string_nvm_state_t;
|
||||
|
||||
char send_string_get_next_nvm(void *arg) {
|
||||
send_string_nvm_state_t *state = (send_string_nvm_state_t *)arg;
|
||||
char ret = dynamic_keymap_read_byte(state->offset);
|
||||
state->offset++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dynamic_keymap_macro_reset(void) {
|
||||
void *p = (void *)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR);
|
||||
void *end = (void *)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE);
|
||||
while (p != end) {
|
||||
eeprom_update_byte(p, 0);
|
||||
++p;
|
||||
}
|
||||
// Erase the macros, if necessary.
|
||||
nvm_dynamic_keymap_macro_erase();
|
||||
nvm_dynamic_keymap_macro_reset();
|
||||
}
|
||||
|
||||
void dynamic_keymap_macro_send(uint8_t id) {
|
||||
|
@ -274,27 +148,26 @@ void dynamic_keymap_macro_send(uint8_t id) {
|
|||
// If it's not zero, then we are in the middle
|
||||
// of buffer writing, possibly an aborted buffer
|
||||
// write. So do nothing.
|
||||
void *p = (void *)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE - 1);
|
||||
if (eeprom_read_byte(p) != 0) {
|
||||
if (dynamic_keymap_read_byte(nvm_dynamic_keymap_macro_size() - 1) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip N null characters
|
||||
// p will then point to the Nth macro
|
||||
p = (void *)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR);
|
||||
void *end = (void *)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE);
|
||||
uint32_t offset = 0;
|
||||
uint32_t end = nvm_dynamic_keymap_macro_size();
|
||||
while (id > 0) {
|
||||
// If we are past the end of the buffer, then there is
|
||||
// no Nth macro in the buffer.
|
||||
if (p == end) {
|
||||
if (offset == end) {
|
||||
return;
|
||||
}
|
||||
if (eeprom_read_byte(p) == 0) {
|
||||
if (dynamic_keymap_read_byte(offset) == 0) {
|
||||
--id;
|
||||
}
|
||||
++p;
|
||||
++offset;
|
||||
}
|
||||
|
||||
send_string_eeprom_state_t state = {p};
|
||||
send_string_with_delay_impl(send_string_get_next_eeprom, &state, DYNAMIC_KEYMAP_MACRO_DELAY);
|
||||
send_string_nvm_state_t state = {.offset = 0};
|
||||
send_string_with_delay_impl(send_string_get_next_nvm, &state, DYNAMIC_KEYMAP_MACRO_DELAY);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue