18#if DETWS_ENABLE_LD2410
24const uint8_t HDR[4] = {0xF4, 0xF3, 0xF2, 0xF1};
25const uint8_t FTR[4] = {0xF8, 0xF7, 0xF6, 0xF5};
26const uint8_t CMD_HDR[4] = {0xFD, 0xFC, 0xFB, 0xFA};
27const uint8_t CMD_FTR[4] = {0x04, 0x03, 0x02, 0x01};
29const uint16_t LEN_BASIC = 13;
30const uint16_t LEN_ENGINEERING = 35;
32uint16_t rd16(
const uint8_t *p)
34 return (uint16_t)p[0] | ((uint16_t)p[1] << 8);
38size_t cmd_frame(uint8_t *buf,
size_t cap, uint16_t word,
const uint8_t *val,
size_t vlen)
40 size_t need = 4 + 2 + 2 + vlen + 4;
41 if (!buf || cap < need)
44 for (
int k = 0; k < 4; k++)
45 buf[i++] = CMD_HDR[k];
46 uint16_t dl = (uint16_t)(2 + vlen);
47 buf[i++] = (uint8_t)(dl & 0xFF);
48 buf[i++] = (uint8_t)(dl >> 8);
49 buf[i++] = (uint8_t)(word & 0xFF);
50 buf[i++] = (uint8_t)(word >> 8);
51 for (
size_t k = 0; k < vlen; k++)
53 for (
int k = 0; k < 4; k++)
54 buf[i++] = CMD_FTR[k];
61 if (!f || !out || len < (
size_t)(6 + LEN_BASIC + 4))
63 if (memcmp(f, HDR, 4) != 0)
65 uint16_t dl = rd16(f + 4);
66 if ((
size_t)(6 + dl + 4) != len)
68 if (memcmp(f + 6 + dl, FTR, 4) != 0)
71 const uint8_t *p = f + 6;
73 memset(&r, 0,
sizeof(r));
80 else if (p[0] == 0x01)
82 if (dl != LEN_ENGINEERING)
113 else if (p[11] != 0x55)
155 uint32_t total = 6u + (uint32_t)rd16(s->
buf + 4) + 4u;
161 s->
total = (uint16_t)total;
195 const uint8_t v[2] = {0x01, 0x00};
196 return cmd_frame(buf, cap, 0x00FF, v, 2);
200 return cmd_frame(buf, cap, 0x00FE,
nullptr, 0);
204 return cmd_frame(buf, cap, on ? 0x0062 : 0x0063, nullptr, 0);
208 return cmd_frame(buf, cap, 0x00A3,
nullptr, 0);
244 while (Serial2.available())
259 return s_ld.have ? &s_ld.last :
nullptr;
User-facing configuration for DeterministicESPAsyncWebServer.
#define DETWS_LD2410_BAUD
LD2410 UART baud rate (the module's fixed factory default is 256000).
HLK-LD2410 24 GHz mmWave presence / motion radar codec (DETWS_ENABLE_LD2410).
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).
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.
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.
uint16_t detect_cm
overall detection distance (cm)
uint8_t static_gate_energy[LD2410_MAX_GATES]
per-gate stationary energy (0-100)
uint16_t moving_cm
moving target distance (cm)
uint8_t out_pin
OUT pin level (0/1)
uint8_t max_static_gate
highest configured stationary gate
uint8_t state
one of LD2410_STATE_*
uint8_t static_energy
stationary target energy (0-100)
uint8_t engineering
1 if this was an engineering-mode frame (per-gate energies valid)
uint8_t moving_gate_energy[LD2410_MAX_GATES]
per-gate moving energy (0-100)
uint8_t moving_energy
moving target energy (0-100)
uint8_t max_moving_gate
highest configured moving gate
uint8_t light
photosensor level (0-255)
uint16_t static_cm
stationary target distance (cm)
static constexpr uint8_t LD2410_STATE_NONE
no target
static constexpr uint8_t LD2410_STATE_BOTH
both a moving and a stationary target
static constexpr uint8_t LD2410_STATE_STATIC
stationary target only
static constexpr uint8_t LD2410_STATE_MOVING
moving target only
Byte-by-byte report-frame reassembler (fixed buffer, resyncs on noise).
uint16_t pos
bytes collected so far
uint8_t hdr_match
header bytes matched while syncing (phase = pos<4)
uint16_t total
expected full-frame length (known after the length field)
uint8_t buf[LD2410_FRAME_MAX]
frame under construction
uint8_t phase
0 sync, 1 length, 2 body