// Ai-Thinker RD-03E "simple report" frame scanner — PURE LOGIC. // // This unit is deliberately free of ESP-IDF: no UART, no esp_err_t, no // FreeRTOS, no logging. It includes only // // so it can be compiled and tested on a host with plain gcc (see // ../test/). `rd03e.c` does the UART I/O and calls in here to do the // actual parsing. // // The reason this split exists: the first version of this firmware had // RD03E_FRAME_LEN set to 5 for a 6-byte frame, so the footer check read // the distance high byte instead of the second footer byte and every // distance reading came back as `lo | 0x5500` (~218 m). That was pure // logic with zero hardware dependency and should have been catchable on a // laptop. Now it is. // // UNVERIFIED AGAINST REAL HARDWARE, and the frame format below is // reconstructed from a third-party bring-up write-up (electroniclinic.com's // RD-03E/ESP32 tutorial), not Ai-Thinker's own datasheet PDF (not available // while writing this) — treat this as the least-certain protocol detail in // this driver. What's cross-confirmed from multiple independent sources: // UART is 256000 baud / 8N1, and the module also has a separate, more // complex configuration-frame protocol (0xFD 0xFC 0xFB 0xFA header / // 0x04 0x03 0x02 0x01 footer) for calibration and firmware queries — this // driver does NOT implement that; it only reads the module's free-running // "simple report" output frames, which need no configuration to start // streaming after power-up. // // Simple report frame, as reconstructed (6 bytes total): // [0] 0xAA frame header // [1] gesture code raw value, meaning not confirmed against an // official datasheet — reported as-is in // metadata rather than translated to a label // that might be wrong // [2] distance lo byte distance_cm = lo | (hi << 8), little-endian // [3] distance hi byte // [4..5] 0x55 0x55 frame footer // Real bring-up should verify this against a logic analyzer capture before // trusting field values, same as the LD2410 driver this replaced. // // Host tests prove the SHAPE of the parse (byte order, frame length, // footer validation, resynchronisation) against this reconstructed spec. // They cannot prove the reconstructed spec is what the silicon emits. #pragma once #include #include #include #ifdef __cplusplus extern "C" { #endif // Total bytes in one simple-report frame: header + gesture + 2 distance // bytes + 2 footer bytes. Six, not five — see the note above. #define RD03E_FRAME_LEN 6 #define RD03E_FRAME_HEADER 0xAAu #define RD03E_FRAME_FOOTER0 0x55u #define RD03E_FRAME_FOOTER1 0x55u typedef struct { uint8_t gesture; uint16_t distance_cm; } rd03e_frame_t; // Scan `buf` (`len` bytes) for complete, footer-validated simple-report // frames and write the NEWEST one (highest offset) to *out. // // Returns true if at least one valid frame was found, false otherwise // (in which case *out is untouched). A NULL buf, a NULL out, or a buffer // shorter than one frame are all "no frame", not a crash. bool rd03e_parse_latest(const uint8_t *buf, size_t len, rd03e_frame_t *out); #ifdef __cplusplus } #endif