|
| 1 | +// fallback.cpp |
| 2 | +#include <Arduino.h> |
| 3 | +#include "lvgl.h" |
| 4 | +#include "rm67162.h" |
| 5 | +#include "notification.h" // Contains 'extern const lv_img_dsc_t notification;' |
| 6 | + |
| 7 | +// External objects |
| 8 | +extern lv_disp_draw_buf_t draw_buf; // or create local if you prefer |
| 9 | +extern lv_color_t *buf; // or create local |
| 10 | +extern bool fallbackActive; // Exposed globally for your main |
| 11 | + |
| 12 | +// The GIF from notification.h |
| 13 | +extern const lv_img_dsc_t notification; |
| 14 | + |
| 15 | +// We'll keep these static to avoid collisions |
| 16 | +static lv_obj_t *label = nullptr; |
| 17 | +static lv_obj_t *gif = nullptr; |
| 18 | + |
| 19 | +static void my_disp_flush_fallback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { |
| 20 | + // Display flush provided by rm67162 or your custom driver |
| 21 | + // e.g.: |
| 22 | + uint32_t w = (area->x2 - area->x1 + 1); |
| 23 | + uint32_t h = (area->y2 - area->y1 + 1); |
| 24 | + lcd_PushColors(area->x1, area->y1, w, h, (uint16_t *)&color_p->full); |
| 25 | + lv_disp_flush_ready(disp); |
| 26 | +} |
| 27 | + |
| 28 | +static void scroll_anim_cb(void *var, int32_t v) { |
| 29 | + lv_obj_set_y((lv_obj_t *)var, v); |
| 30 | +} |
| 31 | + |
| 32 | +static void create_scroll_animation(lv_obj_t *obj, int32_t start, int32_t end, uint32_t duration) { |
| 33 | + lv_anim_t a; |
| 34 | + lv_anim_init(&a); |
| 35 | + lv_anim_set_var(&a, obj); |
| 36 | + lv_anim_set_values(&a, start, end); |
| 37 | + lv_anim_set_time(&a, duration); |
| 38 | + lv_anim_set_exec_cb(&a, scroll_anim_cb); |
| 39 | + lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out); |
| 40 | + lv_anim_set_repeat_count(&a, 2); // Repeat twice |
| 41 | + |
| 42 | + // When animation finishes, hide label, show GIF |
| 43 | + lv_anim_set_ready_cb(&a, [](lv_anim_t *anim) { |
| 44 | + lv_obj_t *obj = static_cast<lv_obj_t *>(anim->var); |
| 45 | + lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); // Hide text |
| 46 | + lv_obj_clear_flag(gif, LV_OBJ_FLAG_HIDDEN);// Show GIF |
| 47 | + }); |
| 48 | + lv_anim_start(&a); |
| 49 | +} |
| 50 | + |
| 51 | +// ------------------------------------------------------------------ |
| 52 | +// Fallback setup |
| 53 | +// ------------------------------------------------------------------ |
| 54 | +void fallback_setup() { |
| 55 | + Serial.println("FALLBACK: Setting up LVGL + scrolling label + GIF..."); |
| 56 | + |
| 57 | + // 1) Minimal LVGL init if not already done |
| 58 | + lv_init(); |
| 59 | + // 2) Screen on |
| 60 | + pinMode(PIN_LED, OUTPUT); |
| 61 | + digitalWrite(PIN_LED, HIGH); |
| 62 | + |
| 63 | + // 3) Init your AMOLED driver, set rotation |
| 64 | + rm67162_init(); |
| 65 | + lcd_setRotation(1); |
| 66 | + |
| 67 | + // 4) Allocate buffer |
| 68 | + buf = (lv_color_t *)ps_malloc(sizeof(lv_color_t) * LVGL_LCD_BUF_SIZE); |
| 69 | + if(!buf) { |
| 70 | + Serial.println("FALLBACK: Buffer alloc failed"); |
| 71 | + return; |
| 72 | + } |
| 73 | + |
| 74 | + // 5) Initialize draw buffer |
| 75 | + lv_disp_draw_buf_init(&draw_buf, buf, NULL, LVGL_LCD_BUF_SIZE); |
| 76 | + |
| 77 | + // 6) Register display driver |
| 78 | + static lv_disp_drv_t disp_drv; |
| 79 | + lv_disp_drv_init(&disp_drv); |
| 80 | + disp_drv.hor_res = 536; |
| 81 | + disp_drv.ver_res = 240; |
| 82 | + disp_drv.flush_cb = my_disp_flush_fallback; |
| 83 | + disp_drv.draw_buf = &draw_buf; |
| 84 | + lv_disp_drv_register(&disp_drv); |
| 85 | + |
| 86 | + // 7) Style |
| 87 | + static lv_style_t style; |
| 88 | + lv_style_init(&style); |
| 89 | + lv_style_set_text_font(&style, &lv_font_montserrat_40); |
| 90 | + lv_style_set_text_color(&style, lv_color_white()); |
| 91 | + lv_style_set_bg_color(&style, lv_color_black()); |
| 92 | + lv_style_set_pad_all(&style, 5); |
| 93 | + lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER); |
| 94 | + |
| 95 | + // 8) Create label |
| 96 | + label = lv_label_create(lv_scr_act()); |
| 97 | + lv_obj_add_style(label, &style, 0); |
| 98 | + lv_label_set_text(label, |
| 99 | + "This is fallback: a long text that will scroll automatically.\n" |
| 100 | + "Add more text to test scrolling.\n" |
| 101 | + "Eventually it shows a GIF afterwards." |
| 102 | + ); |
| 103 | + lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); |
| 104 | + lv_obj_set_width(label, 525); |
| 105 | + lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); |
| 106 | + |
| 107 | + // 9) Create scroll animation (10 seconds for a full scroll) |
| 108 | + create_scroll_animation(label, 240, -lv_obj_get_height(label), 10000); |
| 109 | + |
| 110 | + // 10) Create the GIF |
| 111 | + gif = lv_gif_create(lv_scr_act()); |
| 112 | + lv_gif_set_src(gif, ¬ification); |
| 113 | + lv_obj_align(gif, LV_ALIGN_CENTER, 0, 0); |
| 114 | + |
| 115 | + // Initially hide label, show GIF |
| 116 | + lv_obj_add_flag(label, LV_OBJ_FLAG_HIDDEN); |
| 117 | + lv_obj_clear_flag(gif, LV_OBJ_FLAG_HIDDEN); |
| 118 | + |
| 119 | + Serial.println("FALLBACK: Setup complete"); |
| 120 | +} |
| 121 | + |
| 122 | +// ------------------------------------------------------------------ |
| 123 | +// Fallback loop |
| 124 | +// ------------------------------------------------------------------ |
| 125 | +void fallback_loop() { |
| 126 | + lv_timer_handler(); |
| 127 | + |
| 128 | + // If there's serial input, re-animate the label with new text |
| 129 | + if (Serial.available()) { |
| 130 | + String received = Serial.readStringUntil('\n'); |
| 131 | + lv_label_set_text(label, received.c_str()); |
| 132 | + lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); |
| 133 | + lv_obj_clear_flag(label, LV_OBJ_FLAG_HIDDEN); |
| 134 | + lv_obj_add_flag(gif, LV_OBJ_FLAG_HIDDEN); |
| 135 | + |
| 136 | + create_scroll_animation(label, 240, -lv_obj_get_height(label), 10000); |
| 137 | + } |
| 138 | +} |
0 commit comments