From 9000edd176a3df351f44cec2a973f1773b849409 Mon Sep 17 00:00:00 2001 From: arlaneenalra Date: Sun, 14 May 2023 18:30:26 -0500 Subject: [PATCH 1/8] Allow force flush of oled display. API copmatible refactoring of the oled_render function that allows callers to forcibly render all dirty blocks instead of allowing the oled_task function to render them asynchronously. This is mostly useful when want to display a logo/message/graphic right before rebooting into a bootloader or other state where the MCU will be unable to finish flushing blocks to the display. --- docs/feature_oled_driver.md | 63 +++++++++++++++++++++++++++-------- drivers/oled/oled_driver.h | 8 +++-- drivers/oled/ssd1306_sh1106.c | 4 +-- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md index dea9cb807495..e2db883e353c 100644 --- a/docs/feature_oled_driver.md +++ b/docs/feature_oled_driver.md @@ -150,6 +150,34 @@ bool oled_task_user(void) { return false; } #endif +``` + +Render a message before booting into bootloader mode. +```c +void oled_render_boot(void) { + oled_clear(); + for (int i = 0; i < 16; i++) { + oled_set_cursor(0, i); + oled_write_P(PSTR("BOOT "), false); + } + + oled_render_dirty(true); +} + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + if (record->event.pressed) { + + // Display a special message prior to rebooting... + if (keycode == QK_BOOT) { + oled_render_boot(); + } + } + + return true; +} + + + ``` ## Basic Configuration @@ -235,7 +263,7 @@ So those precalculated arrays just index the memory offsets in the order in whic ## OLED API ```c -// OLED rotation enum values are flags +// OLED Rotation enum values are flags typedef enum { OLED_ROTATION_0 = 0, OLED_ROTATION_90 = 1, @@ -243,7 +271,7 @@ typedef enum { OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180 } oled_rotation_t; -// Initialize the OLED display, rotating the rendered output based on the define passed in. +// Initialize the oled display, rotating the rendered output based on the define passed in. // Returns true if the OLED was initialized successfully bool oled_init(oled_rotation_t rotation); @@ -256,20 +284,24 @@ oled_rotation_t oled_init_user(oled_rotation_t rotation); // Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering void oled_clear(void); -// Renders the dirty chunks of the buffer to OLED display -void oled_render(void); +// Alias to olde_render_dirty to avoid a change in api. +#define oled_render() oled_render_dirty(false) + +// Renders all dirty blocks to the display at one time or a subset depending on the value of +// all. +void oled_render_dirty(bool all); // Moves cursor to character position indicated by column and line, wraps if out of bounds // Max column denoted by 'oled_max_chars()' and max lines by 'oled_max_lines()' functions void oled_set_cursor(uint8_t col, uint8_t line); // Advances the cursor to the next page, writing ' ' if true -// Wraps to the beginning when out of bounds +// Wraps to the begining when out of bounds void oled_advance_page(bool clearPageRemainder); // Moves the cursor forward 1 character length // Advance page if there is not enough room for the next character -// Wraps to the beginning when out of bounds +// Wraps to the begining when out of bounds void oled_advance_char(void); // Writes a single character to the buffer at current cursor position @@ -288,8 +320,6 @@ void oled_write_ln(const char *data, bool invert); // Pans the buffer to the right (or left by passing true) by moving contents of the buffer // Useful for moving the screen in preparation for new drawing -// oled_scroll_left or oled_scroll_right should be preferred for all cases of moving a static -// image such as a logo or to avoid burn-in as it's much, much less cpu intensive void oled_pan(bool left); // Returns a pointer to the requested start index in the buffer plus remaining @@ -306,6 +336,7 @@ void oled_write_raw_byte(const char data, uint16_t index); // Coordinates start at top-left and go right and down for positive x and y void oled_write_pixel(uint8_t x, uint8_t y, bool on); +#if defined(__AVR__) // Writes a PROGMEM string to the buffer at current cursor position // Advances the cursor while writing, inverts the pixels if true // Remapped to call 'void oled_write(const char *data, bool invert);' on ARM @@ -319,6 +350,11 @@ void oled_write_ln_P(const char *data, bool invert); // Writes a PROGMEM string to the buffer at current cursor position void oled_write_raw_P(const char *data, uint16_t size); +#else +# define oled_write_P(data, invert) oled_write(data, invert) +# define oled_write_ln_P(data, invert) oled_write_ln(data, invert) +# define oled_write_raw_P(data, size) oled_write_raw(data, size) +#endif // defined(__AVR__) // Can be used to manually turn on the screen if it is off // Returns true if the screen was on or turns on @@ -332,10 +368,10 @@ bool oled_off(void); // not bool is_oled_on(void); -// Sets the brightness level of the display +// Sets the brightness of the display uint8_t oled_set_brightness(uint8_t level); -// Gets the current brightness level of the display +// Gets the current brightness of the display uint8_t oled_get_brightness(void); // Basically it's oled_render, but with timeout management and oled_task_user calling! @@ -357,12 +393,12 @@ void oled_scroll_set_area(uint8_t start_line, uint8_t end_line); // 0=2, 1=3, 2=4, 3=5, 4=25, 5=64, 6=128, 7=256 void oled_scroll_set_speed(uint8_t speed); -// Begin scrolling the entire display right +// Scrolls the entire display right // Returns true if the screen was scrolling or starts scrolling // NOTE: display contents cannot be changed while scrolling bool oled_scroll_right(void); -// Begin scrolling the entire display left +// Scrolls the entire display left // Returns true if the screen was scrolling or starts scrolling // NOTE: display contents cannot be changed while scrolling bool oled_scroll_left(void); @@ -382,10 +418,9 @@ bool oled_invert(bool invert); // Returns the maximum number of characters that will fit on a line uint8_t oled_max_chars(void); -// Returns the maximum number of lines that will fit on the OLED +// Returns the maximum number of lines that will fit on the oled uint8_t oled_max_lines(void); ``` - !> Scrolling and rotation are unsupported on the SH1106. ## SSD1306.h Driver Conversion Guide diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h index 291049e36bd7..197faca6ad6e 100644 --- a/drivers/oled/oled_driver.h +++ b/drivers/oled/oled_driver.h @@ -200,8 +200,12 @@ oled_rotation_t oled_init_user(oled_rotation_t rotation); // Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering void oled_clear(void); -// Renders the dirty chunks of the buffer to oled display -void oled_render(void); +// Alias to olde_render_dirty to avoid a change in api. +#define oled_render() oled_render_dirty(false) + +// Renders all dirty blocks to the display at one time or a subset depending on the value of +// all. +void oled_render_dirty(bool all); // Moves cursor to character position indicated by column and line, wraps if out of bounds // Max column denoted by 'oled_max_chars()' and max lines by 'oled_max_lines()' functions diff --git a/drivers/oled/ssd1306_sh1106.c b/drivers/oled/ssd1306_sh1106.c index 342920572e3a..8aa6aa41cf35 100644 --- a/drivers/oled/ssd1306_sh1106.c +++ b/drivers/oled/ssd1306_sh1106.c @@ -290,7 +290,7 @@ static void rotate_90(const uint8_t *src, uint8_t *dest) { } } -void oled_render(void) { +void oled_render_dirty(bool all) { // Do we have work to do? oled_dirty &= OLED_ALL_BLOCKS_MASK; if (!oled_dirty || !oled_initialized || oled_scrolling) { @@ -302,7 +302,7 @@ void oled_render(void) { uint8_t update_start = 0; uint8_t num_processed = 0; - while (oled_dirty && num_processed++ < OLED_UPDATE_PROCESS_LIMIT) { // render all dirty blocks (up to the configured limit) + while (oled_dirty && (num_processed++ < OLED_UPDATE_PROCESS_LIMIT || all)) { // render all dirty blocks (up to the configured limit) // Find next dirty block while (!(oled_dirty & ((OLED_BLOCK_TYPE)1 << update_start))) { ++update_start; From b77761f4367153c684ad619ff3f6a3975a25dc1d Mon Sep 17 00:00:00 2001 From: arlaneenalra Date: Sun, 14 May 2023 20:36:08 -0500 Subject: [PATCH 2/8] Fix errant newline. --- drivers/oled/oled_driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h index db5c40c1bf07..a2e46bf11586 100644 --- a/drivers/oled/oled_driver.h +++ b/drivers/oled/oled_driver.h @@ -353,7 +353,7 @@ oled_rotation_t oled_init_user(oled_rotation_t rotation); // Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering void oled_clear(void); -// Alias to olde_render_dirty to avoid a change in api. +// Alias to olde_render_dirty to avoid a change in api. #define oled_render() oled_render_dirty(false) // Renders all dirty blocks to the display at one time or a subset depending on the value of From 1bbc2f1e8e1cf03bdab07f4513aa874a95b77dfc Mon Sep 17 00:00:00 2001 From: arlaneenalra Date: Sun, 14 May 2023 21:39:00 -0500 Subject: [PATCH 3/8] Use shutdown_user instead. --- docs/feature_oled_driver.md | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md index fe210f1c1656..dfdf68d1b56e 100644 --- a/docs/feature_oled_driver.md +++ b/docs/feature_oled_driver.md @@ -169,28 +169,32 @@ bool oled_task_user(void) { Render a message before booting into bootloader mode. ```c void oled_render_boot(void) { - oled_clear(); - for (int i = 0; i < 16; i++) { - oled_set_cursor(0, i); - oled_write_P(PSTR("BOOT "), false); - } + oled_clear(); + for (int i = 0; i < 16; i++) { + oled_set_cursor(0, i); + oled_write_P(PSTR("BOOT "), false); + } - oled_render_dirty(true); + oled_render_dirty(true); } -bool process_record_user(uint16_t keycode, keyrecord_t *record) { - if (record->event.pressed) { +bool reboot = false; + +bool uint16_t keycode, keyrecord_t *record) { + if (record->event.pressed) { - // Display a special message prior to rebooting... - if (keycode == QK_BOOT) { - oled_render_boot(); + // Display a special message prior to rebooting... + if (keycode == QK_BOOT) { + reboot = true; + } } - } - return true; + return true; } - +void shutdown_user(void) { + oled_render_boot(); +} ``` From 9dcbdc853d650c1134de5229c55550be42d5041d Mon Sep 17 00:00:00 2001 From: arlaneenalra Date: Sun, 14 May 2023 21:55:40 -0500 Subject: [PATCH 4/8] Fix missing if in docs. --- docs/feature_oled_driver.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md index dfdf68d1b56e..ef83ba426fd4 100644 --- a/docs/feature_oled_driver.md +++ b/docs/feature_oled_driver.md @@ -193,7 +193,9 @@ bool uint16_t keycode, keyrecord_t *record) { } void shutdown_user(void) { - oled_render_boot(); + if (reboot) { + oled_render_boot(); + } } ``` From 021614042c33a3f51c51dea44929e6b1514d90db Mon Sep 17 00:00:00 2001 From: arlaneenalra Date: Tue, 16 May 2023 11:57:20 -0500 Subject: [PATCH 5/8] Fix typo. --- docs/feature_oled_driver.md | 2 +- drivers/oled/oled_driver.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md index ef83ba426fd4..aa713327eda1 100644 --- a/docs/feature_oled_driver.md +++ b/docs/feature_oled_driver.md @@ -335,7 +335,7 @@ bool oled_send_data(const uint8_t *data, uint16_t size); // Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering void oled_clear(void); -// Alias to olde_render_dirty to avoid a change in api. +// Alias to oled_render_dirty to avoid a change in api. #define oled_render() oled_render_dirty(false) // Renders all dirty blocks to the display at one time or a subset depending on the value of diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h index a2e46bf11586..4cf53446c2dc 100644 --- a/drivers/oled/oled_driver.h +++ b/drivers/oled/oled_driver.h @@ -353,7 +353,7 @@ oled_rotation_t oled_init_user(oled_rotation_t rotation); // Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering void oled_clear(void); -// Alias to olde_render_dirty to avoid a change in api. +// Alias to oled_render_dirty to avoid a change in api. #define oled_render() oled_render_dirty(false) // Renders all dirty blocks to the display at one time or a subset depending on the value of From 59d1558ce9a7de9601e1671a9f6247e2115034be Mon Sep 17 00:00:00 2001 From: Chris Salch Date: Tue, 16 May 2023 17:23:02 -0500 Subject: [PATCH 6/8] Apply suggestions from code review Co-authored-by: Drashna Jaelre --- docs/feature_oled_driver.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md index aa713327eda1..16c4e51ef2e6 100644 --- a/docs/feature_oled_driver.md +++ b/docs/feature_oled_driver.md @@ -168,11 +168,15 @@ bool oled_task_user(void) { Render a message before booting into bootloader mode. ```c -void oled_render_boot(void) { +void oled_render_boot(bool bootloader) { oled_clear(); for (int i = 0; i < 16; i++) { oled_set_cursor(0, i); - oled_write_P(PSTR("BOOT "), false); + if (bootloader) { + oled_write_P(PSTR("Awaiting New Firmware "), false); + } else { + oled_write_P(PSTR("Rebooting "), false); + } } oled_render_dirty(true); @@ -193,9 +197,7 @@ bool uint16_t keycode, keyrecord_t *record) { } void shutdown_user(void) { - if (reboot) { - oled_render_boot(); - } + oled_render_boot(reboot); } ``` From 122798da4f1277a1c10d80df0f6cbfb1736b60b3 Mon Sep 17 00:00:00 2001 From: Chris Salch Date: Wed, 17 May 2023 10:32:31 -0500 Subject: [PATCH 7/8] Apply suggestions from code review Incorporating other docs updates .. Co-authored-by: Ryan --- docs/feature_oled_driver.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md index 16c4e51ef2e6..a0a4f0370c1c 100644 --- a/docs/feature_oled_driver.md +++ b/docs/feature_oled_driver.md @@ -349,12 +349,12 @@ void oled_render_dirty(bool all); void oled_set_cursor(uint8_t col, uint8_t line); // Advances the cursor to the next page, writing ' ' if true -// Wraps to the begining when out of bounds +// Wraps to the beginning when out of bounds void oled_advance_page(bool clearPageRemainder); // Moves the cursor forward 1 character length // Advance page if there is not enough room for the next character -// Wraps to the begining when out of bounds +// Wraps to the beginning when out of bounds void oled_advance_char(void); // Writes a single character to the buffer at current cursor position @@ -421,10 +421,10 @@ bool oled_off(void); // not bool is_oled_on(void); -// Sets the brightness of the display +// Sets the brightness level of the display uint8_t oled_set_brightness(uint8_t level); -// Gets the current brightness of the display +// Gets the current brightness level of the display uint8_t oled_get_brightness(void); // Basically it's oled_render, but with timeout management and oled_task_user calling! @@ -446,12 +446,12 @@ void oled_scroll_set_area(uint8_t start_line, uint8_t end_line); // 0=2, 1=3, 2=4, 3=5, 4=25, 5=64, 6=128, 7=256 void oled_scroll_set_speed(uint8_t speed); -// Scrolls the entire display right +// Begin scrolling the entire display right // Returns true if the screen was scrolling or starts scrolling // NOTE: display contents cannot be changed while scrolling bool oled_scroll_right(void); -// Scrolls the entire display left +// Begin scrolling the entire display left // Returns true if the screen was scrolling or starts scrolling // NOTE: display contents cannot be changed while scrolling bool oled_scroll_left(void); From c19beca49db8ed2d8e2debaa6bb46cf3c53e0b2f Mon Sep 17 00:00:00 2001 From: arlaneenalra Date: Wed, 17 May 2023 10:33:19 -0500 Subject: [PATCH 8/8] Update .h to match docs. --- drivers/oled/oled_driver.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h index 4cf53446c2dc..fba6633176ab 100644 --- a/drivers/oled/oled_driver.h +++ b/drivers/oled/oled_driver.h @@ -365,12 +365,12 @@ void oled_render_dirty(bool all); void oled_set_cursor(uint8_t col, uint8_t line); // Advances the cursor to the next page, writing ' ' if true -// Wraps to the begining when out of bounds +// Wraps to the beginning when out of bounds void oled_advance_page(bool clearPageRemainder); // Moves the cursor forward 1 character length // Advance page if there is not enough room for the next character -// Wraps to the begining when out of bounds +// Wraps to the beginning when out of bounds void oled_advance_char(void); // Writes a single character to the buffer at current cursor position @@ -437,10 +437,10 @@ bool oled_off(void); // not bool is_oled_on(void); -// Sets the brightness of the display +// Sets the brightness level of the display uint8_t oled_set_brightness(uint8_t level); -// Gets the current brightness of the display +// Gets the current brightness level of the display uint8_t oled_get_brightness(void); // Basically it's oled_render, but with timeout management and oled_task_user calling! @@ -462,12 +462,12 @@ void oled_scroll_set_area(uint8_t start_line, uint8_t end_line); // 0=2, 1=3, 2=4, 3=5, 4=25, 5=64, 6=128, 7=256 void oled_scroll_set_speed(uint8_t speed); -// Scrolls the entire display right +// Begin scrolling the entire display right // Returns true if the screen was scrolling or starts scrolling // NOTE: display contents cannot be changed while scrolling bool oled_scroll_right(void); -// Scrolls the entire display left +// Begin scrolling the entire display left // Returns true if the screen was scrolling or starts scrolling // NOTE: display contents cannot be changed while scrolling bool oled_scroll_left(void);