DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
ld2410.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file ld2410.h
6 * @brief HLK-LD2410 24 GHz mmWave presence / motion radar codec (DETWS_ENABLE_LD2410).
7 *
8 * The LD2410 streams a framed serial report at 256000 baud: header `F4 F3 F2 F1`, a
9 * little-endian intra-frame length, the payload, and footer `F8 F7 F6 F5`. The payload carries
10 * the target state (none / moving / stationary / both), the moving and stationary target
11 * distance (cm) and energy (0-100), the overall detection distance, and - in "engineering
12 * mode" - the per-gate energy of all nine range gates. Configuration is a second frame kind
13 * (header `FD FC FB FA`, footer `04 03 02 01`) carrying a 2-byte command word.
14 *
15 * This codec is pure and host-tested: ::ld2410_parse_report decodes one report frame, and
16 * ::Ld2410Stream reassembles frames byte-by-byte from a UART with resync on noise (no heap,
17 * fixed buffer). The command encoders build the config frames. On an ESP32 the binding pumps a
18 * `HardwareSerial` and keeps the latest report; only that read/write touches hardware.
19 *
20 * A cheap solder-and-bench-test breakout: wire it to a UART, wave a hand, watch presence.
21 *
22 * @author Douglas Quigg (dstroy0)
23 * @date 2026
24 */
25
26#ifndef DETERMINISTICESPASYNCWEBSERVER_LD2410_H
27#define DETERMINISTICESPASYNCWEBSERVER_LD2410_H
28
29#include <stddef.h>
30#include <stdint.h>
31
32/** @brief Range gates the LD2410 reports energy for in engineering mode (gate 0..8). */
33#define LD2410_MAX_GATES 9
34
35/** @brief Largest assembled frame: header(4) + len(2) + payload(<=60) + footer(4), rounded up. */
36#define LD2410_FRAME_MAX 72
37
38/** @brief Target presence state (report payload byte 2). */
40{
41 static constexpr uint8_t LD2410_STATE_NONE = 0x00; ///< no target
42 static constexpr uint8_t LD2410_STATE_MOVING = 0x01; ///< moving target only
43 static constexpr uint8_t LD2410_STATE_STATIC = 0x02; ///< stationary target only
44 static constexpr uint8_t LD2410_STATE_BOTH = 0x03; ///< both a moving and a stationary target
45};
46
47/** @brief A decoded LD2410 target report. Engineering fields are 0 unless @ref engineering. */
49{
50 uint8_t engineering; ///< 1 if this was an engineering-mode frame (per-gate energies valid)
51 uint8_t state; ///< one of LD2410_STATE_*
52 uint16_t moving_cm; ///< moving target distance (cm)
53 uint8_t moving_energy; ///< moving target energy (0-100)
54 uint16_t static_cm; ///< stationary target distance (cm)
55 uint8_t static_energy; ///< stationary target energy (0-100)
56 uint16_t detect_cm; ///< overall detection distance (cm)
57 // Engineering mode only:
58 uint8_t max_moving_gate; ///< highest configured moving gate
59 uint8_t max_static_gate; ///< highest configured stationary gate
60 uint8_t moving_gate_energy[LD2410_MAX_GATES]; ///< per-gate moving energy (0-100)
61 uint8_t static_gate_energy[LD2410_MAX_GATES]; ///< per-gate stationary energy (0-100)
62 uint8_t light; ///< photosensor level (0-255)
63 uint8_t out_pin; ///< OUT pin level (0/1)
64};
65
66/**
67 * @brief Decode one whole LD2410 report frame (header `F4 F3 F2 F1` .. footer `F8 F7 F6 F5`).
68 * Pure - no I/O. Validates the header/footer, the intra-frame length, the data-type byte
69 * (0x02 basic / 0x01 engineering), the `0xAA` head marker and the `0x55` tail.
70 * @return true on a valid frame; false on any mismatch or a short buffer.
71 */
72bool ld2410_parse_report(const uint8_t *frame, size_t len, Ld2410Report *out);
73
74/** @brief Byte-by-byte report-frame reassembler (fixed buffer, resyncs on noise). */
76{
77 uint8_t buf[LD2410_FRAME_MAX]; ///< frame under construction
78 uint16_t pos; ///< bytes collected so far
79 uint16_t total; ///< expected full-frame length (known after the length field)
80 uint8_t hdr_match; ///< header bytes matched while syncing (phase = pos<4)
81 uint8_t phase; ///< 0 sync, 1 length, 2 body
82};
83
84/** @brief Reset a stream to the syncing state. */
86
87/**
88 * @brief Feed one received byte. When it completes a valid report frame, fills @p out and
89 * returns true; otherwise returns false (still syncing / mid-frame / bad frame - it resyncs).
90 */
91bool ld2410_stream_push(Ld2410Stream *s, uint8_t byte, Ld2410Report *out);
92
93/** @brief true if @p r shows any target (moving or stationary). */
95
96/** @brief Best available target distance (cm): the moving distance if moving, else stationary. */
98
99// --- Config-command encoders (build a full `FD FC FB FA` .. `04 03 02 01` frame) -------------
100// Each returns the frame length written, or 0 if @p cap is too small. Config commands must be
101// bracketed by enable/end; engineering + restart take effect inside that bracket.
102
103/** @brief "Enable configuration" (word 0x00FF, value 0x0001). */
104size_t ld2410_cmd_config_enable(uint8_t *buf, size_t cap);
105/** @brief "End configuration" (word 0x00FE). */
106size_t ld2410_cmd_config_end(uint8_t *buf, size_t cap);
107/** @brief Enable (0x0062) or disable (0x0063) engineering mode. */
108size_t ld2410_cmd_engineering(uint8_t *buf, size_t cap, bool on);
109/** @brief Restart the module (word 0x00A3). */
110size_t ld2410_cmd_restart(uint8_t *buf, size_t cap);
111
112// --- ESP32 binding (Serial pump; no-ops on a host build) -------------------------------------
113
114/** @brief Open UART2 at DETWS_LD2410_BAUD on @p rx_pin / @p tx_pin. @return true on ESP32. */
115bool ld2410_begin(int rx_pin, int tx_pin);
116
117/** @brief Pump the UART through the stream. @return true if a fresh report was decoded. */
119
120/** @brief The most recently decoded report, or nullptr before the first one arrives. */
122
123/** @brief Enable/disable engineering mode (brackets the command with enable/end). */
125
126/** @brief Restart the module (brackets the command with enable/end). */
128
129#endif // DETERMINISTICESPASYNCWEBSERVER_LD2410_H
bool ld2410_present(const Ld2410Report *r)
true if r shows any target (moving or stationary).
size_t ld2410_cmd_restart(uint8_t *buf, size_t cap)
Restart the module (word 0x00A3).
const Ld2410Report * ld2410_last()
The most recently decoded report, or nullptr before the first one arrives.
bool ld2410_restart()
Restart the module (brackets the command with enable/end).
size_t ld2410_cmd_engineering(uint8_t *buf, size_t cap, bool on)
Enable (0x0062) or disable (0x0063) engineering mode.
uint16_t ld2410_distance_cm(const Ld2410Report *r)
Best available target distance (cm): the moving distance if moving, else stationary.
bool ld2410_stream_push(Ld2410Stream *s, uint8_t byte, Ld2410Report *out)
Feed one received byte. When it completes a valid report frame, fills out and returns true; otherwise...
bool ld2410_parse_report(const uint8_t *frame, size_t len, Ld2410Report *out)
Decode one whole LD2410 report frame (header F4 F3 F2 F1 .. footer F8 F7 F6 F5). Pure - no I/O....
#define LD2410_MAX_GATES
Range gates the LD2410 reports energy for in engineering mode (gate 0..8).
Definition ld2410.h:33
bool ld2410_begin(int rx_pin, int tx_pin)
Open UART2 at DETWS_LD2410_BAUD on rx_pin / tx_pin.
size_t ld2410_cmd_config_enable(uint8_t *buf, size_t cap)
"Enable configuration" (word 0x00FF, value 0x0001).
#define LD2410_FRAME_MAX
Largest assembled frame: header(4) + len(2) + payload(<=60) + footer(4), rounded up.
Definition ld2410.h:36
bool ld2410_poll()
Pump the UART through the stream.
bool ld2410_set_engineering(bool on)
Enable/disable engineering mode (brackets the command with enable/end).
size_t ld2410_cmd_config_end(uint8_t *buf, size_t cap)
"End configuration" (word 0x00FE).
void ld2410_stream_reset(Ld2410Stream *s)
Reset a stream to the syncing state.
A decoded LD2410 target report. Engineering fields are 0 unless engineering.
Definition ld2410.h:49
uint16_t detect_cm
overall detection distance (cm)
Definition ld2410.h:56
uint8_t static_gate_energy[LD2410_MAX_GATES]
per-gate stationary energy (0-100)
Definition ld2410.h:61
uint16_t moving_cm
moving target distance (cm)
Definition ld2410.h:52
uint8_t out_pin
OUT pin level (0/1)
Definition ld2410.h:63
uint8_t max_static_gate
highest configured stationary gate
Definition ld2410.h:59
uint8_t state
one of LD2410_STATE_*
Definition ld2410.h:51
uint8_t static_energy
stationary target energy (0-100)
Definition ld2410.h:55
uint8_t engineering
1 if this was an engineering-mode frame (per-gate energies valid)
Definition ld2410.h:50
uint8_t moving_gate_energy[LD2410_MAX_GATES]
per-gate moving energy (0-100)
Definition ld2410.h:60
uint8_t moving_energy
moving target energy (0-100)
Definition ld2410.h:53
uint8_t max_moving_gate
highest configured moving gate
Definition ld2410.h:58
uint8_t light
photosensor level (0-255)
Definition ld2410.h:62
uint16_t static_cm
stationary target distance (cm)
Definition ld2410.h:54
Target presence state (report payload byte 2).
Definition ld2410.h:40
static constexpr uint8_t LD2410_STATE_NONE
no target
Definition ld2410.h:41
static constexpr uint8_t LD2410_STATE_BOTH
both a moving and a stationary target
Definition ld2410.h:44
static constexpr uint8_t LD2410_STATE_STATIC
stationary target only
Definition ld2410.h:43
static constexpr uint8_t LD2410_STATE_MOVING
moving target only
Definition ld2410.h:42
Byte-by-byte report-frame reassembler (fixed buffer, resyncs on noise).
Definition ld2410.h:76
uint16_t pos
bytes collected so far
Definition ld2410.h:78
uint8_t hdr_match
header bytes matched while syncing (phase = pos<4)
Definition ld2410.h:80
uint16_t total
expected full-frame length (known after the length field)
Definition ld2410.h:79
uint8_t buf[LD2410_FRAME_MAX]
frame under construction
Definition ld2410.h:77
uint8_t phase
0 sync, 1 length, 2 body
Definition ld2410.h:81