Skip to content

Commit

Permalink
Restructure into LedSymbol & Bar widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
Apehaenger committed Sep 11, 2023
1 parent 2fff601 commit d8e2654
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 104 deletions.
2 changes: 1 addition & 1 deletion Firmware/CoverUI/YardForce/LEDcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
111 changes: 15 additions & 96 deletions Firmware/CoverUI/YardForce/WYM240128K1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <lvgl.h>
#include "LEDcontrol.h"
#include "WidgetLedSymbol.hpp"
#include "WidgetBar.hpp"

// C images
LV_IMG_DECLARE(OM_Logo_Inv_120x54x1);
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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));
}
}
}
Expand Down
102 changes: 102 additions & 0 deletions Firmware/CoverUI/YardForce/WidgetBar.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* @file WidgetBar.hpp
* @author Apehaenger ([email protected])
* @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 <Arduino.h>
#include <lvgl.h>
#include "LEDcontrol.h"

namespace display
{
class WidgetBar
{
public:
std::string bar_label; // sprintf formatted bar label like "<UNICODE SYMBOL> %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
49 changes: 44 additions & 5 deletions Firmware/CoverUI/YardForce/WidgetLedSymbol.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @file GuiLedSymbol.hpp
* @file WidgetLedSymbol.hpp
* @author Apehaenger ([email protected])
* @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
Expand Down Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions Firmware/CoverUI/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ build_src_filter =
-<YardForce/assets/*>
-<YardForce/UC1698.*>
-<YardForce/WYM240128K1.*>
-<YardForce/WidgetLedSymbol.*>
-<YardForce/Widget*>

build_flags =
-DHW_YF
Expand Down Expand Up @@ -314,7 +314,7 @@ build_src_filter =
+<YardForce/assets/*>
+<YardForce/UC1698.*>
+<YardForce/WYM240128K1.*>
+<YardForce/WidgetLedSymbol.*>
+<YardForce/Widget*>

build_flags =
${env.build_flags}
Expand Down

0 comments on commit d8e2654

Please sign in to comment.