mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-02 00:38:50 +00:00
do a full display reset after splashscreen
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include <zephyr/kernel.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(zephcore_display, CONFIG_ZEPHCORE_BOARD_LOG_LEVEL);
|
||||
@@ -58,6 +59,31 @@ static const struct device *backlight_reg;
|
||||
|
||||
static bool backlight_on;
|
||||
|
||||
/* EPD frame change detection (Arduino-style):
|
||||
* hash draw calls across a frame and skip hardware flush if unchanged. */
|
||||
static uint32_t epd_frame_hash;
|
||||
static uint32_t epd_last_frame_hash = UINT_MAX;
|
||||
|
||||
static inline void epd_hash_bytes(const void *data, size_t len)
|
||||
{
|
||||
if (!is_epd || !data || len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *p = (const uint8_t *)data;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
/* FNV-1a */
|
||||
epd_frame_hash ^= p[i];
|
||||
epd_frame_hash *= 16777619u;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void epd_hash_u32(uint32_t v)
|
||||
{
|
||||
epd_hash_bytes(&v, sizeof(v));
|
||||
}
|
||||
|
||||
static inline void backlight_set(bool on)
|
||||
{
|
||||
if (backlight_reg && device_is_ready(backlight_reg) && on != backlight_on) {
|
||||
@@ -336,6 +362,9 @@ void mc_display_clear(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_epd) {
|
||||
epd_frame_hash = 2166136261u;
|
||||
}
|
||||
cfb_framebuffer_clear(disp_dev, false);
|
||||
}
|
||||
|
||||
@@ -349,6 +378,12 @@ void mc_display_text(int x, int y, const char *text, bool invert)
|
||||
cfb_framebuffer_invert(disp_dev);
|
||||
}
|
||||
|
||||
if (is_epd) {
|
||||
epd_hash_u32((uint32_t)x);
|
||||
epd_hash_u32((uint32_t)y);
|
||||
epd_hash_u32(invert ? 1u : 0u);
|
||||
epd_hash_bytes(text, strlen(text));
|
||||
}
|
||||
cfb_print(disp_dev, text, x + DISP_INSET, y + DISP_INSET);
|
||||
|
||||
if (invert) {
|
||||
@@ -365,6 +400,12 @@ void mc_display_fill_rect(int x, int y, int w, int h)
|
||||
/* CFB doesn't have a native fill_rect, so we draw line by line */
|
||||
const int row_clamp = (int)disp_height - DISP_INSET;
|
||||
|
||||
if (is_epd) {
|
||||
epd_hash_u32((uint32_t)x);
|
||||
epd_hash_u32((uint32_t)y);
|
||||
epd_hash_u32((uint32_t)w);
|
||||
epd_hash_u32((uint32_t)h);
|
||||
}
|
||||
for (int row = y + DISP_INSET; row < y + h + DISP_INSET && row < row_clamp; row++) {
|
||||
struct cfb_position start = { .x = x + DISP_INSET, .y = row };
|
||||
struct cfb_position end = { .x = x + w - 1 + DISP_INSET, .y = row };
|
||||
@@ -380,6 +421,12 @@ void mc_display_hline(int x, int y, int w)
|
||||
|
||||
struct cfb_position start = { .x = x + DISP_INSET, .y = y + DISP_INSET };
|
||||
struct cfb_position end = { .x = x + w - 1 + DISP_INSET, .y = y + DISP_INSET };
|
||||
|
||||
if (is_epd) {
|
||||
epd_hash_u32((uint32_t)x);
|
||||
epd_hash_u32((uint32_t)y);
|
||||
epd_hash_u32((uint32_t)w);
|
||||
}
|
||||
cfb_draw_line(disp_dev, &start, &end);
|
||||
}
|
||||
|
||||
@@ -393,6 +440,15 @@ void mc_display_xbm(int x, int y, const uint8_t *data, int w, int h)
|
||||
* This matches the Arduino MeshCore logo data from icons.h.
|
||||
* Each row is padded to byte boundary: bytes_per_row = (w+7)/8 */
|
||||
int bytes_per_row = (w + 7) / 8;
|
||||
size_t bitmap_len = (size_t)bytes_per_row * (size_t)h;
|
||||
|
||||
if (is_epd) {
|
||||
epd_hash_u32((uint32_t)x);
|
||||
epd_hash_u32((uint32_t)y);
|
||||
epd_hash_u32((uint32_t)w);
|
||||
epd_hash_u32((uint32_t)h);
|
||||
epd_hash_bytes(data, bitmap_len);
|
||||
}
|
||||
|
||||
for (int row = 0; row < h; row++) {
|
||||
for (int col = 0; col < w; col++) {
|
||||
@@ -421,7 +477,13 @@ void mc_display_finalize(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_epd && epd_frame_hash == epd_last_frame_hash) {
|
||||
return;
|
||||
}
|
||||
cfb_framebuffer_finalize(disp_dev);
|
||||
if (is_epd) {
|
||||
epd_last_frame_hash = epd_frame_hash;
|
||||
}
|
||||
}
|
||||
|
||||
void mc_display_reset_auto_off(void)
|
||||
@@ -439,6 +501,24 @@ void mc_display_reset_auto_off(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void mc_display_epd_full_reset(void)
|
||||
{
|
||||
if (!disp_initialized || !is_epd) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Force the SSD16xx path back through a full-refresh cycle before
|
||||
* entering steady-state partial updates for page rendering. */
|
||||
display_blanking_on(disp_dev);
|
||||
display_blanking_off(disp_dev);
|
||||
epd_last_frame_hash = UINT_MAX;
|
||||
|
||||
/* After splash handoff, keep frontlight off; next user interaction
|
||||
* wakes it via mc_display_on(). */
|
||||
backlight_set(false);
|
||||
disp_on = false;
|
||||
}
|
||||
|
||||
const struct device *mc_display_get_device(void)
|
||||
{
|
||||
return disp_initialized ? disp_dev : NULL;
|
||||
|
||||
+157
-151
@@ -1,151 +1,157 @@
|
||||
/*
|
||||
* ZephCore - Display Abstraction (CFB)
|
||||
* Copyright (c) 2025 ZephCore
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Wraps Zephyr's Character Framebuffer (CFB) subsystem with:
|
||||
* - Auto-detection from devicetree (any Zephyr-supported display)
|
||||
* - Runtime resolution query (supports any size, not just 128x64)
|
||||
* - Auto-off timer via k_work_delayable
|
||||
* - Simple text/rect drawing API for UI pages
|
||||
*
|
||||
* All functions prefixed mc_display_ to avoid collision with
|
||||
* Zephyr's display_* namespace in <zephyr/drivers/display.h>.
|
||||
*/
|
||||
|
||||
#ifndef ZEPHCORE_DISPLAY_H
|
||||
#define ZEPHCORE_DISPLAY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize the display from devicetree.
|
||||
* Detects any Zephyr-supported display via:
|
||||
* 1. "zephyr,display" chosen node (standard)
|
||||
* 2. Legacy nodelabels: sh1106, ssd1306 (backwards compat)
|
||||
*
|
||||
* Queries actual resolution from driver — no hardcoded dimensions.
|
||||
*
|
||||
* @return 0 on success, negative errno on failure, -ENODEV if no display
|
||||
*/
|
||||
int mc_display_init(void);
|
||||
|
||||
/**
|
||||
* Get display width in pixels (queried from hardware at init).
|
||||
* Returns 0 if display not initialized.
|
||||
*/
|
||||
uint16_t mc_display_width(void);
|
||||
|
||||
/**
|
||||
* Get display height in pixels (queried from hardware at init).
|
||||
* Returns 0 if display not initialized.
|
||||
*/
|
||||
uint16_t mc_display_height(void);
|
||||
|
||||
/**
|
||||
* Get active font width in pixels.
|
||||
* Returns 0 if display not initialized.
|
||||
*/
|
||||
uint8_t mc_display_font_width(void);
|
||||
|
||||
/**
|
||||
* Get active font height in pixels.
|
||||
* Returns 0 if display not initialized.
|
||||
*/
|
||||
uint8_t mc_display_font_height(void);
|
||||
|
||||
/**
|
||||
* Turn display on (wake from blanking).
|
||||
* Resets the auto-off timer.
|
||||
*/
|
||||
void mc_display_on(void);
|
||||
|
||||
/**
|
||||
* Turn display off (blanking).
|
||||
*/
|
||||
void mc_display_off(void);
|
||||
|
||||
/**
|
||||
* @return true if the display is currently on
|
||||
*/
|
||||
bool mc_display_is_on(void);
|
||||
|
||||
/**
|
||||
* @return true if the display is an e-paper (EPD) type.
|
||||
* EPD displays have slow refresh (~2s) and use zero power when static,
|
||||
* so callers should use longer update intervals and skip blanking.
|
||||
*/
|
||||
bool mc_display_is_epd(void);
|
||||
|
||||
/**
|
||||
* Clear the framebuffer (fill with black).
|
||||
* Call before rendering a new frame.
|
||||
*/
|
||||
void mc_display_clear(void);
|
||||
|
||||
/**
|
||||
* Draw text at position.
|
||||
*
|
||||
* @param x X position in pixels
|
||||
* @param y Y position in pixels
|
||||
* @param text Null-terminated string
|
||||
* @param invert If true, draw black text on white background
|
||||
*/
|
||||
void mc_display_text(int x, int y, const char *text, bool invert);
|
||||
|
||||
/**
|
||||
* Draw a filled rectangle.
|
||||
*
|
||||
* @param x Top-left X
|
||||
* @param y Top-left Y
|
||||
* @param w Width
|
||||
* @param h Height
|
||||
*/
|
||||
void mc_display_fill_rect(int x, int y, int w, int h);
|
||||
|
||||
/**
|
||||
* Draw a horizontal line.
|
||||
*/
|
||||
void mc_display_hline(int x, int y, int w);
|
||||
|
||||
/**
|
||||
* Draw a monochrome bitmap (Adafruit/Arduino format).
|
||||
* MSB first, row-major, 1=foreground.
|
||||
* Compatible with Arduino's drawBitmap() and MeshCore icons.h data.
|
||||
*
|
||||
* @param x Top-left X position
|
||||
* @param y Top-left Y position
|
||||
* @param data Bitmap data (MSB first, row-major)
|
||||
* @param w Width in pixels
|
||||
* @param h Height in pixels
|
||||
*/
|
||||
void mc_display_xbm(int x, int y, const uint8_t *data, int w, int h);
|
||||
|
||||
/**
|
||||
* Flush the framebuffer to the display hardware.
|
||||
* Call after all drawing operations for a frame are complete.
|
||||
*/
|
||||
void mc_display_finalize(void);
|
||||
|
||||
/**
|
||||
* Reset the auto-off timer (called on user interaction).
|
||||
*/
|
||||
void mc_display_reset_auto_off(void);
|
||||
|
||||
/**
|
||||
* Get the raw display device pointer.
|
||||
* Used by easter egg (Doom) to bypass CFB and write directly.
|
||||
* Returns NULL if display not initialized.
|
||||
*/
|
||||
const struct device *mc_display_get_device(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHCORE_DISPLAY_H */
|
||||
/*
|
||||
* ZephCore - Display Abstraction (CFB)
|
||||
* Copyright (c) 2025 ZephCore
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Wraps Zephyr's Character Framebuffer (CFB) subsystem with:
|
||||
* - Auto-detection from devicetree (any Zephyr-supported display)
|
||||
* - Runtime resolution query (supports any size, not just 128x64)
|
||||
* - Auto-off timer via k_work_delayable
|
||||
* - Simple text/rect drawing API for UI pages
|
||||
*
|
||||
* All functions prefixed mc_display_ to avoid collision with
|
||||
* Zephyr's display_* namespace in <zephyr/drivers/display.h>.
|
||||
*/
|
||||
|
||||
#ifndef ZEPHCORE_DISPLAY_H
|
||||
#define ZEPHCORE_DISPLAY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize the display from devicetree.
|
||||
* Detects any Zephyr-supported display via:
|
||||
* 1. "zephyr,display" chosen node (standard)
|
||||
* 2. Legacy nodelabels: sh1106, ssd1306 (backwards compat)
|
||||
*
|
||||
* Queries actual resolution from driver — no hardcoded dimensions.
|
||||
*
|
||||
* @return 0 on success, negative errno on failure, -ENODEV if no display
|
||||
*/
|
||||
int mc_display_init(void);
|
||||
|
||||
/**
|
||||
* Get display width in pixels (queried from hardware at init).
|
||||
* Returns 0 if display not initialized.
|
||||
*/
|
||||
uint16_t mc_display_width(void);
|
||||
|
||||
/**
|
||||
* Get display height in pixels (queried from hardware at init).
|
||||
* Returns 0 if display not initialized.
|
||||
*/
|
||||
uint16_t mc_display_height(void);
|
||||
|
||||
/**
|
||||
* Get active font width in pixels.
|
||||
* Returns 0 if display not initialized.
|
||||
*/
|
||||
uint8_t mc_display_font_width(void);
|
||||
|
||||
/**
|
||||
* Get active font height in pixels.
|
||||
* Returns 0 if display not initialized.
|
||||
*/
|
||||
uint8_t mc_display_font_height(void);
|
||||
|
||||
/**
|
||||
* Turn display on (wake from blanking).
|
||||
* Resets the auto-off timer.
|
||||
*/
|
||||
void mc_display_on(void);
|
||||
|
||||
/**
|
||||
* Turn display off (blanking).
|
||||
*/
|
||||
void mc_display_off(void);
|
||||
|
||||
/**
|
||||
* @return true if the display is currently on
|
||||
*/
|
||||
bool mc_display_is_on(void);
|
||||
|
||||
/**
|
||||
* @return true if the display is an e-paper (EPD) type.
|
||||
* EPD displays have slow refresh (~2s) and use zero power when static,
|
||||
* so callers should use longer update intervals and skip blanking.
|
||||
*/
|
||||
bool mc_display_is_epd(void);
|
||||
|
||||
/**
|
||||
* Clear the framebuffer (fill with black).
|
||||
* Call before rendering a new frame.
|
||||
*/
|
||||
void mc_display_clear(void);
|
||||
|
||||
/**
|
||||
* Draw text at position.
|
||||
*
|
||||
* @param x X position in pixels
|
||||
* @param y Y position in pixels
|
||||
* @param text Null-terminated string
|
||||
* @param invert If true, draw black text on white background
|
||||
*/
|
||||
void mc_display_text(int x, int y, const char *text, bool invert);
|
||||
|
||||
/**
|
||||
* Draw a filled rectangle.
|
||||
*
|
||||
* @param x Top-left X
|
||||
* @param y Top-left Y
|
||||
* @param w Width
|
||||
* @param h Height
|
||||
*/
|
||||
void mc_display_fill_rect(int x, int y, int w, int h);
|
||||
|
||||
/**
|
||||
* Draw a horizontal line.
|
||||
*/
|
||||
void mc_display_hline(int x, int y, int w);
|
||||
|
||||
/**
|
||||
* Draw a monochrome bitmap (Adafruit/Arduino format).
|
||||
* MSB first, row-major, 1=foreground.
|
||||
* Compatible with Arduino's drawBitmap() and MeshCore icons.h data.
|
||||
*
|
||||
* @param x Top-left X position
|
||||
* @param y Top-left Y position
|
||||
* @param data Bitmap data (MSB first, row-major)
|
||||
* @param w Width in pixels
|
||||
* @param h Height in pixels
|
||||
*/
|
||||
void mc_display_xbm(int x, int y, const uint8_t *data, int w, int h);
|
||||
|
||||
/**
|
||||
* Flush the framebuffer to the display hardware.
|
||||
* Call after all drawing operations for a frame are complete.
|
||||
*/
|
||||
void mc_display_finalize(void);
|
||||
|
||||
/**
|
||||
* Reset the auto-off timer (called on user interaction).
|
||||
*/
|
||||
void mc_display_reset_auto_off(void);
|
||||
|
||||
/**
|
||||
* EPD-only: force a full panel reset cycle before normal page rendering.
|
||||
* No-op on non-EPD displays or when display is not initialized.
|
||||
*/
|
||||
void mc_display_epd_full_reset(void);
|
||||
|
||||
/**
|
||||
* Get the raw display device pointer.
|
||||
* Used by easter egg (Doom) to bypass CFB and write directly.
|
||||
* Returns NULL if display not initialized.
|
||||
*/
|
||||
const struct device *mc_display_get_device(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHCORE_DISPLAY_H */
|
||||
|
||||
@@ -245,6 +245,8 @@ static void splash_work_handler(struct k_work *work)
|
||||
splash_active = false;
|
||||
|
||||
#ifdef CONFIG_ZEPHCORE_UI_DISPLAY
|
||||
mc_display_epd_full_reset();
|
||||
|
||||
/* Transition from splash to home page (first active page for this role) */
|
||||
#ifdef ZEPHCORE_REPEATER
|
||||
ui_pages_set(UI_PAGE_STATUS);
|
||||
@@ -741,6 +743,8 @@ static void ui_input_cb(struct input_event *evt, void *user_data)
|
||||
k_work_cancel_delayable(&splash_work);
|
||||
splash_active = false;
|
||||
#ifdef CONFIG_ZEPHCORE_UI_DISPLAY
|
||||
mc_display_epd_full_reset();
|
||||
|
||||
#ifdef ZEPHCORE_REPEATER
|
||||
ui_pages_set(UI_PAGE_STATUS);
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user