Files
tronone-h7-scaffold/User_Code/module/software/prts/prts.c
2026-07-20 21:59:16 +08:00

321 lines
10 KiB
C

#include "prts.h"
#include "lvgl.h"
#include "prts_lvgl_port.h"
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#define PRTS_CARD_BG_COLOR 0x0E1B24
#define PRTS_VALUE_BG_COLOR 0x132530
#define PRTS_VALUE_PANEL_WIDTH 228
#define PRTS_VALUE_PANEL_HEIGHT 34
#define PRTS_VALUE_LABEL_WIDTH 210
#define PRTS_VALUE_LABEL_HEIGHT 28
#define PRTS_VALUE_LABEL_X 12
#define PRTS_VALUE_LABEL_Y 4
#define PRTS_VALUE_ACCENT_WIDTH 4
static bool prts_initialized = false;
static bool prts_lvgl_initialized = false;
static lv_obj_t *prts_temperature_panel = NULL;
static lv_obj_t *prts_temperature_label = NULL;
static lv_obj_t *prts_temperature_accent = NULL;
static lv_obj_t *prts_mode_panel = NULL;
static lv_obj_t *prts_mode_label = NULL;
static lv_obj_t *prts_mode_accent = NULL;
static lv_obj_t *prts_status_bar = NULL;
static int16_t prts_last_temperature_tenths = INT16_MIN;
static RobotMode_t prts_last_mode = (RobotMode_t) 0xFF;
static int16_t prts_temperature_to_tenths(float temperature_c)
{
return (int16_t) ((temperature_c * 10.0f) + (temperature_c >= 0.0f ? 0.5f : -0.5f));
}
static void prts_format_temperature(char *buf, size_t len, int16_t temperature_tenths)
{
uint16_t abs_temp;
uint16_t integer;
uint8_t decimal;
if (buf == NULL || len == 0U)
{
return;
}
if (temperature_tenths < 0)
{
abs_temp = (uint16_t) (-temperature_tenths);
integer = abs_temp / 10U;
decimal = (uint8_t) (abs_temp % 10U);
(void) snprintf(buf, len, "-%u.%u C", (unsigned int) integer, (unsigned int) decimal);
}
else
{
abs_temp = (uint16_t) temperature_tenths;
integer = abs_temp / 10U;
decimal = (uint8_t) (abs_temp % 10U);
(void) snprintf(buf, len, "%u.%u C", (unsigned int) integer, (unsigned int) decimal);
}
}
static const char *prts_robot_mode_text(RobotMode_t mode)
{
switch (mode)
{
case NORMAL_MODE:
return "NORMAL";
case SYS_ERROR_OCCURRED:
return "ERROR";
case REMOTE_NOT_CONNECTED:
return "REMOTE OFF";
case REMOTE_CONNECTED:
return "REMOTE ON";
case AUTO_SHOOTING_MODE:
return "AUTO SHOOT";
case IMU_CALIBERATION_MODE:
return "IMU CAL";
default:
return "UNKNOWN";
}
}
static lv_color_t prts_robot_mode_color(RobotMode_t mode)
{
switch (mode)
{
case NORMAL_MODE:
return lv_color_hex(0x25D366);
case SYS_ERROR_OCCURRED:
case REMOTE_NOT_CONNECTED:
return lv_color_hex(0xFF4D4F);
case REMOTE_CONNECTED:
return lv_color_hex(0xFFD666);
case AUTO_SHOOTING_MODE:
return lv_color_hex(0x40C4FF);
case IMU_CALIBERATION_MODE:
return lv_color_hex(0xC678FF);
default:
return lv_color_hex(0xD9D9D9);
}
}
static lv_color_t prts_robot_mode_text_color(RobotMode_t mode)
{
switch (mode)
{
case SYS_ERROR_OCCURRED:
case REMOTE_NOT_CONNECTED:
return lv_color_hex(0xFFE2E2);
case REMOTE_CONNECTED:
return lv_color_hex(0xFFF3C4);
default:
return lv_color_hex(0xFFFFFF);
}
}
static void prts_style_label(lv_obj_t *label, lv_color_t color)
{
lv_obj_set_style_bg_opa(label, LV_OPA_TRANSP, 0);
lv_obj_set_style_text_color(label, color, 0);
}
static lv_obj_t *prts_create_value_panel(lv_obj_t *parent, int32_t x, int32_t y)
{
lv_obj_t *panel = lv_obj_create(parent);
lv_obj_remove_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_pos(panel, x, y);
lv_obj_set_size(panel, PRTS_VALUE_PANEL_WIDTH, PRTS_VALUE_PANEL_HEIGHT);
lv_obj_set_style_radius(panel, 0, 0);
lv_obj_set_style_border_width(panel, 0, 0);
lv_obj_set_style_pad_all(panel, 0, 0);
lv_obj_set_style_bg_color(panel, lv_color_hex(PRTS_VALUE_BG_COLOR), 0);
lv_obj_set_style_bg_opa(panel, LV_OPA_COVER, 0);
return panel;
}
static lv_obj_t *prts_create_value_accent(lv_obj_t *parent, lv_color_t color)
{
lv_obj_t *accent = lv_obj_create(parent);
lv_obj_remove_flag(accent, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_pos(accent, 0, 0);
lv_obj_set_size(accent, PRTS_VALUE_ACCENT_WIDTH, PRTS_VALUE_PANEL_HEIGHT);
lv_obj_set_style_radius(accent, 0, 0);
lv_obj_set_style_border_width(accent, 0, 0);
lv_obj_set_style_pad_all(accent, 0, 0);
lv_obj_set_style_bg_color(accent, color, 0);
lv_obj_set_style_bg_opa(accent, LV_OPA_COVER, 0);
return accent;
}
static void prts_style_value_label(lv_obj_t *label, lv_color_t color)
{
lv_label_set_long_mode(label, LV_LABEL_LONG_MODE_CLIP);
lv_obj_set_size(label, PRTS_VALUE_LABEL_WIDTH, PRTS_VALUE_LABEL_HEIGHT);
lv_obj_set_style_radius(label, 0, 0);
lv_obj_set_style_border_width(label, 0, 0);
lv_obj_set_style_pad_all(label, 0, 0);
lv_obj_set_style_bg_opa(label, LV_OPA_TRANSP, 0);
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_LEFT, 0);
lv_obj_set_style_text_color(label, color, 0);
}
static lv_obj_t *prts_create_card(lv_obj_t *parent, int32_t x, int32_t y, int32_t w, int32_t h)
{
lv_obj_t *card = lv_obj_create(parent);
lv_obj_remove_flag(card, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_pos(card, x, y);
lv_obj_set_size(card, w, h);
lv_obj_set_style_radius(card, 4, 0);
lv_obj_set_style_border_width(card, 1, 0);
lv_obj_set_style_border_color(card, lv_color_hex(0x27475A), 0);
lv_obj_set_style_bg_color(card, lv_color_hex(PRTS_CARD_BG_COLOR), 0);
lv_obj_set_style_bg_opa(card, LV_OPA_COVER, 0);
lv_obj_set_style_pad_all(card, 10, 0);
return card;
}
static void prts_create_status_screen(void)
{
lv_obj_t *screen = lv_obj_create(NULL);
lv_obj_t *title;
lv_obj_t *subtitle;
lv_obj_t *temp_card;
lv_obj_t *mode_card;
lv_obj_t *caption;
lv_obj_remove_flag(screen, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_style_bg_color(screen, lv_color_hex(0x071016), 0);
lv_obj_set_style_bg_opa(screen, LV_OPA_COVER, 0);
lv_obj_set_style_pad_all(screen, 0, 0);
title = lv_label_create(screen);
lv_label_set_text(title, "PRTS");
prts_style_label(title, lv_color_hex(0x6EE7F9));
lv_obj_set_pos(title, 16, 12);
subtitle = lv_label_create(screen);
lv_label_set_text(subtitle, "PORTABLE RM TELEMETRY");
prts_style_label(subtitle, lv_color_hex(0xB5C8D5));
lv_obj_set_pos(subtitle, 16, 34);
prts_status_bar = lv_obj_create(screen);
lv_obj_remove_flag(prts_status_bar, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_pos(prts_status_bar, 190, 16);
lv_obj_set_size(prts_status_bar, 74, 8);
lv_obj_set_style_radius(prts_status_bar, 2, 0);
lv_obj_set_style_border_width(prts_status_bar, 0, 0);
lv_obj_set_style_bg_color(prts_status_bar, lv_color_hex(0xD9D9D9), 0);
lv_obj_set_style_bg_opa(prts_status_bar, LV_OPA_COVER, 0);
temp_card = prts_create_card(screen, 16, 62, 248, 68);
caption = lv_label_create(temp_card);
lv_label_set_text(caption, "TEMPERATURE");
prts_style_label(caption, lv_color_hex(0xFFD666));
lv_obj_set_pos(caption, 0, 0);
prts_temperature_panel = prts_create_value_panel(temp_card, 0, 25);
prts_temperature_accent = prts_create_value_accent(prts_temperature_panel, lv_color_hex(0x40C4FF));
prts_temperature_label = lv_label_create(prts_temperature_panel);
lv_label_set_text(prts_temperature_label, "--.- C");
prts_style_value_label(prts_temperature_label, lv_color_hex(0xFFFFFF));
lv_obj_set_pos(prts_temperature_label, PRTS_VALUE_LABEL_X, PRTS_VALUE_LABEL_Y);
mode_card = prts_create_card(screen, 16, 146, 248, 68);
caption = lv_label_create(mode_card);
lv_label_set_text(caption, "CURRENT STATE");
prts_style_label(caption, lv_color_hex(0xFFD666));
lv_obj_set_pos(caption, 0, 0);
prts_mode_panel = prts_create_value_panel(mode_card, 0, 25);
prts_mode_accent = prts_create_value_accent(prts_mode_panel, lv_color_hex(0xD9D9D9));
prts_mode_label = lv_label_create(prts_mode_panel);
lv_label_set_text(prts_mode_label, "UNKNOWN");
prts_style_value_label(prts_mode_label, lv_color_hex(0xD9D9D9));
lv_obj_set_pos(prts_mode_label, PRTS_VALUE_LABEL_X, PRTS_VALUE_LABEL_Y);
lv_screen_load(screen);
}
bool PRTS_Init(void)
{
if (prts_initialized)
{
return true;
}
if (!prts_lvgl_initialized)
{
lv_init();
prts_lvgl_initialized = true;
}
if (!PRTS_LVGLPortInit())
{
return false;
}
prts_create_status_screen();
prts_initialized = true;
return true;
}
void PRTS_UpdateStatus(float temperature_c, RobotMode_t mode)
{
int16_t temperature_tenths;
lv_color_t mode_color;
char temperature_text[16];
if (!prts_initialized)
{
return;
}
temperature_tenths = prts_temperature_to_tenths(temperature_c);
if (temperature_tenths != prts_last_temperature_tenths)
{
bool temperature_warning = temperature_tenths >= 550;
prts_format_temperature(temperature_text, sizeof(temperature_text), temperature_tenths);
lv_obj_invalidate(prts_temperature_panel);
lv_label_set_text(prts_temperature_label, temperature_text);
lv_obj_set_style_bg_color(prts_temperature_accent,
temperature_warning ? lv_color_hex(0xFF4D4F) : lv_color_hex(0x40C4FF),
0);
lv_obj_set_style_text_color(prts_temperature_label,
temperature_warning ? lv_color_hex(0xFFE2E2) : lv_color_hex(0xFFFFFF),
0);
lv_obj_invalidate(prts_temperature_panel);
prts_last_temperature_tenths = temperature_tenths;
}
if (mode != prts_last_mode)
{
mode_color = prts_robot_mode_color(mode);
lv_obj_invalidate(prts_mode_panel);
lv_label_set_text(prts_mode_label, prts_robot_mode_text(mode));
lv_obj_set_style_text_color(prts_mode_label, prts_robot_mode_text_color(mode), 0);
lv_obj_set_style_bg_color(prts_mode_accent, mode_color, 0);
lv_obj_set_style_bg_color(prts_status_bar, mode_color, 0);
lv_obj_invalidate(prts_mode_panel);
prts_last_mode = mode;
}
}
uint32_t PRTS_Task(void)
{
uint32_t next_ms;
if (!prts_initialized)
{
return 10U;
}
next_ms = lv_timer_handler();
if (next_ms == 0U || next_ms > 10U)
{
next_ms = 10U;
}
return next_ms;
}