Re implement display

This commit is contained in:
GW_MC
2026-01-26 18:17:39 +08:00
parent abe840b65d
commit 30dfdd630a
12 changed files with 1780 additions and 849 deletions

View File

@@ -14,11 +14,9 @@
#include "common/queue_defs.h"
#include "io/nvs_handler.h"
#include "info/info.h"
#include "display/display.h"
#include "display/eink_display_handler.h"
#include "ui/ui_handler.h"
#include "ui/app_registry.h"
#include "ui/apps/demo_app.h"
#include "ui/apps/shutdown_app.h"
#include "ui/apps/discord_app.h"
#include "ui/apps/mtr_app.h"
@@ -26,6 +24,7 @@
#include "esp_lvgl_port.h"
#include "lvgl.h"
#include "network.h"
#include <esp_task_wdt.h>
// nvs storage namespaces, 15 characters max
#define DEFAULT_STORAGE_NAMESPACE "storage"
@@ -72,54 +71,56 @@ void app_main(void) {
return esp_restart();
}
//
KVStorageHandler* kv_storage_handler = new NVSStorageHandler(
DEFAULT_STORAGE_NAMESPACE
);
// KVStorageHandler* kv_storage_handler = new NVSStorageHandler(
// DEFAULT_STORAGE_NAMESPACE
// );
auto wifi_handler = std::make_unique<WifiHandler>(
std::unique_ptr<KVStorageHandler>(new NVSStorageHandler(WIFI_CREDENTIALS_STORAGE_NAMESPACE))
);
NetworkHandler* network_handler = new NetworkHandler(std::move(wifi_handler));
EInkDisplayHandler* display_handler = new EInkDisplayHandler(system_event_group);
// auto wifi_handler = std::make_unique<WifiHandler>(
// std::unique_ptr<KVStorageHandler>(new NVSStorageHandler(WIFI_CREDENTIALS_STORAGE_NAMESPACE))
// );
// NetworkHandler* network_handler = new NetworkHandler(std::move(wifi_handler));
EInkDisplayHandler* display_handler = new EInkDisplayHandler();
//
kv_storage_handler->init(system_event_group);
network_handler->init(system_event_group);
// kv_storage_handler->init(system_event_group);
// network_handler->init(system_event_group);
// Initialize display and touch
display_handler->init();
ESP_LOGV(TAG, "Starting touch task...\n");
display_handler->start_touch_task();
ESP_LOGV(TAG, "Touch task started.\n");
display_handler->init_devices(system_event_group);
display_handler->clear_display();
// ESP_LOGV(TAG, "Starting touch task...\n");
// display_handler->start_touch_task();
// ESP_LOGV(TAG, "Touch task started.\n");
//
// LVGL tick timer
auto lvgl_tick_timer_callback = [](TimerHandle_t xTimer) {
lv_tick_inc(5);
};
TickType_t lvgl_tick_period = pdMS_TO_TICKS(5);
if (lvgl_tick_period == 0) {
lvgl_tick_period = 1; // ensure at least 1 tick to avoid FreeRTOS assert
}
ESP_LOGV(TAG, "Creating LVGL tick timer with period %u ticks...\n", (unsigned)lvgl_tick_period);
TimerHandle_t lvgl_tick_timer = xTimerCreate(
"lvgl_tick_timer",
lvgl_tick_period,
pdTRUE,
NULL,
lvgl_tick_timer_callback
);
if (lvgl_tick_timer == NULL) {
ESP_LOGE("Main", "Failed to create LVGL tick timer");
vTaskDelay(5000 / portTICK_PERIOD_MS);
return esp_restart();
}
ESP_LOGV(TAG, "Starting LVGL tick timer...\n");
xTimerStart(lvgl_tick_timer, 0);
// auto lvgl_tick_timer_callback = [](TimerHandle_t xTimer) {
// lv_tick_inc(5);
// };
// TickType_t lvgl_tick_period = pdMS_TO_TICKS(5);
// if (lvgl_tick_period == 0) {
// lvgl_tick_period = 1; // ensure at least 1 tick to avoid FreeRTOS assert
// }
// ESP_LOGV(TAG, "Creating LVGL tick timer with period %u ticks...\n", (unsigned)lvgl_tick_period);
// TimerHandle_t lvgl_tick_timer = xTimerCreate(
// "lvgl_tick_timer",
// lvgl_tick_period,
// pdTRUE,
// NULL,
// lvgl_tick_timer_callback
// );
// if (lvgl_tick_timer == NULL) {
// ESP_LOGE("Main", "Failed to create LVGL tick timer");
// vTaskDelay(5000 / portTICK_PERIOD_MS);
// return esp_restart();
// }
// ESP_LOGV(TAG, "Starting LVGL tick timer...\n");
// xTimerStart(lvgl_tick_timer, 0);
//
ESP_LOGI(TAG, "Waiting for system to be ready...\n");
xEventGroupWaitBits(
system_event_group,
DISPLAY_READY_BIT | STORAGE_READY_BIT | NETWORK_READY_BIT,
// DISPLAY_READY_BIT | STORAGE_READY_BIT | NETWORK_READY_BIT,
DISPLAY_READY_BIT,
// do not clear on exit, require explicit reset
pdFALSE,
pdTRUE,
@@ -129,28 +130,106 @@ void app_main(void) {
// Register apps with AppRegistry by creating their descriptors
// Each descriptor will create and register the app instance
DemoAppDescriptor* demo_descriptor = new DemoAppDescriptor();
ShutdownAppDescriptor* shutdown_descriptor = new ShutdownAppDescriptor();
DiscordAppDescriptor::instance(); // Use singleton pattern for Discord app
MtrAppDescriptor* mtr_descriptor = new MtrAppDescriptor();
// DemoAppDescriptor* demo_descriptor = new DemoAppDescriptor();
// ShutdownAppDescriptor* shutdown_descriptor = new ShutdownAppDescriptor();
// DiscordAppDescriptor::instance(); // Use singleton pattern for Discord app
// MtrAppDescriptor* mtr_descriptor = new MtrAppDescriptor();
// Pass network handler to MtrApp so it can fetch arrival data
MtrApp* mtr_app = dynamic_cast<MtrApp*>(mtr_descriptor->get_app_instance());
if (mtr_app) {
mtr_app->set_network_handler(network_handler);
}
// MtrApp* mtr_app = dynamic_cast<MtrApp*>(mtr_descriptor->get_app_instance());
// if (mtr_app) {
// mtr_app->set_network_handler(network_handler);
// }
ESP_LOGI(TAG, "Apps registered with AppRegistry\n");
// ESP_LOGI(TAG, "Apps registered with AppRegistry\n");
// Initialize UI Handler (will render app icons from registry)
UIHandler ui_handler;
if (ui_handler.init() != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize UI handler");
vTaskDelay(5000 / portTICK_PERIOD_MS);
return esp_restart();
// UIHandler ui_handler;
// if (ui_handler.init() != ESP_OK) {
// ESP_LOGE(TAG, "Failed to initialize UI handler");
// vTaskDelay(5000 / portTICK_PERIOD_MS);
// return esp_restart();
// }
// ESP_LOGI(TAG, "UI handler initialized successfully\n");
// ESP_LOGI(TAG, "Main screen displayed with app icons. Tap an icon to launch an app.\n");
// Run checkerboard draw in its own FreeRTOS task to avoid watchdog triggers
struct CheckerboardTaskParams {
EInkDisplayHandler* display_handler;
};
auto checkerboard_task_fn = [](void* pvParameters) {
CheckerboardTaskParams* params = static_cast<CheckerboardTaskParams*>(pvParameters);
if (params != nullptr && params->display_handler != nullptr) {
// Add this task to the watchdog timer
esp_err_t wdt_err = esp_task_wdt_add(NULL);
if (wdt_err != ESP_OK) {
ESP_LOGW(TAG, "Failed to add checkerboard task to watchdog: %s", esp_err_to_name(wdt_err));
}
EInkDisplayHandler* display_handler = params->display_handler;
const size_t DISPLAY_BUFFER_SIZE = DISPLAY_WIDTH * DISPLAY_HEIGHT / 8;
uint8_t* framebuffer = new uint8_t[DISPLAY_BUFFER_SIZE];
if (framebuffer == nullptr) {
ESP_LOGE(TAG, "Failed to allocate framebuffer for checkerboard task");
if (wdt_err == ESP_OK) {
esp_task_wdt_delete(NULL);
}
vTaskDelete(NULL);
return;
}
// Create checkerboard pattern
for (size_t y = 0; y < DISPLAY_HEIGHT; y++) {
for (size_t x = 0; x < DISPLAY_WIDTH; x++) {
size_t byte_index = (y * DISPLAY_WIDTH + x) / 8;
size_t bit_index = 7 - (x % 8);
bool is_white = ((x / 20) % 2) == ((y / 20) % 2);
if (is_white) {
framebuffer[byte_index] |= (1 << bit_index); // Set bit to 1 for white
} else {
framebuffer[byte_index] &= ~(1 << bit_index); // Clear bit to 0 for black
}
}
// Yield and reset watchdog periodically
if (y % 50 == 0) {
if (wdt_err == ESP_OK) {
esp_task_wdt_reset();
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
}
// Perform full write to display
esp_err_t err = display_handler->full_write(framebuffer);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Checkerboard full write failed: %s", esp_err_to_name(err));
} else {
ESP_LOGI(TAG, "Checkerboard pattern displayed successfully.");
}
delete[] framebuffer;
// Remove task from watchdog before deletion
if (wdt_err == ESP_OK) {
esp_task_wdt_delete(NULL);
}
} else {
ESP_LOGE(TAG, "Invalid parameters for checkerboard task");
}
vTaskDelete(NULL);
};
CheckerboardTaskParams* checker_params = new CheckerboardTaskParams();
checker_params->display_handler = display_handler;
BaseType_t res = xTaskCreate(
checkerboard_task_fn,
"checkerboard_task",
8192,
static_cast<void*>(checker_params),
tskIDLE_PRIORITY + 1,
NULL
);
if (res != pdPASS) {
ESP_LOGE(TAG, "Failed to create checkerboard task");
delete checker_params;
}
ESP_LOGI(TAG, "UI handler initialized successfully\n");
ESP_LOGI(TAG, "Main screen displayed with app icons. Tap an icon to launch an app.\n");
// wait for shutdown signal
ESP_LOGI(TAG, "Waiting for shutdown signal...\n");
@@ -165,17 +244,17 @@ void app_main(void) {
ESP_LOGI(TAG, "Shutdown signal received. Cleaning up...\n");
// Show shutdown screen using the shutdown descriptor's app instance
ShutdownApp* shutdown_app = dynamic_cast<ShutdownApp*>(shutdown_descriptor->get_app_instance());
if (shutdown_app) {
ui_handler.switch_app(shutdown_app);
}
// ShutdownApp* shutdown_app = dynamic_cast<ShutdownApp*>(shutdown_descriptor->get_app_instance());
// if (shutdown_app) {
// ui_handler.switch_app(shutdown_app);
// }
vTaskDelay(1000 / portTICK_PERIOD_MS); // Display shutdown message briefly
// Cleanup
ui_handler.deinit();
delete demo_descriptor;
delete shutdown_descriptor;
delete mtr_descriptor;
// ui_handler.deinit();
// delete demo_descriptor;
// delete shutdown_descriptor;
// delete mtr_descriptor;
delete display_handler;
vSemaphoreDelete(lvgl_mutex);
vEventGroupDelete(system_event_group);