|
| 1 | +#include "fallback.h" |
| 2 | +#include "pins_config.h" |
| 3 | +#include "rm67162.h" // LCD driver |
| 4 | +#include <lvgl.h> // Ensure you have LVGL |
| 5 | +#include <WiFi.h> // (If you need Wi-Fi info in fallback) |
| 6 | +#include <FS.h> // Possibly for file ops |
| 7 | +#include <SD_MMC.h> // If needed for fallback? |
| 8 | + |
| 9 | +// We'll store references to the fallback label + gif |
| 10 | +static lv_obj_t* fb_label = nullptr; |
| 11 | +static lv_obj_t* fb_gif = nullptr; |
| 12 | + |
| 13 | +// A local display buffer/driver just for fallback, if you want separate from dynamic |
| 14 | +static lv_disp_draw_buf_t fbDrawBuf; |
| 15 | +static lv_color_t* fbBuf = nullptr; |
| 16 | + |
| 17 | +// The flush callback |
| 18 | +static void fallback_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { |
| 19 | + uint32_t w = (area->x2 - area->x1 + 1); |
| 20 | + uint32_t h = (area->y2 - area->y1 + 1); |
| 21 | + lcd_PushColors(area->x1, area->y1, w, h, (uint16_t *)&color_p->full); |
| 22 | + lv_disp_flush_ready(disp); |
| 23 | +} |
| 24 | + |
| 25 | +// Animation callback |
| 26 | +static void scroll_anim_cb(void *var, int32_t v) { |
| 27 | + lv_obj_set_y((lv_obj_t *)var, v); |
| 28 | +} |
| 29 | + |
| 30 | +// Helper to create the scrolling animation |
| 31 | +static void create_scroll_animation(lv_obj_t *obj, int32_t start, int32_t end, uint32_t duration) { |
| 32 | + lv_anim_t a; |
| 33 | + lv_anim_init(&a); |
| 34 | + lv_anim_set_var(&a, obj); |
| 35 | + lv_anim_set_values(&a, start, end); |
| 36 | + lv_anim_set_time(&a, duration); |
| 37 | + lv_anim_set_exec_cb(&a, scroll_anim_cb); |
| 38 | + lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out); // Smooth |
| 39 | + lv_anim_set_repeat_count(&a, 2); // Repeat twice |
| 40 | + |
| 41 | + // On animation finish, hide label, show GIF |
| 42 | + lv_anim_set_ready_cb(&a, [](lv_anim_t *anim) { |
| 43 | + lv_obj_t *obj = (lv_obj_t *)anim->var; |
| 44 | + lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); |
| 45 | + lv_obj_clear_flag(fb_gif, LV_OBJ_FLAG_HIDDEN); |
| 46 | + }); |
| 47 | + |
| 48 | + lv_anim_start(&a); |
| 49 | +} |
| 50 | + |
| 51 | +void fallback_setup() { |
| 52 | + Serial.println("FALLBACK: Setting up scrolling label + GIF..."); |
| 53 | + |
| 54 | + // 1) Minimal LVGL init (only if not already done). |
| 55 | + // If your main code calls lv_init() elsewhere, |
| 56 | + // you might skip or check if it’s safe to call again. |
| 57 | + lv_init(); |
| 58 | + |
| 59 | + // 2) Power on the screen, set backlight |
| 60 | + pinMode(PIN_LED, OUTPUT); |
| 61 | + digitalWrite(PIN_LED, HIGH); |
| 62 | + |
| 63 | + // 3) Init your display driver |
| 64 | + rm67162_init(); |
| 65 | + lcd_setRotation(1); |
| 66 | + |
| 67 | + // 4) Allocate a buffer for fallback usage |
| 68 | + fbBuf = (lv_color_t*) ps_malloc(sizeof(lv_color_t) * LVGL_LCD_BUF_SIZE); |
| 69 | + if(!fbBuf) { |
| 70 | + Serial.println("FALLBACK: Failed to allocate buffer"); |
| 71 | + return; |
| 72 | + } |
| 73 | + |
| 74 | + lv_disp_draw_buf_init(&fbDrawBuf, fbBuf, nullptr, LVGL_LCD_BUF_SIZE); |
| 75 | + |
| 76 | + // 5) Register fallback display driver |
| 77 | + static lv_disp_drv_t disp_drv; |
| 78 | + lv_disp_drv_init(&disp_drv); |
| 79 | + disp_drv.hor_res = 536; |
| 80 | + disp_drv.ver_res = 240; |
| 81 | + disp_drv.flush_cb = fallback_disp_flush; |
| 82 | + disp_drv.draw_buf = &fbDrawBuf; |
| 83 | + lv_disp_drv_register(&disp_drv); |
| 84 | + |
| 85 | + // 6) Create a style for the label |
| 86 | + static lv_style_t style; |
| 87 | + lv_style_init(&style); |
| 88 | + lv_style_set_text_font(&style, &lv_font_montserrat_40); |
| 89 | + lv_style_set_text_color(&style, lv_color_white()); |
| 90 | + lv_style_set_bg_color(&style, lv_color_black()); |
| 91 | + lv_style_set_pad_all(&style, 5); |
| 92 | + lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER); |
| 93 | + |
| 94 | + // 7) Create the label |
| 95 | + fb_label = lv_label_create(lv_scr_act()); |
| 96 | + lv_obj_add_style(fb_label, &style, 0); |
| 97 | + lv_label_set_text(fb_label, |
| 98 | + "/\\_/\\\n" |
| 99 | + "= ( • . • ) =\n" |
| 100 | + " / \\ \n" |
| 101 | + "Welcome to Webscreen! This is the Notification App, you can also run apps from the SD card.\n" |
| 102 | + " \n" |
| 103 | + " \n" |
| 104 | + ); |
| 105 | + lv_label_set_long_mode(fb_label, LV_LABEL_LONG_WRAP); |
| 106 | + lv_obj_set_width(fb_label, 525); |
| 107 | + lv_obj_align(fb_label, LV_ALIGN_CENTER, 0, 0); |
| 108 | + |
| 109 | + // 8) Create the scroll animation |
| 110 | + create_scroll_animation(fb_label, 240, -lv_obj_get_height(fb_label), 10000); |
| 111 | + |
| 112 | + // 9) Create the GIF |
| 113 | + fb_gif = lv_gif_create(lv_scr_act()); |
| 114 | + lv_gif_set_src(fb_gif, ¬ification); // from notification.h |
| 115 | + lv_obj_align(fb_gif, LV_ALIGN_CENTER, 0, 0); |
| 116 | + |
| 117 | + // Show label first, hide GIF |
| 118 | + lv_obj_clear_flag(fb_label, LV_OBJ_FLAG_HIDDEN); |
| 119 | + lv_obj_add_flag(fb_gif, LV_OBJ_FLAG_HIDDEN); |
| 120 | +} |
| 121 | + |
| 122 | +void fallback_loop() { |
| 123 | + // Let LVGL run |
| 124 | + lv_timer_handler(); |
| 125 | + |
| 126 | + // If serial data arrives, treat that as an input to update label |
| 127 | + if (Serial.available()) { |
| 128 | + String line = Serial.readStringUntil('\n'); |
| 129 | + lv_label_set_text(fb_label, line.c_str()); |
| 130 | + lv_obj_align(fb_label, LV_ALIGN_CENTER, 0, 0); |
| 131 | + lv_obj_clear_flag(fb_label, LV_OBJ_FLAG_HIDDEN); |
| 132 | + lv_obj_add_flag(fb_gif, LV_OBJ_FLAG_HIDDEN); |
| 133 | + |
| 134 | + // re-run animation |
| 135 | + create_scroll_animation(fb_label, 240, -lv_obj_get_height(fb_label), 10000); |
| 136 | + } |
| 137 | +} |
0 commit comments