#pragma once #include #include #include "Core.h" #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0) #define OPTICAL_USE_RMT_DMA 1 #include #else #define OPTICAL_USE_RMT_DMA 0 #include #endif class PulseReceiver { public: bool begin(); bool start(uint32_t expectedHz); void stop(); void resetStream(); bool poll(PulsePeriod &period); bool overflowed(); uint32_t tickHz() const; bool highRateBackend() const { #if OPTICAL_USE_RMT_DMA && CONFIG_IDF_TARGET_ESP32S3 return true; #else return false; #endif } private: struct Edge { uint32_t tick; uint8_t rising; }; bool consumeEdge(const Edge &edge, PulsePeriod &period); #if OPTICAL_USE_RMT_DMA static constexpr size_t BLOCK_SYMBOLS = 64; struct SymbolBlock { uint16_t count; rmt_symbol_word_t symbols[BLOCK_SYMBOLS]; }; static bool IRAM_ATTR onRmt(rmt_channel_handle_t, const rmt_rx_done_event_data_t *, void *); bool nextRmtEdge(Edge &edge); rmt_channel_handle_t channel_ = nullptr; rmt_symbol_word_t dmaBuffer_[512]; SymbolBlock block_ = {}; uint16_t blockIndex_ = 0; uint8_t phase_ = 0; bool haveLevel_ = false; bool level_ = false; uint32_t rmtTick_ = 0; #else static void IRAM_ATTR onGpio(void *ctx); uint32_t cpuTickHz_ = 0; #endif QueueHandle_t queue_ = nullptr; volatile bool overflow_ = false; bool running_ = false; bool haveRise_ = false, haveFall_ = false, haveRawTick_ = false; uint32_t lastRawTick_ = 0; uint64_t tickEpoch_ = 0, rise_ = 0, fall_ = 0; };