#include #include #include #include #include "esp_err.h" #include "esp_log.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "lvgl.h" #include "app_settings.h" #include "audio_service.h" #include "board.h" #include "radar_service.h" #include "radick_config.h" #include "ui.h" #define AUTO_DIM_BRIGHTNESS_PERCENT 12U #define UI_LOOP_DELAY_MS 5U static const char *TAG = "radick"; static uint8_t s_user_brightness = 78U; static bool s_audio_ready; static bool s_auto_dimmed; static uint64_t s_last_activity_ms; static uint64_t app_now_ms(void) { return (uint64_t)esp_timer_get_time() / 1000U; } static void on_sound_changed(bool enabled) { if (s_audio_ready) { audio_service_set_enabled(enabled); } const esp_err_t err = app_settings_set_sound(enabled); if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { ESP_LOGW(TAG, "could not persist sound setting: %s", esp_err_to_name(err)); } } static void on_brightness_changed(uint8_t percent, bool persist) { s_user_brightness = percent; s_auto_dimmed = false; s_last_activity_ms = app_now_ms(); board_set_brightness(percent); if (persist) { const esp_err_t err = app_settings_set_brightness(percent); if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { ESP_LOGW(TAG, "could not persist brightness: %s", esp_err_to_name(err)); } } } static void fade_in_backlight(uint8_t target_percent) { for (uint8_t brightness = 0U; brightness < target_percent;) { const uint8_t remaining = target_percent - brightness; brightness += remaining > 4U ? 4U : remaining; board_set_brightness(brightness); vTaskDelay(pdMS_TO_TICKS(6)); } } static float nearest_distance_m(const radar_snapshot_t *snapshot) { float nearest_mm = INFINITY; for (size_t i = 0; i < RADAR_SERVICE_MAX_TARGETS; ++i) { if (!snapshot->targets[i].valid) { continue; } const float distance_mm = hypotf(snapshot->targets[i].x_mm, snapshot->targets[i].y_mm); if (distance_mm < nearest_mm) { nearest_mm = distance_mm; } } return isfinite(nearest_mm) ? nearest_mm / 1000.0F : NAN; } static void update_auto_dim(bool target_present) { static uint32_t previous_touch_ms; const uint64_t current_ms = app_now_ms(); const uint32_t touch_ms = board_last_touch_ms(); if (target_present || touch_ms != previous_touch_ms) { s_last_activity_ms = current_ms; previous_touch_ms = touch_ms; if (s_auto_dimmed) { board_set_brightness(s_user_brightness); s_auto_dimmed = false; } return; } if (!s_auto_dimmed && current_ms - s_last_activity_ms >= RADICK_AUTO_DIM_MS) { const uint8_t dimmed = s_user_brightness < AUTO_DIM_BRIGHTNESS_PERCENT ? s_user_brightness : AUTO_DIM_BRIGHTNESS_PERCENT; board_set_brightness(dimmed); s_auto_dimmed = true; } } void app_main(void) { app_settings_t settings; const esp_err_t settings_err = app_settings_init(&settings); if (settings_err != ESP_OK) { ESP_LOGW(TAG, "using default settings: %s", esp_err_to_name(settings_err)); } s_user_brightness = settings.brightness_percent; s_last_activity_ms = app_now_ms(); ESP_ERROR_CHECK(board_init()); const esp_err_t audio_err = audio_service_init(); s_audio_ready = audio_err == ESP_OK; if (s_audio_ready) { audio_service_set_enabled(settings.sound_enabled); } else { ESP_LOGW(TAG, "audio unavailable: %s", esp_err_to_name(audio_err)); } ESP_ERROR_CHECK(radar_service_init()); const ui_config_t ui_config = { .sound_enabled = settings.sound_enabled, .touch_available = board_touch_available(), .brightness_percent = settings.brightness_percent, .sound_changed = on_sound_changed, .brightness_changed = on_brightness_changed, }; ui_init(&ui_config); radar_snapshot_t snapshot; radar_service_get_snapshot(&snapshot); ui_update(&snapshot); (void)lv_timer_handler(); fade_in_backlight(s_user_brightness); uint64_t next_ui_update_ms = 0U; for (;;) { const uint64_t current_ms = app_now_ms(); if (current_ms >= next_ui_update_ms) { radar_service_get_snapshot(&snapshot); ui_update(&snapshot); const float nearest_m = nearest_distance_m(&snapshot); if (s_audio_ready) { if (isfinite(nearest_m)) { audio_service_set_nearest_distance(nearest_m); } else { audio_service_clear_target(); } } update_auto_dim(snapshot.target_count > 0U); next_ui_update_ms = current_ms + RADICK_UI_REFRESH_MS; } (void)lv_timer_handler(); vTaskDelay(pdMS_TO_TICKS(UI_LOOP_DELAY_MS)); } }