173 lines
5.0 KiB
C
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));
|
|
}
|
|
}
|