logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

nvm_dynamic_keymap.c (8588B)


  1. // Copyright 2024 Nick Brassel (@tzarc)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "compiler_support.h"
  4. #include "keycodes.h"
  5. #include "eeprom.h"
  6. #include "dynamic_keymap.h"
  7. #include "nvm_dynamic_keymap.h"
  8. #include "nvm_eeprom_eeconfig_internal.h"
  9. #include "nvm_eeprom_via_internal.h"
  10. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  11. #ifdef ENCODER_ENABLE
  12. # include "encoder.h"
  13. #endif
  14. #ifdef VIA_ENABLE
  15. # include "via.h"
  16. # define DYNAMIC_KEYMAP_EEPROM_START (VIA_EEPROM_CONFIG_END)
  17. #else
  18. # define DYNAMIC_KEYMAP_EEPROM_START (EECONFIG_SIZE)
  19. #endif
  20. #ifndef DYNAMIC_KEYMAP_EEPROM_MAX_ADDR
  21. # define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR (TOTAL_EEPROM_BYTE_COUNT - 1)
  22. #endif
  23. STATIC_ASSERT(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR <= (TOTAL_EEPROM_BYTE_COUNT - 1), "DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is configured to use more space than what is available for the selected EEPROM driver");
  24. // Due to usage of uint16_t check for max 65535
  25. STATIC_ASSERT(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR <= 65535, "DYNAMIC_KEYMAP_EEPROM_MAX_ADDR must be less than 65536");
  26. // If DYNAMIC_KEYMAP_EEPROM_ADDR not explicitly defined in config.h,
  27. #ifndef DYNAMIC_KEYMAP_EEPROM_ADDR
  28. # define DYNAMIC_KEYMAP_EEPROM_ADDR DYNAMIC_KEYMAP_EEPROM_START
  29. #endif
  30. // Dynamic encoders starts after dynamic keymaps
  31. #ifndef DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR
  32. # define DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR (DYNAMIC_KEYMAP_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2))
  33. #endif
  34. // Dynamic macro starts after dynamic encoders, but only when using ENCODER_MAP
  35. #ifdef ENCODER_MAP_ENABLE
  36. # ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
  37. # define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * NUM_ENCODERS * 2 * 2))
  38. # endif // DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
  39. #else // ENCODER_MAP_ENABLE
  40. # ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
  41. # define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR)
  42. # endif // DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
  43. #endif // ENCODER_MAP_ENABLE
  44. // Sanity check that dynamic keymaps fit in available EEPROM
  45. // If there's not 100 bytes available for macros, then something is wrong.
  46. // The keyboard should override DYNAMIC_KEYMAP_LAYER_COUNT to reduce it,
  47. // or DYNAMIC_KEYMAP_EEPROM_MAX_ADDR to increase it, *only if* the microcontroller has
  48. // more than the default.
  49. STATIC_ASSERT((int64_t)(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) - (int64_t)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR) >= 100, "Dynamic keymaps are configured to use more EEPROM than is available.");
  50. #ifndef TOTAL_EEPROM_BYTE_COUNT
  51. # error Unknown total EEPROM size. Cannot derive maximum for dynamic keymaps.
  52. #endif
  53. // Dynamic macros are stored after the keymaps and use what is available
  54. // up to and including DYNAMIC_KEYMAP_EEPROM_MAX_ADDR.
  55. #ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE
  56. # define DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR - DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + 1)
  57. #endif
  58. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  59. void nvm_dynamic_keymap_erase(void) {
  60. // No-op, nvm_eeconfig_erase() will have already erased EEPROM if necessary.
  61. }
  62. void nvm_dynamic_keymap_macro_erase(void) {
  63. // No-op, nvm_eeconfig_erase() will have already erased EEPROM if necessary.
  64. }
  65. static inline void *dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t column) {
  66. return ((void *)DYNAMIC_KEYMAP_EEPROM_ADDR) + (layer * MATRIX_ROWS * MATRIX_COLS * 2) + (row * MATRIX_COLS * 2) + (column * 2);
  67. }
  68. uint16_t nvm_dynamic_keymap_read_keycode(uint8_t layer, uint8_t row, uint8_t column) {
  69. if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return KC_NO;
  70. void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column);
  71. // Big endian, so we can read/write EEPROM directly from host if we want
  72. uint16_t keycode = eeprom_read_byte(address) << 8;
  73. keycode |= eeprom_read_byte(address + 1);
  74. return keycode;
  75. }
  76. void nvm_dynamic_keymap_update_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode) {
  77. if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return;
  78. void *address = dynamic_keymap_key_to_eeprom_address(layer, row, column);
  79. // Big endian, so we can read/write EEPROM directly from host if we want
  80. eeprom_update_byte(address, (uint8_t)(keycode >> 8));
  81. eeprom_update_byte(address + 1, (uint8_t)(keycode & 0xFF));
  82. }
  83. #ifdef ENCODER_MAP_ENABLE
  84. static void *dynamic_keymap_encoder_to_eeprom_address(uint8_t layer, uint8_t encoder_id) {
  85. return ((void *)DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR) + (layer * NUM_ENCODERS * 2 * 2) + (encoder_id * 2 * 2);
  86. }
  87. uint16_t nvm_dynamic_keymap_read_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise) {
  88. if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return KC_NO;
  89. void *address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id);
  90. // Big endian, so we can read/write EEPROM directly from host if we want
  91. uint16_t keycode = ((uint16_t)eeprom_read_byte(address + (clockwise ? 0 : 2))) << 8;
  92. keycode |= eeprom_read_byte(address + (clockwise ? 0 : 2) + 1);
  93. return keycode;
  94. }
  95. void nvm_dynamic_keymap_update_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise, uint16_t keycode) {
  96. if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return;
  97. void *address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id);
  98. // Big endian, so we can read/write EEPROM directly from host if we want
  99. eeprom_update_byte(address + (clockwise ? 0 : 2), (uint8_t)(keycode >> 8));
  100. eeprom_update_byte(address + (clockwise ? 0 : 2) + 1, (uint8_t)(keycode & 0xFF));
  101. }
  102. #endif // ENCODER_MAP_ENABLE
  103. void nvm_dynamic_keymap_read_buffer(uint32_t offset, uint32_t size, uint8_t *data) {
  104. uint32_t dynamic_keymap_eeprom_size = DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2;
  105. void * source = (void *)(uintptr_t)(DYNAMIC_KEYMAP_EEPROM_ADDR + offset);
  106. uint8_t *target = data;
  107. for (uint32_t i = 0; i < size; i++) {
  108. if (offset + i < dynamic_keymap_eeprom_size) {
  109. *target = eeprom_read_byte(source);
  110. } else {
  111. *target = 0x00;
  112. }
  113. source++;
  114. target++;
  115. }
  116. }
  117. void nvm_dynamic_keymap_update_buffer(uint32_t offset, uint32_t size, uint8_t *data) {
  118. uint32_t dynamic_keymap_eeprom_size = DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2;
  119. void * target = (void *)(uintptr_t)(DYNAMIC_KEYMAP_EEPROM_ADDR + offset);
  120. uint8_t *source = data;
  121. for (uint32_t i = 0; i < size; i++) {
  122. if (offset + i < dynamic_keymap_eeprom_size) {
  123. eeprom_update_byte(target, *source);
  124. }
  125. source++;
  126. target++;
  127. }
  128. }
  129. uint32_t nvm_dynamic_keymap_macro_size(void) {
  130. return DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE;
  131. }
  132. void nvm_dynamic_keymap_macro_read_buffer(uint32_t offset, uint32_t size, uint8_t *data) {
  133. void * source = (void *)(uintptr_t)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + offset);
  134. uint8_t *target = data;
  135. for (uint16_t i = 0; i < size; i++) {
  136. if (offset + i < DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE) {
  137. *target = eeprom_read_byte(source);
  138. } else {
  139. *target = 0x00;
  140. }
  141. source++;
  142. target++;
  143. }
  144. }
  145. void nvm_dynamic_keymap_macro_update_buffer(uint32_t offset, uint32_t size, uint8_t *data) {
  146. void * target = (void *)(uintptr_t)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + offset);
  147. uint8_t *source = data;
  148. for (uint16_t i = 0; i < size; i++) {
  149. if (offset + i < DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE) {
  150. eeprom_update_byte(target, *source);
  151. }
  152. source++;
  153. target++;
  154. }
  155. }
  156. void nvm_dynamic_keymap_macro_reset(void) {
  157. void * start = (void *)(uintptr_t)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR);
  158. void * end = (void *)(uintptr_t)(DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE);
  159. long remaining = end - start;
  160. uint8_t dummy[16] = {0};
  161. for (int i = 0; i < DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE; i += sizeof(dummy)) {
  162. int this_loop = remaining < sizeof(dummy) ? remaining : sizeof(dummy);
  163. eeprom_update_block(dummy, start, this_loop);
  164. start += this_loop;
  165. remaining -= this_loop;
  166. }
  167. }