satisfaction_core.c (9904B)
1 // Copyright 2023 Andrew Kannan 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 4 #include "satisfaction_core.h" 5 #include "print.h" 6 #include "debug.h" 7 #include "matrix.h" 8 #include "quantum.h" 9 #include "encoder.h" 10 11 #include <ch.h> 12 #include <hal.h> 13 14 #include "timer.h" 15 16 #include "raw_hid.h" 17 #include "dynamic_keymap.h" 18 #include "eeprom.h" 19 #include "version.h" // for QMK_BUILDDATE used in EEPROM magic 20 21 /* Artificial delay added to get media keys to work in the encoder*/ 22 #define MEDIA_KEY_DELAY 10 23 24 volatile uint8_t led_numlock = false; 25 volatile uint8_t led_capslock = false; 26 volatile uint8_t led_scrolllock = false; 27 28 uint8_t layer; 29 30 bool clock_set_mode = false; 31 uint8_t oled_mode = OLED_DEFAULT; 32 bool oled_repaint_requested = false; 33 bool oled_wakeup_requested = false; 34 uint32_t oled_sleep_timer; 35 36 uint8_t encoder_value = 32; 37 uint8_t encoder_mode = ENC_MODE_VOLUME; 38 uint8_t enabled_encoder_modes = 0x1F; 39 40 RTCDateTime last_timespec; 41 uint16_t last_minute = 0; 42 43 uint8_t time_config_idx = 0; 44 int8_t hour_config = 0; 45 int16_t minute_config = 0; 46 int8_t year_config = 0; 47 int8_t month_config = 0; 48 int8_t day_config = 0; 49 uint8_t previous_encoder_mode = 0; 50 51 void board_init(void) { 52 SYSCFG->CFGR1 |= SYSCFG_CFGR1_I2C1_DMA_RMP; 53 SYSCFG->CFGR1 &= ~(SYSCFG_CFGR1_SPI2_DMA_RMP); 54 } 55 56 uint32_t read_custom_config(void *data, uint32_t offset, uint32_t length) { 57 #ifdef VIA_ENABLE 58 return via_read_custom_config(data, offset, length); 59 #else 60 return eeconfig_read_kb_datablock(data, offset, length); 61 #endif 62 } 63 64 uint32_t write_custom_config(const void *data, uint32_t offset, uint32_t length) { 65 #ifdef VIA_ENABLE 66 return via_update_custom_config(data, offset, length); 67 #else 68 return eeconfig_update_kb_datablock(data, offset, length); 69 #endif 70 } 71 72 void keyboard_post_init_kb(void) { 73 /* 74 This is a workaround to some really weird behavior 75 Without this code, the OLED will turn on, but not when you initially plug the keyboard in. 76 You have to manually trigger a user reset to get the OLED to initialize properly 77 I'm not sure what the root cause is at this time, but this workaround fixes it. 78 */ 79 #ifdef OLED_ENABLE 80 if(!is_oled_on()){ 81 wait_ms(3000); 82 oled_init(OLED_ROTATION_0); 83 } 84 #endif 85 86 keyboard_post_init_user(); 87 } 88 89 #ifdef VIA_ENABLE 90 void custom_set_value(uint8_t *data) { 91 uint8_t *value_id = &(data[0]); 92 uint8_t *value_data = &(data[1]); 93 94 switch ( *value_id ) { 95 case id_oled_default_mode: 96 { 97 write_custom_config(&value_data[0], EEPROM_DEFAULT_OLED_OFFSET, 1); 98 break; 99 } 100 case id_oled_mode: 101 { 102 oled_mode = value_data[0]; 103 oled_request_wakeup(); 104 break; 105 } 106 case id_encoder_modes: 107 { 108 uint8_t index = value_data[0]; 109 uint8_t enable = value_data[1]; 110 enabled_encoder_modes = (enabled_encoder_modes & ~(1<<index)) | (enable<<index); 111 write_custom_config(&enabled_encoder_modes, EEPROM_ENABLED_ENCODER_MODES_OFFSET, 1); 112 break; 113 } 114 case id_encoder_custom: 115 { 116 uint8_t custom_encoder_idx = value_data[0]; 117 uint8_t encoder_behavior = value_data[1]; 118 uint16_t keycode = (value_data[2] << 8) | value_data[3]; 119 set_custom_encoder_config(custom_encoder_idx, encoder_behavior, keycode); 120 break; 121 } 122 } 123 } 124 125 void custom_get_value(uint8_t *data) { 126 uint8_t *value_id = &(data[0]); 127 uint8_t *value_data = &(data[1]); 128 129 switch ( *value_id ) { 130 case id_oled_default_mode: 131 { 132 uint8_t default_oled; 133 read_custom_config(&default_oled, EEPROM_DEFAULT_OLED_OFFSET, 1); 134 value_data[0] = default_oled; 135 break; 136 } 137 case id_oled_mode: 138 { 139 value_data[0] = oled_mode; 140 break; 141 } 142 case id_encoder_modes: 143 { 144 uint8_t index = value_data[0]; 145 value_data[1] = (enabled_encoder_modes & (1<<index)) ? 1 : 0; 146 break; 147 } 148 case id_encoder_custom: 149 { 150 uint8_t custom_encoder_idx = value_data[0]; 151 uint8_t encoder_behavior = value_data[1]; 152 uint16_t keycode = retrieve_custom_encoder_config(custom_encoder_idx, encoder_behavior); 153 value_data[2] = keycode >> 8; 154 value_data[3] = keycode & 0xFF; 155 break; 156 } 157 } 158 } 159 160 void via_custom_value_command_kb(uint8_t *data, uint8_t length) { 161 uint8_t *command_id = &(data[0]); 162 uint8_t *channel_id = &(data[1]); 163 uint8_t *value_id_and_data = &(data[2]); 164 165 if ( *channel_id == id_custom_channel ) { 166 switch ( *command_id ) 167 { 168 case id_custom_set_value: 169 { 170 custom_set_value(value_id_and_data); 171 break; 172 } 173 case id_custom_get_value: 174 { 175 custom_get_value(value_id_and_data); 176 break; 177 } 178 case id_custom_save: 179 { 180 // values are saved in custom_set_value() 181 break; 182 } 183 default: 184 { 185 // Unhandled message. 186 *command_id = id_unhandled; 187 break; 188 } 189 } 190 return; 191 } 192 193 *command_id = id_unhandled; 194 195 // DO NOT call raw_hid_send(data,length) here, let caller do this 196 } 197 #endif 198 199 void read_host_led_state(void) { 200 led_t led_state = host_keyboard_led_state(); 201 if (led_state.num_lock) { 202 if (led_numlock == false){ 203 led_numlock = true;} 204 } else { 205 if (led_numlock == true){ 206 led_numlock = false;} 207 } 208 if (led_state.caps_lock) { 209 if (led_capslock == false){ 210 led_capslock = true;} 211 } else { 212 if (led_capslock == true){ 213 led_capslock = false;} 214 } 215 if (led_state.scroll_lock) { 216 if (led_scrolllock == false){ 217 led_scrolllock = true;} 218 } else { 219 if (led_scrolllock == true){ 220 led_scrolllock = false;} 221 } 222 } 223 224 layer_state_t layer_state_set_kb(layer_state_t state) { 225 state = layer_state_set_user(state); 226 layer = get_highest_layer(state); 227 oled_request_wakeup(); 228 return state; 229 } 230 231 bool process_record_kb(uint16_t keycode, keyrecord_t *record) { 232 oled_request_wakeup(); 233 switch (keycode) { 234 case OLED_TOGG: 235 if(!clock_set_mode){ 236 if (record->event.pressed) { 237 oled_mode = (oled_mode + 1) % _NUM_OLED_MODES; 238 } 239 } 240 return false; 241 case CLOCK_SET: 242 if (record->event.pressed) { 243 if(clock_set_mode){ 244 pre_encoder_mode_change(); 245 clock_set_mode = false; 246 encoder_mode = previous_encoder_mode; 247 post_encoder_mode_change(); 248 249 }else{ 250 previous_encoder_mode = encoder_mode; 251 pre_encoder_mode_change(); 252 clock_set_mode = true; 253 encoder_mode = ENC_MODE_CLOCK_SET; 254 post_encoder_mode_change(); 255 } 256 } 257 return false; 258 case ENC_PRESS: 259 if (record->event.pressed) { 260 uint16_t mapped_code = handle_encoder_press(); 261 uint16_t held_keycode_timer = timer_read(); 262 if(mapped_code != 0){ 263 register_code16(mapped_code); 264 while (timer_elapsed(held_keycode_timer) < MEDIA_KEY_DELAY){ /* no-op */ } 265 unregister_code16(mapped_code); 266 } 267 } else { 268 // Do something else when release 269 } 270 return false; 271 default: 272 break; 273 } 274 275 return process_record_user(keycode, record); 276 } 277 278 279 bool encoder_update_kb(uint8_t index, bool clockwise) { 280 if (!encoder_update_user(index, clockwise)) return false; 281 oled_request_wakeup(); 282 encoder_value = (encoder_value + (clockwise ? 1 : -1)) % 64; 283 if (index == 0) { 284 if (layer == 0){ 285 uint16_t mapped_code = 0; 286 if (clockwise) { 287 mapped_code = handle_encoder_clockwise(); 288 } else { 289 mapped_code = handle_encoder_ccw(); 290 } 291 uint16_t held_keycode_timer = timer_read(); 292 if(mapped_code != 0){ 293 register_code16(mapped_code); 294 while (timer_elapsed(held_keycode_timer) < MEDIA_KEY_DELAY){ /* no-op */ } 295 unregister_code16(mapped_code); 296 } 297 } else { 298 if(clockwise){ 299 change_encoder_mode(false); 300 } else { 301 change_encoder_mode(true); 302 } 303 } 304 } 305 return true; 306 } 307 308 void custom_config_reset(void){ 309 for(int i = 0; i < VIA_EEPROM_CUSTOM_CONFIG_SIZE; ++i) { 310 uint8_t dummy = 0; 311 write_custom_config(&dummy, i, 1); 312 } 313 314 uint8_t encoder_modes = 0x1F; 315 write_custom_config(&encoder_modes, EEPROM_ENABLED_ENCODER_MODES_OFFSET, 1); 316 } 317 318 void custom_config_load(void){ 319 #ifdef DYNAMIC_KEYMAP_ENABLE 320 read_custom_config(&oled_mode, EEPROM_DEFAULT_OLED_OFFSET, 1); 321 read_custom_config(&enabled_encoder_modes, EEPROM_ENABLED_ENCODER_MODES_OFFSET, 1); 322 #endif 323 } 324 325 // Called from via_init() if VIA_ENABLE 326 // Called from matrix_init_kb() if not VIA_ENABLE 327 void satisfaction_core_init(void) 328 { 329 // This checks both an EEPROM reset (from bootmagic lite, keycodes) 330 // and also firmware build date (from via_eeprom_is_valid()) 331 if (eeconfig_is_enabled()) { 332 custom_config_load(); 333 } else { 334 #ifdef DYNAMIC_KEYMAP_ENABLE 335 // Reset the custom stuff 336 custom_config_reset(); 337 #endif 338 // DO NOT set EEPROM valid here, let caller do this 339 } 340 } 341 342 void matrix_init_kb(void) 343 { 344 #ifndef VIA_ENABLE 345 satisfaction_core_init(); 346 #endif // VIA_ENABLE 347 348 rtcGetTime(&RTCD1, &last_timespec); 349 matrix_init_user(); 350 oled_request_wakeup(); 351 } 352 353 #ifdef VIA_ENABLE 354 void via_init_kb(void) { 355 satisfaction_core_init(); 356 } 357 #endif // VIA_ENABLE 358 359 void housekeeping_task_kb(void) { 360 rtcGetTime(&RTCD1, &last_timespec); 361 uint16_t minutes_since_midnight = last_timespec.millisecond / 1000 / 60; 362 363 if (minutes_since_midnight != last_minute){ 364 last_minute = minutes_since_midnight; 365 oled_request_repaint(); 366 } 367 }