#pragma once
#include <Arduino.h>
#include <Stream.h>
/* ------------------------------------------------------------------ */
/* ----------------------- Конфигурация радара ---------------------*/
/* ------------------------------------------------------------------ */
struct RadarConfig {
uint8_t uart_rx_pin;
uint8_t uart_tx_pin;
uint32_t baud_rate = 115200;
/* Хранение данных */
uint16_t presence_hold_ms = 1500; // Как долго держать флаг «presence» после последнего сигнала
uint16_t stale_after_ms = 2000; // Если не пришло ни одной строки – считаем offline
/* Фильтры */
uint8_t median_window_size = 5;
uint8_t max_zone_step_per_sample = 4;
/* EMA‑сглаживание (α) */
float distance_ema_alpha = 0.35f;
float speed_ema_alpha = 0.25f;
/* Диапазон зон, которые считаем «действительными» */
uint16_t min_valid_zone = 1;
uint16_t max_valid_zone = 200;
/* Перевод зоны в метры (параметры калибровки) */
float zone_to_meter_k = 0.7f; // slope
float zone_to_meter_b = 0.0f; // intercept
/* Шкала активности: скорость, с которой считается «активным» */
float activity_min_speed_m_s = 0.03f;
float activity_max_speed_m_s = 1.20f;
bool enable_debug_unknown_lines = false;
};
/* ------------------------------------------------------------------ */
/* -------------------------- Состояние радара ---------------------*/
/* ------------------------------------------------------------------ */
struct RadarState {
bool online = false; // Приём данных
bool presence = false; // Присутствует человек
uint8_t activity_score = 0; // Средняя активность за минуту (0…10)
uint8_t activity_score_current = 0; // Активность в момент запроса
const char *activity_score_dynamics = "constant";
float distance_m = NAN;
};
/* ------------------------------------------------------------------ */
/* ------------------------ Основной класс радара -------------------*/
/* ------------------------------------------------------------------ */
class Ld2420Radar {
public:
/* Инициализация */
void begin(Stream &uart, const RadarConfig &cfg);
/* Обновление состояния – вызывать каждый цикл (или в таймере) */
void update();
/* Получить JSON‑строку текущего состояния */
String get_state_json() const;
private:
/* Внутренние данные */
Stream * _uart = nullptr;
RadarConfig _cfg;
RadarState _state{};
/* Тайминг */
uint32_t _last_line_ms = 0; // Когда пришла последняя строка
uint32_t _presence_start_ms = 0; // Когда появился первый сигнал
/* Буфер для чтения строки */
static const size_t LINE_BUF_SIZE = 64;
char _line_buf[LINE_BUF_SIZE];
size_t _line_pos = 0;
/* Хранение последних N оценок активности (N=10) */
static const uint8_t ACTIVITY_HISTORY = 10;
uint8_t _activity_hist[ACTIVITY_HISTORY] = {0};
uint8_t _hist_idx = 0;
bool _hist_filled = false;
/* Публичные вспомогательные функции (для тестов) */
void _parse_line(const char *line, size_t len);
void _update_online_state();
void _update_presence_state(uint16_t zone);
void _update_distance_speed(float distance_m, float speed_m_s);
void _calc_activity_score_current();
void _calc_activity_score_average();
void _determine_dynamics();
/* Утилиты */
static bool _is_hex_digit(char c) {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F');
}
};