mirror of
https://github.com/m5stack/StackChan.git
synced 2026-04-27 11:02:40 +00:00
0cb413697b
Co-authored-by: jyy <jiangyeying@m5stack.com>
188 lines
7.4 KiB
C
188 lines
7.4 KiB
C
#include "ui_running_screen.h"
|
|
#include "../lvgl_port.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
|
|
lv_obj_t* running_screen = NULL;
|
|
lv_obj_t* joystick_dot = NULL;
|
|
lv_obj_t* joystick_area = NULL;
|
|
lv_obj_t* battery_label = NULL;
|
|
lv_obj_t* channel_info_label = NULL;
|
|
lv_obj_t* id_info_label = NULL;
|
|
|
|
/**
|
|
* @brief Create the running screen UI with joystick visualization and status information
|
|
* @note This function creates a standalone screen with multiple UI elements:
|
|
* - Title label at the top
|
|
* - Joystick visualization area with crosshair
|
|
* - Red dot representing joystick position
|
|
* - Battery level display
|
|
* - Channel information display
|
|
* - Device ID information display
|
|
* @details The function creates a 115x115 pixel joystick area with crosshair lines
|
|
* and a red circular dot that represents the current joystick position
|
|
* @warning This function should only be called once per application run to avoid memory leaks
|
|
*/
|
|
void create_running_screen()
|
|
{
|
|
while (!lvgl_port_lock()) {
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
}
|
|
lv_disp_t* disp = lv_disp_get_default();
|
|
if (disp == NULL) {
|
|
ESP_LOGE("UI", "No default display found!");
|
|
lvgl_port_unlock();
|
|
return;
|
|
}
|
|
|
|
if (running_screen == NULL) {
|
|
running_screen = lv_obj_create(NULL);
|
|
}
|
|
|
|
if (running_screen == NULL) {
|
|
ESP_LOGE("UI", "Failed to create running screen!");
|
|
return;
|
|
}
|
|
|
|
lv_obj_clear_flag(running_screen, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
// Create title
|
|
lv_obj_t* label = lv_label_create(running_screen);
|
|
|
|
lv_label_set_text(label, "StackChan :)");
|
|
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 10);
|
|
lv_obj_set_style_text_font(label, &lv_font_montserrat_14, 0);
|
|
|
|
// Create joystick area
|
|
joystick_area = lv_obj_create(running_screen);
|
|
lv_obj_set_size(joystick_area, 115, 115); // Reduced size
|
|
lv_obj_align(joystick_area, LV_ALIGN_TOP_MID, 0, 35);
|
|
|
|
// Set joystick area style
|
|
lv_obj_set_style_border_width(joystick_area, 2, LV_PART_MAIN);
|
|
lv_obj_set_style_border_color(joystick_area, lv_color_black(), LV_PART_MAIN);
|
|
lv_obj_set_style_bg_color(joystick_area, lv_color_white(), LV_PART_MAIN);
|
|
lv_obj_set_style_pad_all(joystick_area, 0, LV_PART_MAIN);
|
|
lv_obj_clear_flag(joystick_area, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
// Add horizontal crosshair line
|
|
lv_obj_t* cross_line_h = lv_line_create(joystick_area);
|
|
static lv_point_t points_h[2] = {{0, 57}, {115, 57}}; // Horizontal center line
|
|
lv_line_set_points(cross_line_h, points_h, 2);
|
|
lv_obj_set_style_line_color(cross_line_h, lv_color_make(64, 64, 64), 0);
|
|
lv_obj_set_style_line_width(cross_line_h, 1, 0);
|
|
|
|
// Add vertical crosshair line
|
|
lv_obj_t* cross_line_v = lv_line_create(joystick_area);
|
|
static lv_point_t points_v[2] = {{56, 0}, {56, 115}}; // Vertical center line
|
|
lv_line_set_points(cross_line_v, points_v, 2);
|
|
lv_obj_set_style_line_color(cross_line_v, lv_color_make(64, 64, 64), 0);
|
|
lv_obj_set_style_line_width(cross_line_v, 1, 0);
|
|
|
|
// Create joystick dot
|
|
joystick_dot = lv_obj_create(joystick_area);
|
|
lv_obj_set_size(joystick_dot, 10, 10); // Dot size
|
|
lv_obj_set_style_radius(joystick_dot, LV_RADIUS_CIRCLE, LV_PART_MAIN); // Set to circle
|
|
lv_obj_set_style_bg_color(joystick_dot, lv_palette_main(LV_PALETTE_RED), LV_PART_MAIN);
|
|
lv_obj_set_style_border_width(joystick_dot, 0, LV_PART_MAIN);
|
|
lv_obj_align(joystick_dot, LV_ALIGN_CENTER, 0, 0);
|
|
|
|
// Create battery level display
|
|
battery_label = lv_label_create(running_screen);
|
|
lv_label_set_text(battery_label, "Bat: 100%%");
|
|
lv_obj_align(battery_label, LV_ALIGN_TOP_LEFT, 10, 160);
|
|
lv_obj_set_style_text_font(battery_label, &lv_font_montserrat_14, 0);
|
|
|
|
// Create Channel information display
|
|
channel_info_label = lv_label_create(running_screen);
|
|
lv_label_set_text(channel_info_label, "Channel: 1");
|
|
lv_obj_align(channel_info_label, LV_ALIGN_TOP_LEFT, 10, 180);
|
|
lv_obj_set_style_text_font(channel_info_label, &lv_font_montserrat_14, 0);
|
|
|
|
// Create ID information display
|
|
id_info_label = lv_label_create(running_screen);
|
|
lv_label_set_text(id_info_label, "Receiver ID: \n0(broadcast)");
|
|
lv_obj_align(id_info_label, LV_ALIGN_TOP_LEFT, 10, 200);
|
|
lv_obj_set_style_text_font(id_info_label, &lv_font_montserrat_14, 0);
|
|
|
|
lvgl_port_unlock();
|
|
}
|
|
|
|
/**
|
|
* @brief Update the running screen UI with current joystick values and status information
|
|
* @param joyX X-axis value from joystick (raw value to be mapped to screen coordinates)
|
|
* @param joyY Y-axis value from joystick (raw value to be mapped to screen coordinates)
|
|
* @param channel Current WiFi channel being used
|
|
* @param id Device ID for communication
|
|
* @param bat Battery level percentage (0-100)
|
|
* @note This function maps joystick values to the 115x115 pixel joystick area
|
|
* and applies deadzone correction to center the dot when joystick is near center position
|
|
* @details
|
|
* 1. Maps raw joystick values to screen coordinates within the joystick area
|
|
* 2. Applies deadzone correction to keep dot centered when joystick is in neutral position
|
|
* 3. Clamps values to prevent the dot from going outside the joystick area
|
|
* 4. Updates the position of the joystick dot
|
|
* 5. Updates battery level, channel and ID information labels
|
|
*/
|
|
void update_running_screen(int16_t joyX, int16_t joyY, uint8_t channel, uint8_t id, uint8_t bat)
|
|
{
|
|
// Map joystick values to 115x115 area (using your mapping approach)
|
|
int16_t x_pos = map(joyX, X_MIN, X_MAX, 5, 110); // Leave 5px margin
|
|
int16_t y_pos = map(joyY, Y_MIN, Y_MAX, 110, 5); // Y-axis inverted
|
|
|
|
// Apply deadzone
|
|
int16_t x_center = map(X_CENTER, X_MIN, X_MAX, 5, 110);
|
|
int16_t y_center = map(Y_CENTER, Y_MIN, Y_MAX, 110, 5);
|
|
|
|
if (abs(joyX - X_CENTER) < DEAD_ZONE) {
|
|
x_pos = x_center;
|
|
}
|
|
if (abs(joyY - Y_CENTER) < DEAD_ZONE) {
|
|
y_pos = y_center;
|
|
}
|
|
|
|
// Limit range
|
|
x_pos = fmax(5, fmin(x_pos, 110));
|
|
y_pos = fmax(5, fmin(y_pos, 110));
|
|
|
|
while (!lvgl_port_lock()) {
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
}
|
|
// Update joystick dot position (relative to joystick_area center)
|
|
lv_obj_align(joystick_dot, LV_ALIGN_TOP_LEFT, x_pos - 5, y_pos - 5);
|
|
|
|
// Update battery level
|
|
lv_label_set_text_fmt(battery_label, "Bat: %d%%", bat);
|
|
|
|
// Update Channel and ID display
|
|
lv_label_set_text_fmt(channel_info_label, "Channel: %u", channel);
|
|
if (id == 0) {
|
|
lv_label_set_text(id_info_label, "Receiver ID:\n 0(broadcast)");
|
|
} else {
|
|
lv_label_set_text_fmt(id_info_label, "Receiver ID: %u", id);
|
|
}
|
|
lvgl_port_unlock();
|
|
}
|
|
|
|
/**
|
|
* @brief Reset all UI object pointers to NULL to prepare for screen destruction
|
|
* @note This function does not actually destroy the UI objects, but resets the pointers
|
|
* that reference them, allowing the UI to be recreated or switched
|
|
* @warning The actual UI objects should be destroyed separately using LVGL's object destruction functions
|
|
*/
|
|
void ui_running_screen_destory()
|
|
{
|
|
while (!lvgl_port_lock()) {
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
}
|
|
if (running_screen != NULL) {
|
|
lv_obj_del(running_screen);
|
|
running_screen = NULL;
|
|
}
|
|
lvgl_port_unlock();
|
|
joystick_dot = NULL;
|
|
joystick_area = NULL;
|
|
battery_label = NULL;
|
|
channel_info_label = NULL;
|
|
id_info_label = NULL;
|
|
} |