Files
Radick/main/app_main.c
dami b473ed4369
Some checks failed
build / host-tests (push) Has been cancelled
build / esp-idf (push) Has been cancelled
Implement native ESP-IDF radar firmware
2026-07-21 07:47:02 +00:00

173 lines
5.0 KiB
C

#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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));
}
}