// ===================================================================== // LD2453Parser.h // // UART frame acquisition + parsing for the Hi-Link HLK-LD2453 radar. // // *** IMPORTANT / READ THIS FIRST *** // The byte-level frame format implemented in LD2453Parser.cpp is a // PLACEHOLDER. As of this writing, the official HLK-LD2453 "5. // Communication Protocol" manual section (frame header, frame tail, // per-target record layout, byte order, sign convention, speed // encoding) could not be sourced from a verifiable primary source. // // Rather than guess and silently emit plausible-but-wrong X/Y/speed // numbers, tryParseFrame() is stubbed to always fail until the real // constants below are filled in from the official manual or from a // reverse-engineered capture (see DEBUG_RADAR_RAW in config.h and the // README "Confirming the protocol" section). // // What IS implemented and fully working right now: // - Non-blocking UART byte acquisition (ring buffer, no delay()) // - Raw hex frame dumping (DEBUG_RADAR_RAW) for protocol capture // - Packets-per-second / parse-error counters // - The public data structures your application code should use // (RadarTarget, RadarFrame) so ZoneManager / WebServerManager / // your .ino never need to change once the real parser is dropped // in below. // ===================================================================== #pragma once #include // --------------------------------------------------------------- // Public data structures // --------------------------------------------------------------- struct RadarTarget { bool valid; int16_t x_mm; int16_t y_mm; int16_t speed; // cm/s, sign = direction (towards/away), per LD2450-family convention — UNCONFIRMED for LD2453 float distance_mm; // only populated if the confirmed protocol provides it directly; else derived from x/y float angle_deg; // only populated if the confirmed protocol provides it directly }; struct RadarFrame { uint32_t timestamp_ms; // millis() at time of frame completion uint32_t sequence_number; // increments per frame, for multi-radar fusion later const char *node_id; // NODE_ID from config.h RadarTarget targets[3]; uint8_t targetCount; // number of *valid* targets in this frame (0-3) }; // Simple acquisition/parse statistics, useful for the diagnostic // serial output requested for stage 1. struct LD2453Stats { uint32_t framesParsed = 0; uint32_t parseErrors = 0; uint32_t bytesReceived = 0; uint32_t lastFrameLength = 0; float packetsPerSecond = 0.0f; }; // --------------------------------------------------------------- // Parser class // --------------------------------------------------------------- class LD2453Parser { public: // rawDebug: when true, every candidate frame's raw bytes are // printed as hex to Serial. Drive this from DEBUG_RADAR_RAW. void begin(HardwareSerial &serial, int rxPin, int txPin, uint32_t baud, const char *nodeId, bool rawDebug = false); // Call every loop() iteration. Non-blocking: reads whatever bytes // are available, feeds the internal state machine, and returns // true exactly once when a *new, fully parsed* frame is ready // (retrieve it with getLastFrame()). // // NOTE: with tryParseFrame() stubbed out (see .cpp), this will // currently never return true — see the header comment above. bool update(); const RadarFrame &getLastFrame() const { return _lastFrame; } const LD2453Stats &getStats() const { return _stats; } // Kiểm tra xem có đang nhận dữ liệu từ LD2453 không bool isConnected() const { return _stats.bytesReceived > 0 && (millis() - _lastByteTime) < 2000; } private: HardwareSerial *_serial = nullptr; bool _rawDebug = false; const char *_nodeId = "RADAR_A"; static const size_t RING_BUFFER_SIZE = 256; uint8_t _ringBuffer[RING_BUFFER_SIZE]; size_t _bufferLen = 0; RadarFrame _lastFrame{}; LD2453Stats _stats{}; uint32_t _sequenceCounter = 0; uint32_t _lastByteTime = 0; // Thời điểm nhận byte cuối cùng uint32_t _ppsWindowStart = 0; uint32_t _ppsWindowCount = 0; void feedByte(uint8_t b); void dumpRawHex(const uint8_t *data, size_t len); // Returns true and consumes `len` bytes from _ringBuffer if a // valid frame was found and parsed into _lastFrame. Returns // false (and consumes 0 bytes) otherwise. // // *** STUBBED — see LD2453Parser.cpp *** bool tryParseFrame(); };