ESP32_Weather/main/app_lvgl.c

145 lines
3.7 KiB
C

#include <stdio.h>
#include "sdkconfig.h"
/* FreeRTOS */
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
/* IDF drivers */
#include "esp_sleep.h"
#include "esp_spi_flash.h"
#include "esp_system.h"
#include "esp_log.h"
/* EPD driver */
#include "epd_driver.h"
#include "epd_highlevel.h"
/* LVGL */
#include "lvgl.h"
/* Private */
#include "app_lvgl.h"
#define LVGL_TASK_HEAP 4096
#define LVGL_TASK_INTERVAL 100
#define APP_LOG_TAG "APP_LVGL"
static EpdiyHighlevelState s_epd_hl;
static int s_temp = 26;
static lv_disp_draw_buf_t s_disp_buf;
static lv_color_t *s_screen_buf;
static lv_disp_drv_t s_disp_drv;
static SemaphoreHandle_t s_lvgl_semphr;
static void app_lvgl_task(void *pvParameters);
static void app_lvgl_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
static void app_lvgl_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa);
int app_lvgl_init(void) {
/* Initialize EPDIY */
epd_init(EPD_OPTIONS_DEFAULT);
s_epd_hl = epd_hl_init(EPD_BUILTIN_WAVEFORM);
s_screen_buf = (lv_color_t *)epd_hl_get_framebuffer(&s_epd_hl);
epd_poweron();
epd_fullclear(&s_epd_hl, s_temp);
epd_poweroff();
/* Initialize LVGL */
lv_init();
lv_disp_draw_buf_init(&s_disp_buf, s_screen_buf, NULL, 960 * 540);
lv_disp_drv_init(&s_disp_drv);
s_disp_drv.user_data = &s_epd_hl;
s_disp_drv.draw_buf = &s_disp_buf;
s_disp_drv.hor_res = 960;
s_disp_drv.ver_res = 540;
s_disp_drv.flush_cb = app_lvgl_flush_cb;
s_disp_drv.set_px_cb = app_lvgl_set_px_cb;
lv_disp_drv_register(&s_disp_drv);
s_lvgl_semphr = xSemaphoreCreateMutex();
if (s_lvgl_semphr == NULL) {
ESP_LOGE(APP_LOG_TAG, "Failed to create LVGL semaphore.");
return -1;
}
if (xTaskCreate(app_lvgl_task, "LV_TASK", LVGL_TASK_HEAP, NULL, 2, NULL) != pdPASS) {
ESP_LOGE(APP_LOG_TAG, "Failed to create LVGL task, available heap: %d.", esp_get_free_heap_size());
return -2;
}
ESP_LOGI(APP_LOG_TAG, "LVGL initialized.");
return 0;
}
int app_lvgl_lock(uint32_t ms) {
if(xSemaphoreTake(s_lvgl_semphr, pdMS_TO_TICKS(ms)) != pdPASS) {
return -1;
}
return 0;
}
int app_lvgl_unlock(void) {
if(xSemaphoreGive(s_lvgl_semphr) != pdPASS) {
return -1;
}
return 0;
}
static void app_lvgl_task(void *pvParameters) {
for (;;) {
if(app_lvgl_lock(50) == 0) {
lv_timer_handler();
ESP_LOGD(APP_LOG_TAG, "LVGL timer handler executed.");
app_lvgl_unlock();
}
vTaskDelay(pdMS_TO_TICKS(LVGL_TASK_INTERVAL));
}
}
static void app_lvgl_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) {
EpdiyHighlevelState *hl = disp_drv->user_data;
EpdRect rect = {
.x = area->x1,
.y = area->y1,
.width = area->x2 - area->x1 + 1,
.height = area->y2 - area->y1 + 1,
};
ESP_LOGI(APP_LOG_TAG, "Flush called.");
epd_poweron();
epd_hl_update_area(hl, MODE_GC16, s_temp, rect);
epd_poweroff();
lv_disp_flush_ready(disp_drv);
}
static void app_lvgl_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa) {
uint32_t px_offset = (buf_w * y / 2) + x / 2;
uint8_t pix_y = lv_color_brightness(color);
pix_y = (pix_y / 16) & 0x0FU;
if (x % 2 == 0) {
buf[px_offset] &= 0xF0;
buf[px_offset] |= pix_y;
} else {
buf[px_offset] &= 0x0F;
buf[px_offset] |= pix_y << 4;
}
}