Landzo_K60Z_WebServer/src/lvgl_helpers.c

208 lines
4.9 KiB
C

#include <stdio.h>
/* LVGL */
#include "lvgl.h"
/* FreeRTOS */
#include "FreeRTOS.h"
#include "event_groups.h"
#include "semphr.h"
#include "task.h"
/* FatFS */
#include "ff.h"
/* LCD */
#include "epd-spi/panel/lcd_generic_ssd1289.h"
#include "lcd_impl.h"
#define LVGL_FS_BASE "0:/LV_ROOT/"
#define LVGL_RES_HOR 240
#define LVGL_RES_VER 320
SemaphoreHandle_t g_lvgl_semphr;
EventGroupHandle_t g_lvgl_event_group;
static lv_disp_draw_buf_t s_lvgl_disp_buf;
static lv_disp_drv_t s_lvgl_disp_drv;
static lv_fs_drv_t s_lvgl_fs_drv;
static lcd_impl_t s_lcd_impl;
static lcd_generic_ssd1289_t s_lcd = {
.cb =
{
.reset_cb = epd_impl_reset,
.write_command_cb = epd_impl_write_command,
.write_data_cb = epd_impl_write_data,
},
.dir = LCD_GENERIC_SSD1289_DIR_VERTICAL,
.mode = LCD_GENERIC_SSD1289_MODE_XBRG8888,
.user_data = &s_lcd_impl,
};
__attribute((section(".lvgl_buffer"))) static lv_color_t s_lvgl_buf_1[LVGL_RES_HOR * 20];
__attribute((section(".lvgl_buffer"))) static lv_color_t s_lvgl_buf_2[LVGL_RES_HOR * 20];
void lvgl_task(void *pvParameters);
static void lvgl_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) {
lcd_generic_ssd1289_t *lcd = disp_drv->user_data;
epd_coord_t coord = {
.x_start = area->x1,
.x_end = area->x2,
.y_start = area->y1,
.y_end = area->y2,
};
lcd_generic_ssd1289_upload(lcd, &coord, (uint8_t *)color_p);
lv_disp_flush_ready(disp_drv);
}
static void 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) {
/* 4 bytes per pixel. */
uint32_t *px = (uint32_t *)&buf[(y * buf_w + x) * 4];
/* Set color */
*px = color.ch.green & 0xFFU;
*px |= (color.ch.red & 0xFFU) << 8U;
*px |= (color.ch.blue & 0xFFU) << 16U;
}
static void *lvgl_fs_open_cb(lv_fs_drv_t *drv, const char *path, lv_fs_mode_t mode) {
FIL *fp = pvPortMalloc(sizeof(FIL));
if (fp == NULL) {
return NULL;
}
char *ff_path = pvPortMalloc(255);
if (ff_path == NULL) {
vPortFree(fp);
return NULL;
}
snprintf(ff_path, 255, LVGL_FS_BASE "%s", path);
FRESULT res = f_open(fp, ff_path, FA_READ);
if (res != FR_OK) {
vPortFree(ff_path);
vPortFree(fp);
return NULL;
}
vPortFree(ff_path);
return fp;
}
static lv_fs_res_t lvgl_fs_close_cb(lv_fs_drv_t *drv, void *file_p) {
FIL *fp = file_p;
FRESULT res = f_close(fp);
vPortFree(fp);
if (res != FR_OK) {
return LV_FS_RES_FS_ERR;
}
return LV_FS_RES_OK;
}
static lv_fs_res_t lvgl_fs_read_cb(lv_fs_drv_t *drv, void *file_p, void *buf, uint32_t btr, uint32_t *br) {
FIL *fp = file_p;
FRESULT res = f_read(fp, buf, btr, (unsigned int *)br);
if (res != FR_OK) {
return LV_FS_RES_FS_ERR;
}
return LV_FS_RES_OK;
}
static lv_fs_res_t lvgl_fs_seek_cb(lv_fs_drv_t *drv, void *file_p, uint32_t pos, lv_fs_whence_t whence) {
FRESULT res;
FIL *fp = file_p;
uint32_t size = f_size(fp);
if (whence != LV_FS_SEEK_CUR) {
res = f_rewind(fp);
if (res != FR_OK) {
return LV_FS_RES_FS_ERR;
}
}
if (whence == LV_FS_SEEK_END) {
pos = (size - 1) - pos;
}
res = f_lseek(fp, pos);
if (res != FR_OK) {
return LV_FS_RES_FS_ERR;
}
return LV_FS_RES_OK;
}
int lvgl_setup(void) {
lv_init();
lv_disp_draw_buf_init(&s_lvgl_disp_buf, s_lvgl_buf_1, s_lvgl_buf_2, LVGL_RES_HOR * 10);
epd_impl_init(&s_lcd_impl);
lcd_generic_ssd1289_init(&s_lcd);
lv_disp_drv_init(&s_lvgl_disp_drv);
s_lvgl_disp_drv.draw_buf = &s_lvgl_disp_buf;
s_lvgl_disp_drv.user_data = &s_lcd;
s_lvgl_disp_drv.flush_cb = lvgl_flush_cb;
s_lvgl_disp_drv.set_px_cb = lvgl_set_px_cb;
s_lvgl_disp_drv.hor_res = LVGL_RES_HOR;
s_lvgl_disp_drv.ver_res = LVGL_RES_VER;
lv_disp_drv_register(&s_lvgl_disp_drv);
lv_fs_drv_init(&s_lvgl_fs_drv);
s_lvgl_fs_drv.letter = 'A';
s_lvgl_fs_drv.open_cb = lvgl_fs_open_cb;
s_lvgl_fs_drv.close_cb = lvgl_fs_close_cb;
s_lvgl_fs_drv.read_cb = lvgl_fs_read_cb;
s_lvgl_fs_drv.seek_cb = lvgl_fs_seek_cb;
lv_fs_drv_register(&s_lvgl_fs_drv);
g_lvgl_semphr = xSemaphoreCreateBinary();
if (g_lvgl_semphr == NULL) {
return -1;
}
xSemaphoreGive(g_lvgl_semphr);
if (xTaskCreate(lvgl_task, "LVTASK", 2048, NULL, 32, NULL) != pdPASS) {
return -3;
}
return 0;
}
uint32_t lvgl_millis(void) {
return xTaskGetTickCount();
}
void lvgl_task(void *pvParameters) {
for (;;) {
if (xSemaphoreTake(g_lvgl_semphr, pdMS_TO_TICKS(150)) == pdTRUE) {
lv_timer_handler();
xSemaphoreGive(g_lvgl_semphr);
}
vTaskDelay(pdMS_TO_TICKS(15));
}
}