diff --git a/Firmware/CoverUI/YardForce/LEDcontrol.h b/Firmware/CoverUI/YardForce/LEDcontrol.h index 611da1a..25dfcd1 100644 --- a/Firmware/CoverUI/YardForce/LEDcontrol.h +++ b/Firmware/CoverUI/YardForce/LEDcontrol.h @@ -76,7 +76,7 @@ class LEDcontrol private: #ifdef MDL_C500 // Model Classic 500 const uint32_t kLeds[NUM_LEDS] = { - // FIXME: Why is it uint32_t large? Test with C500 in STM & GD variant. Should become uint16_t (because of NC case) + // FIXME: Why is it uint32_t large? Test with C500 in STM & GD variant. Should become uint16_t (not uint8_t because of NC case) // Order derived from LowLevel "enum LED_id" LED_PIN_CHARGE, // 0 LED_PIN_BAT, // 1 diff --git a/Firmware/CoverUI/YardForce/WYM240128K1.hpp b/Firmware/CoverUI/YardForce/WYM240128K1.hpp index 4ccec23..9680f10 100644 --- a/Firmware/CoverUI/YardForce/WYM240128K1.hpp +++ b/Firmware/CoverUI/YardForce/WYM240128K1.hpp @@ -21,6 +21,7 @@ #include #include "LEDcontrol.h" #include "WidgetLedSymbol.hpp" +#include "WidgetBar.hpp" // C images LV_IMG_DECLARE(OM_Logo_Inv_120x54x1); @@ -37,16 +38,9 @@ namespace display lv_disp_drv_t lv_disp_drv; // LVGL driver - // Widgets - lv_obj_t *gps_bar = nullptr; // GPS Bar - const std::string gps_bar_label_format = FA_SYMBOL_GPS2 " %d %%"; - lv_obj_t *bat_bar = nullptr; // Battery Bar - const std::string bat_bar_label_format = FA_SYMBOL_BATTERY " %d %%"; - lv_style_t bar_style_bg; - lv_style_t bar_style_indic; - - // Status symbols + // Status Screen Widgets WidgetLedSymbol *v_led_ros, *v_led_charge; + WidgetBar *bar_gps, *bar_bat; /** * @brief Rounder callback will round the display area to a multiple of 3, on x axis (RGB control lines of a pixel are connected to 3 monochrome pixels) @@ -87,80 +81,14 @@ namespace display lv_disp_flush_ready(disp_drv); } - static void event_bar_label_cb(lv_event_t *e) - { - lv_obj_draw_part_dsc_t *dsc = lv_event_get_draw_part_dsc(e); - if (dsc->part != LV_PART_INDICATOR) - return; - - lv_obj_t *obj = lv_event_get_target(e); - int32_t bar_value = lv_bar_get_value(obj); - lv_draw_label_dsc_t label_dsc; - lv_draw_label_dsc_init(&label_dsc); - - char buf[12]; - lv_snprintf(buf, sizeof(buf), (const char *)lv_obj_get_user_data(obj), bar_value); - - lv_point_t txt_size; - lv_txt_get_size(&txt_size, buf, label_dsc.font, label_dsc.letter_space, label_dsc.line_space, LV_COORD_MAX, - label_dsc.flag); - - lv_area_t txt_area; - // If the indicator is long enough put the text inside on the right - if (lv_area_get_width(dsc->draw_area) > txt_size.x + 20) - { - txt_area.x2 = dsc->draw_area->x2 - 5; - txt_area.x1 = txt_area.x2 - txt_size.x + 1; - label_dsc.color = lv_color_black(); - } - // If the indicator is still short put the text out of it on the right - else - { - txt_area.x1 = dsc->draw_area->x2 + 5; - txt_area.x2 = txt_area.x1 + txt_size.x - 1; - label_dsc.color = lv_color_white(); - } - - txt_area.y1 = (dsc->draw_area->y1 + (lv_area_get_height(dsc->draw_area) - txt_size.y) / 2) + 1; - txt_area.y2 = txt_area.y1 + txt_size.y; - - lv_draw_label(dsc->draw_ctx, &label_dsc, &txt_area, buf, NULL); - } - - static void drawGPSBar() - { - gps_bar = lv_bar_create(lv_scr_act()); - lv_obj_set_user_data(gps_bar, (void *)gps_bar_label_format.c_str()); // Save label prefix to object user data - lv_obj_remove_style_all(gps_bar); // To have a clean start - lv_obj_add_style(gps_bar, &bar_style_bg, 0); - lv_obj_add_style(gps_bar, &bar_style_indic, LV_PART_INDICATOR); - - lv_obj_add_event_cb(gps_bar, event_bar_label_cb, LV_EVENT_DRAW_PART_END, NULL); - lv_obj_set_size(gps_bar, UC1698_DISPLAY_WIDTH, 21); - lv_obj_align(gps_bar, LV_ALIGN_TOP_MID, 0, 30); - } - - static void drawBatBar() - { - bat_bar = lv_bar_create(lv_scr_act()); - lv_obj_set_user_data(bat_bar, (void *)bat_bar_label_format.c_str()); // Save label prefix to object user data - lv_obj_remove_style_all(bat_bar); // To have a clean start - lv_obj_add_style(bat_bar, &bar_style_bg, 0); - lv_obj_add_style(bat_bar, &bar_style_indic, LV_PART_INDICATOR); - - lv_obj_add_event_cb(bat_bar, event_bar_label_cb, LV_EVENT_DRAW_PART_END, NULL); - lv_obj_set_size(bat_bar, UC1698_DISPLAY_WIDTH, 21); - lv_obj_align(bat_bar, LV_ALIGN_TOP_MID, 0, 60); - } - static void mainStatusScreen() { // Status symbols, from right to left v_led_charge = new WidgetLedSymbol(FA_SYMBOL_CHARGE, LV_ALIGN_OUT_TOP_RIGHT, (240 - (1 * 14)), 0); v_led_ros = new WidgetLedSymbol(FA_SYMBOL_ROS, LV_ALIGN_OUT_TOP_RIGHT, (240 - (2 * 14) - 5), 0); - - drawGPSBar(); - drawBatBar(); + // GPS & Battery bars + bar_gps = new WidgetBar(FA_SYMBOL_GPS2 " %d %%", LV_ALIGN_TOP_MID, 0, 30, UC1698_DISPLAY_WIDTH, 21); + bar_bat = new WidgetBar(FA_SYMBOL_BATTERY " %d %%", LV_ALIGN_TOP_MID, 0, 60, UC1698_DISPLAY_WIDTH, 21); } static void anim_x_cb(void *var, int32_t v) @@ -195,7 +123,7 @@ namespace display lv_anim_t aw; lv_anim_init(&aw); lv_anim_set_var(&aw, img_wordmark); - lv_anim_set_values(&aw, 0, (UC1698_DISPLAY_WIDTH / 2) + (OM_Wordmark_Inv_240x35x1.header.w / 2)); + lv_anim_set_values(&aw, 0, (UC1698_DISPLAY_WIDTH / 2) + (OM_Wordmark_Inv_240x35x1.header.w / 2) + 20); lv_anim_set_time(&aw, 2500); lv_anim_set_delay(&aw, 1700); lv_anim_set_exec_cb(&aw, (lv_anim_exec_xcb_t)anim_x_cb); @@ -233,18 +161,6 @@ namespace display disp = lv_disp_drv_register(&lv_disp_drv); // Register the driver and save the created display objects lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x000000), LV_PART_MAIN); // No background color - // Init bar style settings - lv_style_init(&bar_style_bg); - lv_style_set_border_color(&bar_style_bg, lv_color_hex(0xffffff)); - lv_style_set_border_width(&bar_style_bg, 2); - lv_style_set_pad_all(&bar_style_bg, 3); // To make the indicator smaller - lv_style_set_radius(&bar_style_bg, 4); - - lv_style_init(&bar_style_indic); - lv_style_set_bg_opa(&bar_style_indic, LV_OPA_COVER); - lv_style_set_bg_color(&bar_style_indic, lv_color_hex(0xffffff)); - lv_style_set_radius(&bar_style_indic, 1); - openmower_anim(); //mainStatusScreen(); // test1(); @@ -286,7 +202,7 @@ namespace display { next_display_data_ms = now + 100; // 100ms display data refresh - if (gps_bar != nullptr) + if (bar_gps != nullptr) { // Rev-calc GPS LEDs to percent int8_t gps_perc = 0; @@ -302,10 +218,11 @@ namespace display gps_perc += 25; // One LED represents 25% } } - lv_bar_set_value(gps_bar, gps_perc, LV_ANIM_OFF); + //lv_bar_set_value(gps_bar, gps_perc, LV_ANIM_OFF); + bar_gps->set_value(gps_perc); } - if (bat_bar != nullptr) + if (bar_bat != nullptr) { // Rev-calc Battery LEDs to percent uint8_t bat_perc = 0; @@ -315,12 +232,14 @@ namespace display continue; bat_perc += 15; // One LED represents 14.3% } - lv_bar_set_value(bat_bar, bat_perc, LV_ANIM_OFF); + //lv_bar_set_value(bat_bar, bat_perc, LV_ANIM_OFF); + bar_bat->set_value(bat_perc); } - if (v_led_charge != nullptr) + if (v_led_charge != nullptr && v_led_ros != nullptr) { v_led_charge->set(leds.get(LED_NUM_CHARGE)); + v_led_ros->set(leds.get(LED_NUM_S1)); } } } diff --git a/Firmware/CoverUI/YardForce/WidgetBar.hpp b/Firmware/CoverUI/YardForce/WidgetBar.hpp new file mode 100644 index 0000000..4d1e99b --- /dev/null +++ b/Firmware/CoverUI/YardForce/WidgetBar.hpp @@ -0,0 +1,102 @@ +/** + * @file WidgetBar.hpp + * @author Apehaenger (joerg@ebeling.ws) + * @brief Tiny class/wrapper for a progress-bar, which get displayed for GPS or Battery (as LVGL bar) for OpenMower https://github.com/ClemensElflein/OpenMower + * @version 0.1 + * @date 2023-09-11 + * + * @copyright Copyright (c) 2023 + */ +#ifndef __WIDGETBAR_HPP +#define __WIDGETBAR_HPP + +#include +#include +#include "LEDcontrol.h" + +namespace display +{ + class WidgetBar + { + public: + std::string bar_label; // sprintf formatted bar label like " %d %%" + + WidgetBar(const std::string &t_bar_label, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs, lv_coord_t w, lv_coord_t h) : bar_label(t_bar_label) + { + // Init bar style settings for custom (labeled) bar graph + lv_style_init(&bar_style_bg); + lv_style_set_border_color(&bar_style_bg, lv_color_hex(0xffffff)); + lv_style_set_border_width(&bar_style_bg, 2); + lv_style_set_pad_all(&bar_style_bg, 3); // To make the indicator smaller + lv_style_set_radius(&bar_style_bg, 4); + + lv_style_init(&bar_style_indic); + lv_style_set_bg_opa(&bar_style_indic, LV_OPA_COVER); + lv_style_set_bg_color(&bar_style_indic, lv_color_hex(0xffffff)); + lv_style_set_radius(&bar_style_indic, 1); + + // Draw bar + bar = lv_bar_create(lv_scr_act()); + lv_obj_set_user_data(bar, (void *)bar_label.c_str()); // Store bar label to object user data + lv_obj_remove_style_all(bar); // To have a clean start + lv_obj_add_style(bar, &bar_style_bg, 0); + lv_obj_add_style(bar, &bar_style_indic, LV_PART_INDICATOR); + + lv_obj_add_event_cb(bar, event_bar_label_cb, LV_EVENT_DRAW_PART_END, NULL); + lv_obj_set_size(bar, w, h); + lv_obj_align(bar, align, x_ofs, y_ofs); + } + + void set_value(int16_t value) + { + lv_bar_set_value(bar, value, LV_ANIM_OFF); + } + + + private: + lv_obj_t *bar; + lv_style_t bar_style_bg, bar_style_indic; + + static void event_bar_label_cb(lv_event_t *e) + { + lv_obj_draw_part_dsc_t *dsc = lv_event_get_draw_part_dsc(e); + if (dsc->part != LV_PART_INDICATOR) + return; + + lv_obj_t *obj = lv_event_get_target(e); + int32_t bar_value = lv_bar_get_value(obj); + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + + char buf[12]; + lv_snprintf(buf, sizeof(buf), (const char *)lv_obj_get_user_data(obj), bar_value); + + lv_point_t txt_size; + lv_txt_get_size(&txt_size, buf, label_dsc.font, label_dsc.letter_space, label_dsc.line_space, LV_COORD_MAX, + label_dsc.flag); + + lv_area_t txt_area; + // If the indicator is long enough put the text inside on the right + if (lv_area_get_width(dsc->draw_area) > txt_size.x + 20) + { + txt_area.x2 = dsc->draw_area->x2 - 5; + txt_area.x1 = txt_area.x2 - txt_size.x + 1; + label_dsc.color = lv_color_black(); + } + // If the indicator is still short put the text out of it on the right + else + { + txt_area.x1 = dsc->draw_area->x2 + 5; + txt_area.x2 = txt_area.x1 + txt_size.x - 1; + label_dsc.color = lv_color_white(); + } + + txt_area.y1 = (dsc->draw_area->y1 + (lv_area_get_height(dsc->draw_area) - txt_size.y) / 2) + 1; + txt_area.y2 = txt_area.y1 + txt_size.y; + + lv_draw_label(dsc->draw_ctx, &label_dsc, &txt_area, buf, NULL); + } + }; +} // namespace display + +#endif // __WIDGETBAR_HPP \ No newline at end of file diff --git a/Firmware/CoverUI/YardForce/WidgetLedSymbol.hpp b/Firmware/CoverUI/YardForce/WidgetLedSymbol.hpp index 1061cf0..19c2569 100644 --- a/Firmware/CoverUI/YardForce/WidgetLedSymbol.hpp +++ b/Firmware/CoverUI/YardForce/WidgetLedSymbol.hpp @@ -1,5 +1,5 @@ /** - * @file GuiLedSymbol.hpp + * @file WidgetLedSymbol.hpp * @author Apehaenger (joerg@ebeling.ws) * @brief Tiny class/wrapper for a virtual LED, which get displayed as symbol (LVGL label) for OpenMower https://github.com/ClemensElflein/OpenMower * @version 0.1 @@ -29,16 +29,55 @@ namespace display lv_obj_align(label, align, x_ofs, y_ofs); } - void set(LED_state state) + static void anim_blink_cb(void *var, int32_t v) { - if (state == LED_off) - lv_obj_add_flag(label, LV_OBJ_FLAG_HIDDEN); - else if (state == LED_on) + if (v) + lv_obj_clear_flag((lv_obj_t *)var, LV_OBJ_FLAG_HIDDEN); + else + lv_obj_add_flag((lv_obj_t *)var, LV_OBJ_FLAG_HIDDEN); + } + + void set(LED_state t_state) + { + if (t_state == state) + return; + + switch (t_state) + { + case LED_on: + lv_anim_del(label, (lv_anim_exec_xcb_t)anim_blink_cb); lv_obj_clear_flag(label, LV_OBJ_FLAG_HIDDEN); + break; + case LED_blink_slow: + startBlinkAnim(600); // Somehow slower than originals 500ms (because of increased blink_fast period) + break; + case LED_blink_fast: + startBlinkAnim(200); // 100ms fast blink is to quick for the cheap WYM240128K1 + break; + default: // off + lv_anim_del(label, (lv_anim_exec_xcb_t)anim_blink_cb); + lv_obj_add_flag(label, LV_OBJ_FLAG_HIDDEN); + break; + } + state = t_state; } private: lv_obj_t *label; + lv_anim_t anim; + LED_state state = LED_on; + + void startBlinkAnim(uint16_t t_period_ms) + { + lv_anim_init(&anim); + lv_anim_set_exec_cb(&anim, (lv_anim_exec_xcb_t)anim_blink_cb); + lv_anim_set_var(&anim, label); + lv_anim_set_time(&anim, t_period_ms); + lv_anim_set_repeat_delay(&anim, t_period_ms); + lv_anim_set_values(&anim, 0, 1); + lv_anim_set_repeat_count(&anim, LV_ANIM_REPEAT_INFINITE); + lv_anim_start(&anim); + } }; } // namespace display diff --git a/Firmware/CoverUI/platformio.ini b/Firmware/CoverUI/platformio.ini index 729792c..fe937ba 100644 --- a/Firmware/CoverUI/platformio.ini +++ b/Firmware/CoverUI/platformio.ini @@ -45,7 +45,7 @@ build_src_filter = - - - - - + - build_flags = -DHW_YF @@ -314,7 +314,7 @@ build_src_filter = + + + - + + + build_flags = ${env.build_flags}