From 2d3bd7cfcfd3418507a932f3aca7b7c77df07caa Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 10 Oct 2021 19:01:29 +0300 Subject: [PATCH] Fix OLED timeout on satisfaction75 after migration from QWIIC (#14780) The custom OLED_OFF mode implemented on satisfaction75 is incompatible with the OLED_TIMEOUT feature (the OLED_TIMEOUT code assumes that any key or encoder action should turn the OLED display on, and does not provide any way to disable that behavior). To keep the OLED_OFF mode functioning as before while still having a working OLED idle timeout, a custom implementation of the OLED idle timeout code is added. --- keyboards/cannonkeys/satisfaction75/config.h | 6 ++ .../satisfaction75/satisfaction75.c | 16 +++-- .../satisfaction75/satisfaction75.h | 7 ++ .../satisfaction75/satisfaction_oled.c | 66 ++++++++++++++++++- 4 files changed, 87 insertions(+), 8 deletions(-) diff --git a/keyboards/cannonkeys/satisfaction75/config.h b/keyboards/cannonkeys/satisfaction75/config.h index 7fca7226b..53e4c18e5 100644 --- a/keyboards/cannonkeys/satisfaction75/config.h +++ b/keyboards/cannonkeys/satisfaction75/config.h @@ -74,6 +74,12 @@ along with this program. If not, see . // configure oled driver for the 128x32 oled #define OLED_UPDATE_INTERVAL 66 // ~15fps +// OLED_TIMEOUT is incompatible with the OLED_OFF mode +#define OLED_TIMEOUT 0 + +// OLED timeout reimplemented in the keyboard-specific code +#define CUSTOM_OLED_TIMEOUT 60000 + // Custom config starts after VIA's EEPROM usage, // dynamic keymaps start after this. // Custom config Usage: diff --git a/keyboards/cannonkeys/satisfaction75/satisfaction75.c b/keyboards/cannonkeys/satisfaction75/satisfaction75.c index 304df3325..8b5016437 100644 --- a/keyboards/cannonkeys/satisfaction75/satisfaction75.c +++ b/keyboards/cannonkeys/satisfaction75/satisfaction75.c @@ -23,6 +23,9 @@ uint8_t layer; bool clock_set_mode = false; uint8_t oled_mode = OLED_DEFAULT; +bool oled_repaint_requested = false; +bool oled_wakeup_requested = false; +uint32_t oled_sleep_timer; uint8_t encoder_value = 32; uint8_t encoder_mode = ENC_MODE_VOLUME; @@ -158,6 +161,7 @@ void raw_hid_receive_kb( uint8_t *data, uint8_t length ) case id_oled_mode: { oled_mode = command_data[1]; + oled_request_wakeup(); break; } case id_encoder_modes: @@ -237,10 +241,12 @@ void read_host_led_state(void) { layer_state_t layer_state_set_kb(layer_state_t state) { state = layer_state_set_user(state); layer = biton32(state); + oled_request_wakeup(); return state; } bool process_record_kb(uint16_t keycode, keyrecord_t *record) { + oled_request_wakeup(); switch (keycode) { case OLED_TOGG: if(!clock_set_mode){ @@ -289,6 +295,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { bool encoder_update_kb(uint8_t index, bool clockwise) { if (!encoder_update_user(index, clockwise)) return false; + oled_request_wakeup(); encoder_value = (encoder_value + (clockwise ? 1 : -1)) % 64; if (index == 0) { if (layer == 0){ @@ -364,6 +371,7 @@ void matrix_init_kb(void) rtcGetTime(&RTCD1, &last_timespec); backlight_init_ports(); matrix_init_user(); + oled_request_wakeup(); } @@ -373,13 +381,7 @@ void housekeeping_task_kb(void) { if (minutes_since_midnight != last_minute){ last_minute = minutes_since_midnight; - } - - if((oled_mode == OLED_OFF) && is_oled_on()){ - oled_off(); - } - if((oled_mode != OLED_OFF) && !is_oled_on()){ - oled_on(); + oled_request_repaint(); } } diff --git a/keyboards/cannonkeys/satisfaction75/satisfaction75.h b/keyboards/cannonkeys/satisfaction75/satisfaction75.h index 9d20dd9c9..c6dbc31f1 100644 --- a/keyboards/cannonkeys/satisfaction75/satisfaction75.h +++ b/keyboards/cannonkeys/satisfaction75/satisfaction75.h @@ -72,6 +72,9 @@ extern uint8_t layer; // OLED Behavior extern uint8_t oled_mode; +extern bool oled_repaint_requested; +extern bool oled_wakeup_requested; +extern uint32_t oled_sleep_timer; // Encoder Behavior extern uint8_t encoder_value; @@ -107,6 +110,10 @@ void set_custom_encoder_config(uint8_t encoder_idx, uint8_t behavior, uint16_t n void update_time_config(int8_t increment); +void oled_request_wakeup(void); +void oled_request_repaint(void); +bool oled_task_needs_to_repaint(void); + void backlight_init_ports(void); void backlight_set(uint8_t level); bool is_breathing(void); diff --git a/keyboards/cannonkeys/satisfaction75/satisfaction_oled.c b/keyboards/cannonkeys/satisfaction75/satisfaction_oled.c index 9589ecea8..443482eac 100644 --- a/keyboards/cannonkeys/satisfaction75/satisfaction_oled.c +++ b/keyboards/cannonkeys/satisfaction75/satisfaction_oled.c @@ -8,7 +8,7 @@ void draw_clock(void); __attribute__((weak)) oled_rotation_t oled_init_user(oled_rotation_t rotation) { return OLED_ROTATION_0; } __attribute__((weak)) void oled_task_user(void) { - if (!is_oled_on()) { + if (!oled_task_needs_to_repaint()) { return; } oled_clear(); @@ -27,6 +27,70 @@ __attribute__((weak)) void oled_task_user(void) { } } +// Request a repaint of the OLED image without resetting the OLED sleep timer. +// Used for things like clock updates that should not keep the OLED turned on +// if there is no other activity. +void oled_request_repaint(void) { + if (is_oled_on()) { + oled_repaint_requested = true; + } +} + +// Request a repaint of the OLED image and reset the OLED sleep timer. +// Needs to be called after any activity that should keep the OLED turned on. +void oled_request_wakeup(void) { + oled_wakeup_requested = true; +} + +// Check whether oled_task_user() needs to repaint the OLED image. This +// function should be called at the start of oled_task_user(); it also handles +// the OLED sleep timer and the OLED_OFF mode. +bool oled_task_needs_to_repaint(void) { + // In the OLED_OFF mode the OLED is kept turned off; any wakeup requests + // are ignored. + if ((oled_mode == OLED_OFF) && !clock_set_mode) { + oled_wakeup_requested = false; + oled_repaint_requested = false; + oled_off(); + return false; + } + + // If OLED wakeup was requested, reset the sleep timer and do a repaint. + if (oled_wakeup_requested) { + oled_wakeup_requested = false; + oled_repaint_requested = false; + oled_sleep_timer = timer_read32() + CUSTOM_OLED_TIMEOUT; + oled_on(); + return true; + } + + // If OLED repaint was requested, just do a repaint without touching the + // sleep timer. + if (oled_repaint_requested) { + oled_repaint_requested = false; + return true; + } + + // If the OLED is currently off, skip the repaint (which would turn the + // OLED on if the image is changed in any way). + if (!is_oled_on()) { + return false; + } + + // If the sleep timer has expired while the OLED was on, turn the OLED off. + if (timer_expired32(timer_read32(), oled_sleep_timer)) { + oled_off(); + return false; + } + + // Always perform a repaint if the OLED is currently on. (This can + // potentially be optimized to avoid unneeded repaints if all possible + // state changes are covered by oled_request_repaint() or + // oled_request_wakeup(), but then any missed calls to these functions + // would result in displaying a stale image.) + return true; +} + static void draw_line_h(uint8_t x, uint8_t y, uint8_t len) { for (uint8_t i = 0; i < len; i++) {