Fix polling error
This commit is contained in:
@@ -61,9 +61,9 @@ EInkDisplayHandler::~EInkDisplayHandler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EInkDisplayHandler::deep_sleep_display(void) {
|
esp_err_t EInkDisplayHandler::deep_sleep_display(void) {
|
||||||
ESP_LOGI(TAG, "Putting display into deep sleep mode...");
|
ESP_LOGV(TAG, "Putting display into deep sleep mode...");
|
||||||
if (is_deep_sleep_) {
|
if (is_deep_sleep_) {
|
||||||
ESP_LOGI(TAG, "Display is already in deep sleep mode");
|
ESP_LOGW(TAG, "Display is already in deep sleep mode");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -111,7 +111,7 @@ esp_err_t EInkDisplayHandler::refresh_display() {
|
|||||||
} else {
|
} else {
|
||||||
// refresh does not correctly work after recovering from deep sleep due to sram reset
|
// refresh does not correctly work after recovering from deep sleep due to sram reset
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Waiting for display to be idle...");
|
ESP_LOGV(TAG, "Waiting for display to be idle...");
|
||||||
TransactionGuard transaction_guard(this->epd_handler_);
|
TransactionGuard transaction_guard(this->epd_handler_);
|
||||||
err = transaction_guard.begin(pdMS_TO_TICKS(10000));
|
err = transaction_guard.begin(pdMS_TO_TICKS(10000));
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
@@ -123,7 +123,7 @@ esp_err_t EInkDisplayHandler::refresh_display() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
epd_handler_.wait_for_idle();
|
epd_handler_.wait_for_idle();
|
||||||
ESP_LOGI(TAG, "Starting display refresh...");
|
ESP_LOGV(TAG, "Starting display refresh...");
|
||||||
err = epd_handler_.epd_write_cmd(0x92, transaction_guard.transaction_id()); // enter normal mode
|
err = epd_handler_.epd_write_cmd(0x92, transaction_guard.transaction_id()); // enter normal mode
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to enter normal mode: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to enter normal mode: %s", esp_err_to_name(err));
|
||||||
@@ -149,12 +149,12 @@ esp_err_t EInkDisplayHandler::refresh_display() {
|
|||||||
force_full_refresh_ = false;
|
force_full_refresh_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Refresh complete");
|
ESP_LOGV(TAG, "Refresh complete");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EInkDisplayHandler::full_write(const uint8_t* framebuffer, const bool white_basemap) {
|
esp_err_t EInkDisplayHandler::full_write(const uint8_t* framebuffer, const bool white_basemap) {
|
||||||
ESP_LOGI(TAG, "Starting full refresh (3 seconds)...");
|
ESP_LOGV(TAG, "Starting full refresh (3 seconds)...");
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
|
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ esp_err_t EInkDisplayHandler::full_write(const uint8_t* framebuffer, const bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(MINIMUM_PIN_SETUP_DELAY_MS)); // at least 200us delay
|
vTaskDelay(pdMS_TO_TICKS(MINIMUM_PIN_SETUP_DELAY_MS)); // at least 200us delay
|
||||||
ESP_LOGI(TAG, "Display refresh triggered, BUSY pin: %d", gpio_get_level(PIN_BUSY));
|
ESP_LOGV(TAG, "Display refresh triggered, BUSY pin: %d", gpio_get_level(PIN_BUSY));
|
||||||
|
|
||||||
// Wait for refresh to complete
|
// Wait for refresh to complete
|
||||||
epd_handler_.wait_for_idle();
|
epd_handler_.wait_for_idle();
|
||||||
@@ -229,13 +229,13 @@ esp_err_t EInkDisplayHandler::full_write(const uint8_t* framebuffer, const bool
|
|||||||
refresh_area_.reset();
|
refresh_area_.reset();
|
||||||
memcpy(old_buffer_, draw_buffer_, DISPLAY_BUFFER_SIZE);
|
memcpy(old_buffer_, draw_buffer_, DISPLAY_BUFFER_SIZE);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Full refresh complete");
|
ESP_LOGV(TAG, "Full refresh complete");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Partial refresh is inverted in color
|
// TODO: Partial refresh is inverted in color
|
||||||
esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_framebuffer, const RefreshArea& incoming_area, const bool is_last_partial_update) {
|
esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_framebuffer, const RefreshArea& incoming_area, const bool is_last_partial_update) {
|
||||||
ESP_LOGI(TAG, "Starting partial refresh (0.3 seconds)...");
|
ESP_LOGV(TAG, "Starting partial refresh (0.3 seconds)...");
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
|
|
||||||
write_to_buffer_(incoming_partial_framebuffer, incoming_area);
|
write_to_buffer_(incoming_partial_framebuffer, incoming_area);
|
||||||
@@ -244,7 +244,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
|||||||
refresh_area_.expand_to_include(incoming_area);
|
refresh_area_.expand_to_include(incoming_area);
|
||||||
|
|
||||||
if (!is_last_partial_update) {
|
if (!is_last_partial_update) {
|
||||||
ESP_LOGI(TAG, "Partial refresh skipped (not last partial update)");
|
ESP_LOGV(TAG, "Partial refresh skipped (not last partial update)");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
|||||||
RefreshArea area = refresh_area_;
|
RefreshArea area = refresh_area_;
|
||||||
if (area.x1 % 8 != 0 || area.x2 % 8 != 7) {
|
if (area.x1 % 8 != 0 || area.x2 % 8 != 7) {
|
||||||
ESP_LOGE(TAG, "Partial refresh area x1 and x2 must be byte-aligned (x1 %% 8 == 0 and x2 %% 8 == 7)");
|
ESP_LOGE(TAG, "Partial refresh area x1 and x2 must be byte-aligned (x1 %% 8 == 0 and x2 %% 8 == 7)");
|
||||||
ESP_LOGI(TAG, "Given area: x1=%d, x2=%d", area.x1, area.x2);
|
ESP_LOGV(TAG, "Given area: x1=%d, x2=%d", area.x1, area.x2);
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,9 +348,9 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
|||||||
static_cast<uint8_t>(area.y2 & 0xFF),
|
static_cast<uint8_t>(area.y2 & 0xFF),
|
||||||
0x01 // Gates scan both inside and outside of the partial window
|
0x01 // Gates scan both inside and outside of the partial window
|
||||||
};
|
};
|
||||||
ESP_LOGI(TAG, "Setting partial window: x1=%d, y1=%d, x2=%d, y2=%d",
|
ESP_LOGV(TAG, "Setting partial window: x1=%d, y1=%d, x2=%d, y2=%d",
|
||||||
area.x1, area.y1, area.x2, area.y2);
|
area.x1, area.y1, area.x2, area.y2);
|
||||||
ESP_LOGI(TAG, "Partial window data: %02X %02X %02X %02X %02X %02X %02X %02X",
|
ESP_LOGV(TAG, "Partial window data: %02X %02X %02X %02X %02X %02X %02X %02X",
|
||||||
window_data[0], window_data[1], window_data[2], window_data[3], window_data[4],
|
window_data[0], window_data[1], window_data[2], window_data[3], window_data[4],
|
||||||
window_data[5], window_data[6], window_data[7]);
|
window_data[5], window_data[6], window_data[7]);
|
||||||
err = epd_handler_.epd_write_cmd_with_data(0x90, window_data, transaction_guard.transaction_id()); // Set partial window
|
err = epd_handler_.epd_write_cmd_with_data(0x90, window_data, transaction_guard.transaction_id()); // Set partial window
|
||||||
@@ -370,7 +370,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send only the partial area data, not the full display buffer
|
// Send only the partial area data, not the full display buffer
|
||||||
ESP_LOGI(TAG, "Sending new partial buffer: %zu bytes (area: %dx%d)",
|
ESP_LOGV(TAG, "Sending new partial buffer: %zu bytes (area: %dx%d)",
|
||||||
partial_buffer_size, area_width_bytes * 8, area_height);
|
partial_buffer_size, area_width_bytes * 8, area_height);
|
||||||
err = epd_handler_.transfer_spi_data(partial_buffer, partial_buffer_size, transaction_guard.transaction_id(), true); // Inverted for partial refresh
|
err = epd_handler_.transfer_spi_data(partial_buffer, partial_buffer_size, transaction_guard.transaction_id(), true); // Inverted for partial refresh
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
@@ -403,7 +403,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Partial refresh complete");
|
ESP_LOGV(TAG, "Partial refresh complete");
|
||||||
|
|
||||||
err = deep_sleep_display();
|
err = deep_sleep_display();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
@@ -412,7 +412,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (force_full_refresh_) {
|
if (force_full_refresh_) {
|
||||||
ESP_LOGI(TAG, "Full refresh already requested, skipping partial refresh count increment");
|
ESP_LOGV(TAG, "Full refresh already requested, skipping partial refresh count increment");
|
||||||
err = refresh_display();
|
err = refresh_display();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to perform forced full refresh: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to perform forced full refresh: %s", esp_err_to_name(err));
|
||||||
@@ -432,7 +432,7 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
|||||||
partial_refresh_count_++;
|
partial_refresh_count_++;
|
||||||
}
|
}
|
||||||
if (partial_refresh_count_ >= PARTIAL_REFRESH_THRESHOLD) {
|
if (partial_refresh_count_ >= PARTIAL_REFRESH_THRESHOLD) {
|
||||||
ESP_LOGI(TAG, "Partial refresh count %u reached threshold %u, next refresh will be full",
|
ESP_LOGV(TAG, "Partial refresh count %u reached threshold %u, next refresh will be full",
|
||||||
partial_refresh_count_, PARTIAL_REFRESH_THRESHOLD);
|
partial_refresh_count_, PARTIAL_REFRESH_THRESHOLD);
|
||||||
force_full_refresh_ = true;
|
force_full_refresh_ = true;
|
||||||
partial_refresh_count_ = 0;
|
partial_refresh_count_ = 0;
|
||||||
@@ -447,14 +447,14 @@ esp_err_t EInkDisplayHandler::partial_refresh(const uint8_t* incoming_partial_fr
|
|||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EInkDisplayHandler::clear_display(void) {
|
esp_err_t EInkDisplayHandler::clear_display(void) {
|
||||||
ESP_LOGI(TAG, "Clearing display to all white...");
|
ESP_LOGV(TAG, "Clearing display to all white...");
|
||||||
|
|
||||||
esp_err_t err = full_write(white_data, false);
|
esp_err_t err = full_write(white_data, false);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to clear display: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to clear display: %s", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Display cleared to all white");
|
ESP_LOGV(TAG, "Display cleared to all white");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +478,7 @@ void EInkDisplayHandler::request_full_refresh(void) {
|
|||||||
if (guard.take(pdMS_TO_TICKS(100))) {
|
if (guard.take(pdMS_TO_TICKS(100))) {
|
||||||
force_full_refresh_ = true;
|
force_full_refresh_ = true;
|
||||||
partial_refresh_count_ = 0;
|
partial_refresh_count_ = 0;
|
||||||
ESP_LOGI(TAG, "Full refresh requested");
|
ESP_LOGV(TAG, "Full refresh requested");
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG, "Failed to take refresh mutex to request full refresh");
|
ESP_LOGE(TAG, "Failed to take refresh mutex to request full refresh");
|
||||||
}
|
}
|
||||||
@@ -506,13 +506,13 @@ esp_err_t EInkDisplayHandler::init_devices(EventGroupHandle_t system_event_group
|
|||||||
if (system_event_group != nullptr) {
|
if (system_event_group != nullptr) {
|
||||||
// Indicate that display is ready
|
// Indicate that display is ready
|
||||||
xEventGroupSetBits(system_event_group, DISPLAY_READY_BIT | TOUCH_CALIBRATED_BIT);
|
xEventGroupSetBits(system_event_group, DISPLAY_READY_BIT | TOUCH_CALIBRATED_BIT);
|
||||||
ESP_LOGI(TAG, "Display marked as ready");
|
ESP_LOGV(TAG, "Display marked as ready");
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EInkDisplayHandler::init_display_pins_(void) {
|
esp_err_t EInkDisplayHandler::init_display_pins_(void) {
|
||||||
ESP_LOGI(TAG, "Initializing E-Ink display handler...");
|
ESP_LOGV(TAG, "Initializing E-Ink display handler...");
|
||||||
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
|
|
||||||
@@ -544,7 +544,7 @@ esp_err_t EInkDisplayHandler::init_display_pins_(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EInkDisplayHandler::epd_init_internal_(uint32_t transaction_id) {
|
esp_err_t EInkDisplayHandler::epd_init_internal_(uint32_t transaction_id) {
|
||||||
ESP_LOGI(TAG, "Initializing EPD...");
|
ESP_LOGV(TAG, "Initializing EPD...");
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
|
|
||||||
|
|
||||||
@@ -585,8 +585,8 @@ esp_err_t EInkDisplayHandler::epd_init_internal_(uint32_t transaction_id) {
|
|||||||
vTaskDelay(pdMS_TO_TICKS(MINIMUM_POWER_ON_DELAY_MS)); // Wait for power on
|
vTaskDelay(pdMS_TO_TICKS(MINIMUM_POWER_ON_DELAY_MS)); // Wait for power on
|
||||||
|
|
||||||
// Check BUSY pin with detailed logging
|
// Check BUSY pin with detailed logging
|
||||||
ESP_LOGI(TAG, "Waiting for EPD to be ready after power on...");
|
ESP_LOGV(TAG, "Waiting for EPD to be ready after power on...");
|
||||||
ESP_LOGI(TAG, "BUSY pin level after power on: %d (0=BUSY, 1=FREE)", gpio_get_level(PIN_BUSY));
|
ESP_LOGV(TAG, "BUSY pin level after power on: %d (0=BUSY, 1=FREE)", gpio_get_level(PIN_BUSY));
|
||||||
|
|
||||||
epd_handler_.wait_for_idle();
|
epd_handler_.wait_for_idle();
|
||||||
std::vector<uint8_t> booster_data = { 0x27, 0x27, 0x18, 0x17 };
|
std::vector<uint8_t> booster_data = { 0x27, 0x27, 0x18, 0x17 };
|
||||||
@@ -618,7 +618,7 @@ esp_err_t EInkDisplayHandler::epd_init_internal_(uint32_t transaction_id) {
|
|||||||
|
|
||||||
// Internal version that uses an existing transaction (no separate TransactionGuard)
|
// Internal version that uses an existing transaction (no separate TransactionGuard)
|
||||||
esp_err_t EInkDisplayHandler::epd_init_partial_internal_(uint32_t transaction_id) {
|
esp_err_t EInkDisplayHandler::epd_init_partial_internal_(uint32_t transaction_id) {
|
||||||
ESP_LOGI(TAG, "Initializing EPD for partial refresh (internal)...");
|
ESP_LOGV(TAG, "Initializing EPD for partial refresh (internal)...");
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
|
|
||||||
// 1. Hardware Reset
|
// 1. Hardware Reset
|
||||||
@@ -676,12 +676,12 @@ esp_err_t EInkDisplayHandler::epd_init_partial_internal_(uint32_t transaction_id
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "EPD partial init (internal) complete");
|
ESP_LOGV(TAG, "EPD partial init (internal) complete");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EInkDisplayHandler::init_touch_() {
|
esp_err_t EInkDisplayHandler::init_touch_() {
|
||||||
ESP_LOGI(TAG, "Initializing touch...");
|
ESP_LOGV(TAG, "Initializing touch...");
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
|
|
||||||
// 1. Initialize I2C Bus
|
// 1. Initialize I2C Bus
|
||||||
@@ -703,10 +703,10 @@ esp_err_t EInkDisplayHandler::init_touch_() {
|
|||||||
ESP_LOGE(TAG, "Failed to install I2C driver: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to install I2C driver: %s", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
ESP_LOGI("DisplayHandler", "I2C driver installed");
|
ESP_LOGV("DisplayHandler", "I2C driver installed");
|
||||||
|
|
||||||
// 2. Initialize GT911
|
// 2. Initialize GT911
|
||||||
ESP_LOGI("DisplayHandler", "Initializing GT911 touch controller...");
|
ESP_LOGV("DisplayHandler", "Initializing GT911 touch controller...");
|
||||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {};
|
esp_lcd_panel_io_i2c_config_t tp_io_config = {};
|
||||||
// temporarily disable -Wmissing-field-initializers, as ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG macro does not set all fields
|
// temporarily disable -Wmissing-field-initializers, as ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG macro does not set all fields
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
@@ -734,16 +734,16 @@ esp_err_t EInkDisplayHandler::init_touch_() {
|
|||||||
|
|
||||||
err = esp_lcd_touch_new_i2c_gt911(tp_io_handle_, &tp_cfg, &tp_handle_);
|
err = esp_lcd_touch_new_i2c_gt911(tp_io_handle_, &tp_cfg, &tp_handle_);
|
||||||
if (err == ESP_OK && tp_handle_ != nullptr) {
|
if (err == ESP_OK && tp_handle_ != nullptr) {
|
||||||
ESP_LOGI("DisplayHandler", "GT911 touch controller initialized successfully");
|
ESP_LOGV(TAG, "GT911 touch controller initialized successfully");
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE("DisplayHandler", "GT911 touch controller initialization failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "GT911 touch controller initialization failed: %s", esp_err_to_name(err));
|
||||||
tp_handle_ = nullptr;
|
tp_handle_ = nullptr;
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EInkDisplayHandler::refresh_old_buffer_(uint32_t transaction_id) {
|
esp_err_t EInkDisplayHandler::refresh_old_buffer_(uint32_t transaction_id) {
|
||||||
ESP_LOGI(TAG, "Refreshing display SRAM to restore state after wake...");
|
ESP_LOGV(TAG, "Refreshing display SRAM to restore state after wake...");
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
|
|
||||||
err = epd_handler_.epd_write_cmd(0x92, transaction_id); // enter normal mode
|
err = epd_handler_.epd_write_cmd(0x92, transaction_id); // enter normal mode
|
||||||
@@ -784,6 +784,6 @@ esp_err_t EInkDisplayHandler::refresh_old_buffer_(uint32_t transaction_id) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Display SRAM restored successfully");
|
ESP_LOGV(TAG, "Display SRAM restored successfully");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,23 +73,23 @@ bool EPDHandler::is_busy(void) const {
|
|||||||
return gpio_get_level(PIN_BUSY) != BUSY_ACTIVE_LEVEL; // BUSY is active LOW
|
return gpio_get_level(PIN_BUSY) != BUSY_ACTIVE_LEVEL; // BUSY is active LOW
|
||||||
}
|
}
|
||||||
void EPDHandler::wait_for_idle(void) const {
|
void EPDHandler::wait_for_idle(void) const {
|
||||||
ESP_LOGI(TAG, "Waiting for display ready (BUSY pin)...");
|
ESP_LOGV(TAG, "Waiting for display ready (BUSY pin)...");
|
||||||
int initial_level = gpio_get_level(PIN_BUSY);
|
int initial_level = gpio_get_level(PIN_BUSY);
|
||||||
ESP_LOGI(TAG, "Initial BUSY pin level: %d (0=BUSY, 1=FREE)", initial_level);
|
ESP_LOGV(TAG, "Initial BUSY pin level: %d (0=BUSY, 1=FREE)", initial_level);
|
||||||
|
|
||||||
// If already free, no need to wait
|
// If already free, no need to wait
|
||||||
if (initial_level == BUSY_INACTIVE_LEVEL) {
|
if (initial_level == BUSY_INACTIVE_LEVEL) {
|
||||||
ESP_LOGI(TAG, "Display already ready (BUSY pin = 1)");
|
ESP_LOGV(TAG, "Display already ready (BUSY pin = 1)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (gpio_get_level(PIN_BUSY) != BUSY_INACTIVE_LEVEL) {
|
while (gpio_get_level(PIN_BUSY) != BUSY_INACTIVE_LEVEL) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Display is now ready (BUSY pin = 1)");
|
ESP_LOGV(TAG, "Display is now ready (BUSY pin = 1)");
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EPDHandler::epd_write_cmd(const uint8_t cmd, uint32_t transaction_id) {
|
esp_err_t EPDHandler::epd_write_cmd(const uint8_t cmd, uint32_t transaction_id) {
|
||||||
ESP_LOGI(TAG, "epd_write_cmd: waiting to send 0x%02X", cmd);
|
ESP_LOGV(TAG, "epd_write_cmd: waiting to send 0x%02X", cmd);
|
||||||
|
|
||||||
SemaphoreGuard transaction_guard(spi_transaction_mutex_);
|
SemaphoreGuard transaction_guard(spi_transaction_mutex_);
|
||||||
esp_err_t err =
|
esp_err_t err =
|
||||||
@@ -106,12 +106,12 @@ esp_err_t EPDHandler::epd_write_cmd(const uint8_t cmd, uint32_t transaction_id)
|
|||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
err = dangerous_epd_write_cmd_without_lock_(cmd);
|
err = dangerous_epd_write_cmd_without_lock_(cmd);
|
||||||
ESP_LOGI(TAG, "epd_write_cmd: 0x%02X done", cmd);
|
ESP_LOGV(TAG, "epd_write_cmd: 0x%02X done", cmd);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EPDHandler::epd_write_data(const uint8_t data, uint32_t transaction_id) {
|
esp_err_t EPDHandler::epd_write_data(const uint8_t data, uint32_t transaction_id) {
|
||||||
ESP_LOGI(TAG, "epd_write_data: waiting to send 0x%02X", data);
|
ESP_LOGV(TAG, "epd_write_data: waiting to send 0x%02X", data);
|
||||||
SemaphoreGuard transaction_guard(spi_transaction_mutex_);
|
SemaphoreGuard transaction_guard(spi_transaction_mutex_);
|
||||||
esp_err_t err =
|
esp_err_t err =
|
||||||
wait_for_transaction_end_(pdMS_TO_TICKS(5000), transaction_id, transaction_guard);
|
wait_for_transaction_end_(pdMS_TO_TICKS(5000), transaction_id, transaction_guard);
|
||||||
@@ -126,13 +126,13 @@ esp_err_t EPDHandler::epd_write_data(const uint8_t data, uint32_t transaction_id
|
|||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
err = dangerous_epd_write_data_without_lock_(data);
|
err = dangerous_epd_write_data_without_lock_(data);
|
||||||
ESP_LOGI(TAG, "epd_write_data: 0x%02X done", data);
|
ESP_LOGV(TAG, "epd_write_data: 0x%02X done", data);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EPDHandler::epd_write_cmd_with_data(const uint8_t cmd, std::vector<uint8_t>& data, uint32_t transaction_id) {
|
esp_err_t EPDHandler::epd_write_cmd_with_data(const uint8_t cmd, std::vector<uint8_t>& data, uint32_t transaction_id) {
|
||||||
const size_t data_len = data.size();
|
const size_t data_len = data.size();
|
||||||
ESP_LOGI(TAG, "epd_write_cmd_with_data: waiting to send cmd 0x%02X with %u bytes of data", cmd, data_len);
|
ESP_LOGV(TAG, "epd_write_cmd_with_data: waiting to send cmd 0x%02X with %u bytes of data", cmd, data_len);
|
||||||
|
|
||||||
SemaphoreGuard transaction_guard(spi_transaction_mutex_);
|
SemaphoreGuard transaction_guard(spi_transaction_mutex_);
|
||||||
esp_err_t err =
|
esp_err_t err =
|
||||||
@@ -158,13 +158,13 @@ esp_err_t EPDHandler::epd_write_cmd_with_data(const uint8_t cmd, std::vector<uin
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "epd_write_cmd_with_data: cmd 0x%02X with %u bytes of data done", cmd, data_len);
|
ESP_LOGV(TAG, "epd_write_cmd_with_data: cmd 0x%02X with %u bytes of data done", cmd, data_len);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t EPDHandler::dangerous_epd_write_cmd_without_lock_(const uint8_t cmd) {
|
esp_err_t EPDHandler::dangerous_epd_write_cmd_without_lock_(const uint8_t cmd) {
|
||||||
ESP_LOGI(TAG, "dangerous_epd_write_cmd_without_lock_: sending 0x%02X", cmd);
|
ESP_LOGV(TAG, "dangerous_epd_write_cmd_without_lock_: sending 0x%02X", cmd);
|
||||||
gpio_set_level(PIN_DC, 0); // Command mode
|
gpio_set_level(PIN_DC, 0); // Command mode
|
||||||
spi_transaction_t t {};
|
spi_transaction_t t {};
|
||||||
t.length = 8;t.tx_buffer = &cmd;
|
t.length = 8;t.tx_buffer = &cmd;
|
||||||
@@ -172,13 +172,13 @@ esp_err_t EPDHandler::dangerous_epd_write_cmd_without_lock_(const uint8_t cmd) {
|
|||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to send data 0x%02X", cmd);
|
ESP_LOGE(TAG, "Failed to send data 0x%02X", cmd);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(TAG, "dangerous_epd_write_cmd_without_lock_: 0x%02X sent", cmd);
|
ESP_LOGV(TAG, "dangerous_epd_write_cmd_without_lock_: 0x%02X sent", cmd);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EPDHandler::dangerous_epd_write_data_without_lock_(const uint8_t data) {
|
esp_err_t EPDHandler::dangerous_epd_write_data_without_lock_(const uint8_t data) {
|
||||||
ESP_LOGI(TAG, "dangerous_epd_write_data_without_lock_: sending 0x%02X", data);
|
ESP_LOGV(TAG, "dangerous_epd_write_data_without_lock_: sending 0x%02X", data);
|
||||||
gpio_set_level(PIN_DC, 1); // Data mode
|
gpio_set_level(PIN_DC, 1); // Data mode
|
||||||
spi_transaction_t t = { };
|
spi_transaction_t t = { };
|
||||||
t.length = 8; t.tx_buffer = &data;
|
t.length = 8; t.tx_buffer = &data;
|
||||||
@@ -186,13 +186,13 @@ esp_err_t EPDHandler::dangerous_epd_write_data_without_lock_(const uint8_t data)
|
|||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to send data 0x%02X", data);
|
ESP_LOGE(TAG, "Failed to send data 0x%02X", data);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(TAG, "dangerous_epd_write_data_without_lock_: 0x%02X sent", data);
|
ESP_LOGV(TAG, "dangerous_epd_write_data_without_lock_: 0x%02X sent", data);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EPDHandler::transfer_spi_data(const uint8_t* data, const size_t& length, uint32_t transaction_id, bool inverted) {
|
esp_err_t EPDHandler::transfer_spi_data(const uint8_t* data, const size_t& length, uint32_t transaction_id, bool inverted) {
|
||||||
ESP_LOGI(TAG, "transfer_spi_data: waiting to send %zu bytes of data", length);
|
ESP_LOGV(TAG, "transfer_spi_data: waiting to send %zu bytes of data", length);
|
||||||
|
|
||||||
SemaphoreGuard transaction_guard(spi_transaction_mutex_);
|
SemaphoreGuard transaction_guard(spi_transaction_mutex_);
|
||||||
esp_err_t err =
|
esp_err_t err =
|
||||||
@@ -207,7 +207,7 @@ esp_err_t EPDHandler::transfer_spi_data(const uint8_t* data, const size_t& lengt
|
|||||||
ESP_LOGE(TAG, "SPI mutex timeout for data transfer of %zu bytes", length);
|
ESP_LOGE(TAG, "SPI mutex timeout for data transfer of %zu bytes", length);
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "transfer_spi_data: starting to send %zu bytes of data", length);
|
ESP_LOGV(TAG, "transfer_spi_data: starting to send %zu bytes of data", length);
|
||||||
|
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
size_t remaining = length;
|
size_t remaining = length;
|
||||||
@@ -264,7 +264,7 @@ esp_err_t EPDHandler::transfer_spi_data(const uint8_t* data, const size_t& lengt
|
|||||||
|
|
||||||
// Yield every 16KB to prevent watchdog timeout
|
// Yield every 16KB to prevent watchdog timeout
|
||||||
if (offset % (16 * 1024) == 0) {
|
if (offset % (16 * 1024) == 0) {
|
||||||
ESP_LOGI(TAG, "New data progress: %zu/%zu bytes sent, yielding...", offset, length);
|
ESP_LOGV(TAG, "New data progress: %zu/%zu bytes sent, yielding...", offset, length);
|
||||||
vTaskDelay(pdMS_TO_TICKS(1));
|
vTaskDelay(pdMS_TO_TICKS(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,30 +274,30 @@ esp_err_t EPDHandler::transfer_spi_data(const uint8_t* data, const size_t& lengt
|
|||||||
heap_caps_free(temp_transfer_buffer);
|
heap_caps_free(temp_transfer_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "transfer_spi_data: completed sending %zu bytes of data", length);
|
ESP_LOGV(TAG, "transfer_spi_data: completed sending %zu bytes of data", length);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EPDHandler::begin_transaction_(TickType_t timeout, uint32_t& out_id) {
|
esp_err_t EPDHandler::begin_transaction_(TickType_t timeout, uint32_t& out_id) {
|
||||||
ESP_LOGI(TAG, "begin_transaction_: waiting to obtain transaction mutex");
|
ESP_LOGV(TAG, "begin_transaction_: waiting to obtain transaction mutex");
|
||||||
if (xSemaphoreTake(spi_transaction_mutex_, timeout) != pdTRUE) {
|
if (xSemaphoreTake(spi_transaction_mutex_, timeout) != pdTRUE) {
|
||||||
ESP_LOGE(TAG, "begin_transaction_: transaction mutex timeout");
|
ESP_LOGE(TAG, "begin_transaction_: transaction mutex timeout");
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_id = ++spi_transaction_id;
|
out_id = ++spi_transaction_id;
|
||||||
ESP_LOGI(TAG, "begin_transaction_: transaction mutex obtained");
|
ESP_LOGV(TAG, "begin_transaction_: transaction mutex obtained");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t EPDHandler::end_transaction_(void) {
|
esp_err_t EPDHandler::end_transaction_(void) {
|
||||||
ESP_LOGI(TAG, "end_transaction_: releasing transaction mutex");
|
ESP_LOGV(TAG, "end_transaction_: releasing transaction mutex");
|
||||||
if (xSemaphoreGive(spi_transaction_mutex_) != pdTRUE) {
|
if (xSemaphoreGive(spi_transaction_mutex_) != pdTRUE) {
|
||||||
ESP_LOGE(TAG, "end_transaction_: failed to release transaction mutex");
|
ESP_LOGE(TAG, "end_transaction_: failed to release transaction mutex");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "end_transaction_: transaction mutex released");
|
ESP_LOGV(TAG, "end_transaction_: transaction mutex released");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ void IotDisBridge::poll_task_(void* param) {
|
|||||||
while (!bridge->stop_polling_) {
|
while (!bridge->stop_polling_) {
|
||||||
ESP_LOGI(TAG, "Polling for status update...");
|
ESP_LOGI(TAG, "Polling for status update...");
|
||||||
bridge->poll_status_();
|
bridge->poll_status_();
|
||||||
|
ESP_LOGI(TAG, "poll_status_() returned");
|
||||||
|
|
||||||
// Yield to allow display updates to complete
|
// Yield to allow display updates to complete
|
||||||
taskYIELD();
|
taskYIELD();
|
||||||
@@ -150,6 +151,7 @@ void IotDisBridge::poll_task_(void* param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Polling task stopped");
|
ESP_LOGI(TAG, "Polling task stopped");
|
||||||
|
bridge->poll_task_handle_ = nullptr;
|
||||||
vTaskDelete(nullptr);
|
vTaskDelete(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,38 +178,28 @@ void IotDisBridge::poll_status_() {
|
|||||||
event_data.state = StatusUpdateEventData::VoiceState::UNMUTED;
|
event_data.state = StatusUpdateEventData::VoiceState::UNMUTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset failure counter on successful push update
|
||||||
|
if (event_data.state != StatusUpdateEventData::VoiceState::UNKNOWN) {
|
||||||
|
consecutive_failures_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (on_status_update_callback_) {
|
if (on_status_update_callback_) {
|
||||||
on_status_update_callback_(event_data, status_event_user_data_);
|
on_status_update_callback_(event_data, status_event_user_data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// VoiceState new_state = VoiceState::UNKNOWN;
|
// Got push update, skip polling
|
||||||
// if (push_message == MUTED_RESPONSE) {
|
if (event_data.state != StatusUpdateEventData::VoiceState::UNKNOWN) {
|
||||||
// new_state = VoiceState::MUTED;
|
return;
|
||||||
// } else if (push_message == UNMUTED_RESPONSE) {
|
}
|
||||||
// new_state = VoiceState::UNMUTED;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (new_state != VoiceState::UNKNOWN) {
|
|
||||||
// consecutive_failures_ = 0;
|
|
||||||
// if (main_ui_ && current_page_ == Page::MAIN) {
|
|
||||||
// main_ui_->show_error_notification(false);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (state_mutex_ && xSemaphoreTake(state_mutex_, pdMS_TO_TICKS(100)) == pdTRUE) {
|
|
||||||
// current_state_ = new_state;
|
|
||||||
// xSemaphoreGive(state_mutex_);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// update_main_ui();
|
|
||||||
// return; // Got push update, skip polling
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send STATUS command for polling
|
// Send STATUS command for polling
|
||||||
|
ESP_LOGI(TAG, "Sending STATUS command for polling");
|
||||||
err = udp_client_.send_command(STATUS_COMMAND);
|
err = udp_client_.send_command(STATUS_COMMAND);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGW(TAG, "Failed to send STATUS command");
|
|
||||||
consecutive_failures_++;
|
consecutive_failures_++;
|
||||||
|
ESP_LOGW(TAG, "Failed to send STATUS command for polling. Consecutive failures: %d",
|
||||||
|
consecutive_failures_);
|
||||||
|
|
||||||
if (consecutive_failures_ >= MAX_FAILURES_BEFORE_ERROR) {
|
if (consecutive_failures_ >= MAX_FAILURES_BEFORE_ERROR) {
|
||||||
if (on_status_update_callback_) {
|
if (on_status_update_callback_) {
|
||||||
@@ -221,12 +213,15 @@ void IotDisBridge::poll_status_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for response to STATUS command
|
// Wait for response to STATUS command
|
||||||
|
ESP_LOGI(TAG, "Waiting for response to STATUS command (timeout: %dms)", RESPONSE_TIMEOUT_MS);
|
||||||
std::string response;
|
std::string response;
|
||||||
err = udp_client_.receive_response(response, RESPONSE_TIMEOUT_MS);
|
err = udp_client_.receive_response(response, RESPONSE_TIMEOUT_MS);
|
||||||
|
ESP_LOGI(TAG, "Received response from STATUS command: err=%d", err);
|
||||||
|
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
// Success - reset failure counter
|
// Success - reset failure counter
|
||||||
consecutive_failures_ = 0;
|
consecutive_failures_ = 0;
|
||||||
|
ESP_LOGI(TAG, "STATUS response: %s", response.c_str());
|
||||||
|
|
||||||
StatusUpdateEventData event_data {
|
StatusUpdateEventData event_data {
|
||||||
.state = StatusUpdateEventData::VoiceState::UNKNOWN
|
.state = StatusUpdateEventData::VoiceState::UNKNOWN
|
||||||
@@ -236,15 +231,19 @@ void IotDisBridge::poll_status_() {
|
|||||||
} else if (response == UNMUTED_RESPONSE) {
|
} else if (response == UNMUTED_RESPONSE) {
|
||||||
event_data.state = StatusUpdateEventData::VoiceState::UNMUTED;
|
event_data.state = StatusUpdateEventData::VoiceState::UNMUTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Invoking status update callback with state: %d", event_data.state);
|
||||||
if (on_status_update_callback_) {
|
if (on_status_update_callback_) {
|
||||||
on_status_update_callback_(event_data, status_event_user_data_);
|
on_status_update_callback_(event_data, status_event_user_data_);
|
||||||
|
ESP_LOGI(TAG, "Status update callback returned");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Timeout or error
|
// Timeout or error
|
||||||
consecutive_failures_++;
|
consecutive_failures_++;
|
||||||
ESP_LOGW(TAG, "No response to STATUS (failures: %d)", consecutive_failures_);
|
ESP_LOGW(TAG, "No response to STATUS (failures: %d, error: %d)", consecutive_failures_, err);
|
||||||
|
|
||||||
if (consecutive_failures_ >= MAX_FAILURES_BEFORE_ERROR) {
|
if (consecutive_failures_ >= MAX_FAILURES_BEFORE_ERROR) {
|
||||||
|
ESP_LOGW(TAG, "Max failures reached, sending ERROR state");
|
||||||
if (on_status_update_callback_) {
|
if (on_status_update_callback_) {
|
||||||
on_status_update_callback_(
|
on_status_update_callback_(
|
||||||
StatusUpdateEventData { .state = StatusUpdateEventData::VoiceState::ERROR },
|
StatusUpdateEventData { .state = StatusUpdateEventData::VoiceState::ERROR },
|
||||||
@@ -253,4 +252,6 @@ void IotDisBridge::poll_status_() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "poll_status_ complete");
|
||||||
}
|
}
|
||||||
@@ -45,8 +45,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr int POLL_INTERVAL_MS = 2000;
|
static constexpr int POLL_INTERVAL_MS = 10000;
|
||||||
static constexpr int ERROR_POLL_INTERVAL_MS = 5000;
|
static constexpr int ERROR_POLL_INTERVAL_MS = 20000;
|
||||||
static constexpr int RESPONSE_TIMEOUT_MS = 1000;
|
static constexpr int RESPONSE_TIMEOUT_MS = 1000;
|
||||||
static constexpr int MAX_FAILURES_BEFORE_ERROR = 3;
|
static constexpr int MAX_FAILURES_BEFORE_ERROR = 3;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "ui/apps/iotdis/app.h"
|
#include "ui/apps/iotdis/app.h"
|
||||||
#include "ui/interaction_handler.h"
|
#include "ui/interaction_handler.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
|
|
||||||
static const char* TAG = "MainUI";
|
static const char* TAG = "MainUI";
|
||||||
|
|
||||||
@@ -28,6 +29,15 @@ esp_err_t MainUI::deinit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainUI::create_ui_(lv_obj_t* parent) {
|
void MainUI::create_ui_(lv_obj_t* parent) {
|
||||||
|
if (!parent) {
|
||||||
|
ESP_LOGE(TAG, "Parent LVGL object is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lvgl_port_lock(pdMS_TO_TICKS(100))) {
|
||||||
|
ESP_LOGE(TAG, "Failed to acquire LVGL lock for UI creation");
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Set up main page with flex column layout
|
// Set up main page with flex column layout
|
||||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||||
lv_obj_set_flex_align(parent, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
lv_obj_set_flex_align(parent, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||||
@@ -101,6 +111,7 @@ void MainUI::create_ui_(lv_obj_t* parent) {
|
|||||||
lv_obj_center(settings_icon);
|
lv_obj_center(settings_icon);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Main UI created");
|
ESP_LOGI(TAG, "Main UI created");
|
||||||
|
lvgl_port_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t MainUI::register_on_settings_button_clicked(lv_event_cb_t cb, void* user_data) {
|
esp_err_t MainUI::register_on_settings_button_clicked(lv_event_cb_t cb, void* user_data) {
|
||||||
@@ -124,6 +135,11 @@ void MainUI::update_status(VoiceState state) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!lvgl_port_lock(pdMS_TO_TICKS(100))) {
|
||||||
|
ESP_LOGW(TAG, "Failed to acquire LVGL lock for status update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case VoiceState::MUTED:
|
case VoiceState::MUTED:
|
||||||
lv_label_set_text(status_icon_label_, LV_SYMBOL_MUTE);
|
lv_label_set_text(status_icon_label_, LV_SYMBOL_MUTE);
|
||||||
@@ -150,24 +166,40 @@ void MainUI::update_status(VoiceState state) {
|
|||||||
lv_obj_set_style_text_color(status_icon_label_, lv_color_black(), 0);
|
lv_obj_set_style_text_color(status_icon_label_, lv_color_black(), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
lvgl_port_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainUI::show_error_notification(bool show) {
|
void MainUI::show_error_notification(bool show) {
|
||||||
if (error_notification_) {
|
if (!error_notification_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lvgl_port_lock(pdMS_TO_TICKS(100))) {
|
||||||
|
ESP_LOGW(TAG, "Failed to acquire LVGL lock for error notification update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (show) {
|
if (show) {
|
||||||
lv_obj_clear_flag(error_notification_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_clear_flag(error_notification_, LV_OBJ_FLAG_HIDDEN);
|
||||||
} else {
|
} else {
|
||||||
lv_obj_add_flag(error_notification_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(error_notification_, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
}
|
lvgl_port_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainUI::update_config_prompt(bool configured) {
|
void MainUI::update_config_prompt(bool configured) {
|
||||||
if (config_prompt_) {
|
if (!config_prompt_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lvgl_port_lock(pdMS_TO_TICKS(100))) {
|
||||||
|
ESP_LOGW(TAG, "Failed to acquire LVGL lock for config prompt update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (configured) {
|
if (configured) {
|
||||||
lv_obj_add_flag(config_prompt_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(config_prompt_, LV_OBJ_FLAG_HIDDEN);
|
||||||
} else {
|
} else {
|
||||||
lv_obj_clear_flag(config_prompt_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_clear_flag(config_prompt_, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
}
|
lvgl_port_unlock();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,17 +106,24 @@ void MainUIHandler::send_mute_command_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainUIHandler::on_status_update_(StatusUpdateEventData data) {
|
void MainUIHandler::on_status_update_(StatusUpdateEventData data) {
|
||||||
|
ESP_LOGI(TAG, "on_status_update_ called with state: %d", data.state);
|
||||||
|
|
||||||
// Update state in thread-safe manner
|
// Update state in thread-safe manner
|
||||||
if (state_mutex_ && xSemaphoreTake(state_mutex_, pdMS_TO_TICKS(100)) == pdTRUE) {
|
if (state_mutex_ && xSemaphoreTake(state_mutex_, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||||
current_state_ = data.state;
|
current_state_ = data.state;
|
||||||
xSemaphoreGive(state_mutex_);
|
xSemaphoreGive(state_mutex_);
|
||||||
|
ESP_LOGI(TAG, "State updated in mutex");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update UI
|
// Update UI
|
||||||
|
ESP_LOGI(TAG, "Calling update_ui_()");
|
||||||
update_ui_();
|
update_ui_();
|
||||||
|
ESP_LOGI(TAG, "on_status_update_ complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainUIHandler::update_ui_() {
|
void MainUIHandler::update_ui_() {
|
||||||
|
ESP_LOGI(TAG, "update_ui_ called");
|
||||||
|
|
||||||
if (main_ui_) {
|
if (main_ui_) {
|
||||||
StatusUpdateEventData::VoiceState state;
|
StatusUpdateEventData::VoiceState state;
|
||||||
if (state_mutex_ && xSemaphoreTake(state_mutex_, pdMS_TO_TICKS(100)) == pdTRUE) {
|
if (state_mutex_ && xSemaphoreTake(state_mutex_, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||||
@@ -126,6 +133,8 @@ void MainUIHandler::update_ui_() {
|
|||||||
state = StatusUpdateEventData::VoiceState::UNKNOWN;
|
state = StatusUpdateEventData::VoiceState::UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Converting state: %d", state);
|
||||||
|
|
||||||
// Convert to MainUI VoiceState
|
// Convert to MainUI VoiceState
|
||||||
VoiceState ui_state;
|
VoiceState ui_state;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@@ -143,8 +152,14 @@ void MainUIHandler::update_ui_() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Calling main_ui_->update_status() with ui_state: %d", ui_state);
|
||||||
|
|
||||||
|
// Lock LVGL before calling UI functions from another task
|
||||||
main_ui_->update_status(ui_state);
|
main_ui_->update_status(ui_state);
|
||||||
|
ESP_LOGI(TAG, "main_ui_->update_status() returned");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "update_ui_ complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user