custom_lcd_display.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #include "custom_lcd_display.h"
  2. #include "lcd_display.h"
  3. #include <vector>
  4. #include <font_awesome_symbols.h>
  5. #include <esp_log.h>
  6. #include <esp_err.h>
  7. #include <esp_lvgl_port.h>
  8. #include "assets/lang_config.h"
  9. #include <cstring>
  10. #include "settings.h"
  11. #include "esp_lcd_panel_io.h"
  12. #include "freertos/FreeRTOS.h"
  13. #include "freertos/task.h"
  14. #include "freertos/semphr.h"
  15. #include "config.h"
  16. #include "board.h"
  17. #define TAG "CustomLcdDisplay"
  18. // Color definitions for dark theme
  19. #define DARK_BACKGROUND_COLOR lv_color_hex(0x121212) // Dark background
  20. #define DARK_TEXT_COLOR lv_color_white() // White text
  21. #define DARK_CHAT_BACKGROUND_COLOR lv_color_hex(0x1E1E1E) // Slightly lighter than background
  22. #define DARK_USER_BUBBLE_COLOR lv_color_hex(0x1A6C37) // Dark green
  23. #define DARK_ASSISTANT_BUBBLE_COLOR lv_color_hex(0x333333) // Dark gray
  24. #define DARK_SYSTEM_BUBBLE_COLOR lv_color_hex(0x2A2A2A) // Medium gray
  25. #define DARK_SYSTEM_TEXT_COLOR lv_color_hex(0xAAAAAA) // Light gray text
  26. #define DARK_BORDER_COLOR lv_color_hex(0x333333) // Dark gray border
  27. #define DARK_LOW_BATTERY_COLOR lv_color_hex(0xFF0000) // Red for dark mode
  28. // Color definitions for light theme
  29. #define LIGHT_BACKGROUND_COLOR lv_color_white() // White background
  30. #define LIGHT_TEXT_COLOR lv_color_black() // Black text
  31. #define LIGHT_CHAT_BACKGROUND_COLOR lv_color_hex(0xE0E0E0) // Light gray background
  32. #define LIGHT_USER_BUBBLE_COLOR lv_color_hex(0x95EC69) // WeChat green
  33. #define LIGHT_ASSISTANT_BUBBLE_COLOR lv_color_white() // White
  34. #define LIGHT_SYSTEM_BUBBLE_COLOR lv_color_hex(0xE0E0E0) // Light gray
  35. #define LIGHT_SYSTEM_TEXT_COLOR lv_color_hex(0x666666) // Dark gray text
  36. #define LIGHT_BORDER_COLOR lv_color_hex(0xE0E0E0) // Light gray border
  37. #define LIGHT_LOW_BATTERY_COLOR lv_color_black() // Black for light mode
  38. // Define dark theme colors
  39. static const ThemeColors DARK_THEME = {
  40. .background = DARK_BACKGROUND_COLOR,
  41. .text = DARK_TEXT_COLOR,
  42. .chat_background = DARK_CHAT_BACKGROUND_COLOR,
  43. .user_bubble = DARK_USER_BUBBLE_COLOR,
  44. .assistant_bubble = DARK_ASSISTANT_BUBBLE_COLOR,
  45. .system_bubble = DARK_SYSTEM_BUBBLE_COLOR,
  46. .system_text = DARK_SYSTEM_TEXT_COLOR,
  47. .border = DARK_BORDER_COLOR,
  48. .low_battery = DARK_LOW_BATTERY_COLOR
  49. };
  50. // Define light theme colors
  51. static const ThemeColors LIGHT_THEME = {
  52. .background = LIGHT_BACKGROUND_COLOR,
  53. .text = LIGHT_TEXT_COLOR,
  54. .chat_background = LIGHT_CHAT_BACKGROUND_COLOR,
  55. .user_bubble = LIGHT_USER_BUBBLE_COLOR,
  56. .assistant_bubble = LIGHT_ASSISTANT_BUBBLE_COLOR,
  57. .system_bubble = LIGHT_SYSTEM_BUBBLE_COLOR,
  58. .system_text = LIGHT_SYSTEM_TEXT_COLOR,
  59. .border = LIGHT_BORDER_COLOR,
  60. .low_battery = LIGHT_LOW_BATTERY_COLOR
  61. };
  62. // Current theme - initialize based on default config
  63. static ThemeColors current_theme = LIGHT_THEME;
  64. static SemaphoreHandle_t trans_done_sem = NULL;
  65. static uint16_t *trans_act;
  66. static uint16_t *trans_buf_1;
  67. static uint16_t *trans_buf_2;
  68. bool CustomLcdDisplay::lvgl_port_flush_io_ready_callback(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
  69. {
  70. BaseType_t taskAwake = pdFALSE;
  71. lv_display_t *disp_drv = (lv_display_t *)user_ctx;
  72. assert(disp_drv != NULL);
  73. if (trans_done_sem) {
  74. xSemaphoreGiveFromISR(trans_done_sem, &taskAwake);
  75. }
  76. return false;
  77. }
  78. void CustomLcdDisplay::lvgl_port_flush_callback(lv_display_t *drv, const lv_area_t *area, uint8_t *color_map)
  79. {
  80. assert(drv != NULL);
  81. esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)lv_display_get_driver_data(drv);
  82. assert(panel_handle != NULL);
  83. size_t len = lv_area_get_size(area);
  84. lv_draw_sw_rgb565_swap(color_map, len);
  85. const int x_start = area->x1;
  86. const int x_end = area->x2;
  87. const int y_start = area->y1;
  88. const int y_end = area->y2;
  89. const int width = x_end - x_start + 1;
  90. const int height = y_end - y_start + 1;
  91. int32_t hor_res = lv_display_get_horizontal_resolution(drv);
  92. int32_t ver_res = lv_display_get_vertical_resolution(drv);
  93. // printf("hor_res: %ld, ver_res: %ld\r\n", hor_res, ver_res);
  94. // printf("x_start: %d, x_end: %d, y_start: %d, y_end: %d, width: %d, height: %d\r\n", x_start, x_end, y_start, y_end, width, height);
  95. uint16_t *from = (uint16_t *)color_map;
  96. uint16_t *to = NULL;
  97. if (DISPLAY_TRANS_SIZE > 0) {
  98. assert(trans_buf_1 != NULL);
  99. int x_draw_start = 0;
  100. int x_draw_end = 0;
  101. int y_draw_start = 0;
  102. int y_draw_end = 0;
  103. int trans_count = 0;
  104. trans_act = trans_buf_1;
  105. lv_display_rotation_t rotate = LV_DISPLAY_ROTATION;
  106. int x_start_tmp = 0;
  107. int x_end_tmp = 0;
  108. int max_width = 0;
  109. int trans_width = 0;
  110. int y_start_tmp = 0;
  111. int y_end_tmp = 0;
  112. int max_height = 0;
  113. int trans_height = 0;
  114. if (LV_DISPLAY_ROTATION_270 == rotate || LV_DISPLAY_ROTATION_90 == rotate) {
  115. max_width = ((DISPLAY_TRANS_SIZE / height) > width) ? (width) : (DISPLAY_TRANS_SIZE / height);
  116. trans_count = width / max_width + (width % max_width ? (1) : (0));
  117. x_start_tmp = x_start;
  118. x_end_tmp = x_end;
  119. } else {
  120. max_height = ((DISPLAY_TRANS_SIZE / width) > height) ? (height) : (DISPLAY_TRANS_SIZE / width);
  121. trans_count = height / max_height + (height % max_height ? (1) : (0));
  122. y_start_tmp = y_start;
  123. y_end_tmp = y_end;
  124. }
  125. for (int i = 0; i < trans_count; i++) {
  126. if (LV_DISPLAY_ROTATION_90 == rotate) {
  127. trans_width = (x_end - x_start_tmp + 1) > max_width ? max_width : (x_end - x_start_tmp + 1);
  128. x_end_tmp = (x_end - x_start_tmp + 1) > max_width ? (x_start_tmp + max_width - 1) : x_end;
  129. } else if (LV_DISPLAY_ROTATION_270 == rotate) {
  130. trans_width = (x_end_tmp - x_start + 1) > max_width ? max_width : (x_end_tmp - x_start + 1);
  131. x_start_tmp = (x_end_tmp - x_start + 1) > max_width ? (x_end_tmp - trans_width + 1) : x_start;
  132. } else if (LV_DISPLAY_ROTATION_0 == rotate) {
  133. trans_height = (y_end - y_start_tmp + 1) > max_height ? max_height : (y_end - y_start_tmp + 1);
  134. y_end_tmp = (y_end - y_start_tmp + 1) > max_height ? (y_start_tmp + max_height - 1) : y_end;
  135. } else {
  136. trans_height = (y_end_tmp - y_start + 1) > max_height ? max_height : (y_end_tmp - y_start + 1);
  137. y_start_tmp = (y_end_tmp - y_start + 1) > max_height ? (y_end_tmp - max_height + 1) : y_start;
  138. }
  139. trans_act = (trans_act == trans_buf_1) ? (trans_buf_2) : (trans_buf_1);
  140. to = trans_act;
  141. switch (rotate) {
  142. case LV_DISPLAY_ROTATION_90:
  143. for (int y = 0; y < height; y++) {
  144. for (int x = 0; x < trans_width; x++) {
  145. *(to + x * height + (height - y - 1)) = *(from + y * width + x_start_tmp + x);
  146. }
  147. }
  148. x_draw_start = ver_res - y_end - 1;
  149. x_draw_end = ver_res - y_start - 1;
  150. y_draw_start = x_start_tmp;
  151. y_draw_end = x_end_tmp;
  152. break;
  153. case LV_DISPLAY_ROTATION_270:
  154. for (int y = 0; y < height; y++) {
  155. for (int x = 0; x < trans_width; x++) {
  156. *(to + (trans_width - x - 1) * height + y) = *(from + y * width + x_start_tmp + x);
  157. }
  158. }
  159. x_draw_start = y_start;
  160. x_draw_end = y_end;
  161. y_draw_start = hor_res - x_end_tmp - 1;
  162. y_draw_end = hor_res - x_start_tmp - 1;
  163. break;
  164. case LV_DISPLAY_ROTATION_180:
  165. for (int y = 0; y < trans_height; y++) {
  166. for (int x = 0; x < width; x++) {
  167. *(to + (trans_height - y - 1)*width + (width - x - 1)) = *(from + y_start_tmp * width + y * (width) + x);
  168. }
  169. }
  170. x_draw_start = hor_res - x_end - 1;
  171. x_draw_end = hor_res - x_start - 1;
  172. y_draw_start = ver_res - y_end_tmp - 1;
  173. y_draw_end = ver_res - y_start_tmp - 1;
  174. break;
  175. case LV_DISPLAY_ROTATION_0:
  176. for (int y = 0; y < trans_height; y++) {
  177. for (int x = 0; x < width; x++) {
  178. *(to + y * (width) + x) = *(from + y_start_tmp * width + y * (width) + x);
  179. }
  180. }
  181. x_draw_start = x_start;
  182. x_draw_end = x_end;
  183. y_draw_start = y_start_tmp;
  184. y_draw_end = y_end_tmp;
  185. break;
  186. default:
  187. break;
  188. }
  189. if (0 == i) {
  190. // if (disp_ctx->draw_wait_cb) {
  191. // disp_ctx->draw_wait_cb(disp_ctx->panel_handle->user_data);
  192. // }
  193. xSemaphoreGive(trans_done_sem);
  194. }
  195. xSemaphoreTake(trans_done_sem, portMAX_DELAY);
  196. // printf("i: %d, x_draw_start: %d, x_draw_end: %d, y_draw_start: %d, y_draw_end: %d\r\n", i, x_draw_start, x_draw_end, y_draw_start, y_draw_end);
  197. esp_lcd_panel_draw_bitmap(panel_handle, x_draw_start, y_draw_start, x_draw_end + 1, y_draw_end + 1, to);
  198. if (LV_DISPLAY_ROTATION_90 == rotate) {
  199. x_start_tmp += max_width;
  200. } else if (LV_DISPLAY_ROTATION_270 == rotate) {
  201. x_end_tmp -= max_width;
  202. } if (LV_DISPLAY_ROTATION_0 == rotate) {
  203. y_start_tmp += max_height;
  204. } else {
  205. y_end_tmp -= max_height;
  206. }
  207. }
  208. } else {
  209. esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_end + 1, y_end + 1, color_map);
  210. }
  211. lv_disp_flush_ready(drv);
  212. }
  213. CustomLcdDisplay::CustomLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel,
  214. int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy,
  215. DisplayFonts fonts)
  216. : LcdDisplay(panel_io, panel, fonts, width, height) {
  217. // width_ = width;
  218. // height_ = height;
  219. // draw white
  220. std::vector<uint16_t> buffer(width_, 0xFFFF);
  221. for (int y = 0; y < height_; y++) {
  222. esp_lcd_panel_draw_bitmap(panel_, 0, y, width_, y + 1, buffer.data());
  223. }
  224. // Set the display to on
  225. ESP_LOGI(TAG, "Turning display on");
  226. ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_, true));
  227. ESP_LOGI(TAG, "Initialize LVGL library");
  228. lv_init();
  229. ESP_LOGI(TAG, "Initialize LVGL port");
  230. lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
  231. port_cfg.task_priority = 1;
  232. port_cfg.timer_period_ms = 50;
  233. lvgl_port_init(&port_cfg);
  234. trans_done_sem = xSemaphoreCreateCounting(1, 0);
  235. trans_buf_1 = (uint16_t *)heap_caps_malloc(DISPLAY_TRANS_SIZE * sizeof(uint16_t), MALLOC_CAP_DMA);
  236. trans_buf_2 = (uint16_t *)heap_caps_malloc(DISPLAY_TRANS_SIZE * sizeof(uint16_t), MALLOC_CAP_DMA);
  237. #if 0
  238. ESP_LOGI(TAG, "Adding LCD screen");
  239. const lvgl_port_display_cfg_t display_cfg = {
  240. .io_handle = panel_io_,
  241. .panel_handle = panel_,
  242. .control_handle = nullptr,
  243. .buffer_size = static_cast<uint32_t>(width_ * height_),
  244. .double_buffer = false,
  245. .trans_size = 0,
  246. .hres = static_cast<uint32_t>(width_),
  247. .vres = static_cast<uint32_t>(height_),
  248. .monochrome = false,
  249. .rotation = {
  250. .swap_xy = swap_xy,
  251. .mirror_x = mirror_x,
  252. .mirror_y = mirror_y,
  253. },
  254. .color_format = LV_COLOR_FORMAT_RGB565,
  255. .flags = {
  256. .buff_dma = 0,
  257. .buff_spiram = 1,
  258. .sw_rotate = 0,
  259. .swap_bytes = 1,
  260. .full_refresh = 1,
  261. .direct_mode = 0,
  262. },
  263. };
  264. display_ = lvgl_port_add_disp(&display_cfg);
  265. lv_display_set_flush_cb(display_, lvgl_port_flush_callback);
  266. #else
  267. uint32_t buffer_size = 0;
  268. lv_color_t *buf1 = NULL;
  269. lvgl_port_lock(0);
  270. uint8_t color_bytes = lv_color_format_get_size(LV_COLOR_FORMAT_RGB565);
  271. display_ = lv_display_create(width_, height_);
  272. lv_display_set_flush_cb(display_, lvgl_port_flush_callback);
  273. buffer_size = width_ * height_;
  274. buf1 = (lv_color_t *)heap_caps_aligned_alloc(1, buffer_size * color_bytes, MALLOC_CAP_SPIRAM);
  275. lv_display_set_buffers(display_, buf1, NULL, buffer_size * color_bytes, LV_DISPLAY_RENDER_MODE_FULL);
  276. lv_display_set_driver_data(display_, panel_);
  277. lvgl_port_unlock();
  278. #endif
  279. esp_lcd_panel_io_callbacks_t cbs = {
  280. .on_color_trans_done = lvgl_port_flush_io_ready_callback,
  281. };
  282. /* Register done callback */
  283. esp_lcd_panel_io_register_event_callbacks(panel_io_, &cbs, display_);
  284. esp_lcd_panel_disp_on_off(panel_, false);
  285. if (display_ == nullptr) {
  286. ESP_LOGE(TAG, "Failed to add display");
  287. return;
  288. }
  289. if (offset_x != 0 || offset_y != 0) {
  290. lv_display_set_offset(display_, offset_x, offset_y);
  291. }
  292. // Update the theme
  293. if (current_theme_name_ == "dark") {
  294. current_theme = DARK_THEME;
  295. } else if (current_theme_name_ == "light") {
  296. current_theme = LIGHT_THEME;
  297. }
  298. SetupUI();
  299. }