codex init
This commit is contained in:
155
OpticalChannelTester/Receiver.cpp
Normal file
155
OpticalChannelTester/Receiver.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
#include "Receiver.h"
|
||||
#include "Config.h"
|
||||
#include <string.h>
|
||||
#if !OPTICAL_USE_RMT_DMA
|
||||
#include <esp_cpu.h>
|
||||
#include <esp32-hal-cpu.h>
|
||||
#endif
|
||||
|
||||
uint32_t PulseReceiver::tickHz() const {
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
return CAPTURE_RESOLUTION_HZ;
|
||||
#else
|
||||
return cpuTickHz_;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PulseReceiver::begin() {
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
queue_ = xQueueCreate(16, sizeof(SymbolBlock));
|
||||
rmt_rx_channel_config_t cfg = {};
|
||||
cfg.clk_src = RMT_CLK_SRC_DEFAULT; cfg.resolution_hz = CAPTURE_RESOLUTION_HZ;
|
||||
cfg.mem_block_symbols = 512; cfg.gpio_num = static_cast<gpio_num_t>(GPIO_RX);
|
||||
cfg.flags.invert_in = RX_SIGNAL_INVERTED;
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
cfg.flags.with_dma = true;
|
||||
#else
|
||||
cfg.flags.with_dma = false; // C3 uses hardware RMT ping-pong partial reception
|
||||
#endif
|
||||
if (!queue_ || rmt_new_rx_channel(&cfg, &channel_) != ESP_OK) return false;
|
||||
rmt_rx_event_callbacks_t callbacks = {}; callbacks.on_recv_done = onRmt;
|
||||
return rmt_rx_register_event_callbacks(channel_, &callbacks, this) == ESP_OK;
|
||||
#else
|
||||
queue_ = xQueueCreate(256, sizeof(Edge));
|
||||
if (!queue_) return false;
|
||||
pinMode(GPIO_RX, INPUT);
|
||||
cpuTickHz_ = getCpuFrequencyMhz() * 1000000UL;
|
||||
attachInterruptArg(GPIO_RX, onGpio, this, CHANGE);
|
||||
return cpuTickHz_ != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PulseReceiver::start(uint32_t expectedHz) {
|
||||
resetStream();
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
if (rmt_enable(channel_) != ESP_OK) return false;
|
||||
rmt_receive_config_t cfg = {};
|
||||
cfg.signal_range_min_ns = 20;
|
||||
const uint64_t maxNs = 4000000000ULL / (expectedHz ? expectedHz : 1);
|
||||
cfg.signal_range_max_ns = maxNs > 100000000ULL ? 100000000UL : static_cast<uint32_t>(maxNs);
|
||||
cfg.flags.en_partial_rx = true;
|
||||
if (rmt_receive(channel_, dmaBuffer_, sizeof(dmaBuffer_), &cfg) != ESP_OK) {
|
||||
rmt_disable(channel_); return false;
|
||||
}
|
||||
#else
|
||||
(void)expectedHz;
|
||||
#endif
|
||||
running_ = true; return true;
|
||||
}
|
||||
|
||||
void PulseReceiver::stop() {
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
if (running_) rmt_disable(channel_);
|
||||
#endif
|
||||
running_ = false;
|
||||
}
|
||||
|
||||
void PulseReceiver::resetStream() {
|
||||
if (queue_) xQueueReset(queue_);
|
||||
overflow_ = false; haveRise_ = haveFall_ = haveRawTick_ = false;
|
||||
lastRawTick_ = 0; tickEpoch_ = rise_ = fall_ = 0;
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
block_ = {}; blockIndex_ = 0; phase_ = 0; haveLevel_ = false; level_ = false; rmtTick_ = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PulseReceiver::consumeEdge(const Edge &e, PulsePeriod &out) {
|
||||
if (haveRawTick_ && e.tick < lastRawTick_ && lastRawTick_ - e.tick > 0x80000000UL)
|
||||
tickEpoch_ += 0x100000000ULL;
|
||||
haveRawTick_ = true; lastRawTick_ = e.tick;
|
||||
const uint64_t tick = tickEpoch_ + e.tick;
|
||||
if (e.rising) {
|
||||
if (!haveRise_) { rise_ = tick; haveRise_ = true; haveFall_ = false; return false; }
|
||||
if (!haveFall_) { overflow_ = true; rise_ = tick; return false; }
|
||||
const uint32_t period = static_cast<uint32_t>(tick - rise_);
|
||||
const uint32_t active = fall_ - rise_;
|
||||
out = {rise_, period, active}; rise_ = tick; haveFall_ = false;
|
||||
return true;
|
||||
}
|
||||
if (!haveRise_ || haveFall_) { overflow_ = true; return false; }
|
||||
fall_ = tick; haveFall_ = true; return false;
|
||||
}
|
||||
|
||||
bool PulseReceiver::overflowed() {
|
||||
const bool value = overflow_; overflow_ = false; return value;
|
||||
}
|
||||
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
bool IRAM_ATTR PulseReceiver::onRmt(rmt_channel_handle_t, const rmt_rx_done_event_data_t *data, void *ctx) {
|
||||
PulseReceiver *self = static_cast<PulseReceiver *>(ctx);
|
||||
BaseType_t wake = pdFALSE;
|
||||
size_t offset = 0;
|
||||
while (offset < data->num_symbols) {
|
||||
SymbolBlock b = {};
|
||||
b.count = static_cast<uint16_t>((data->num_symbols - offset) > BLOCK_SYMBOLS ?
|
||||
BLOCK_SYMBOLS : (data->num_symbols - offset));
|
||||
memcpy(b.symbols, data->received_symbols + offset, b.count * sizeof(rmt_symbol_word_t));
|
||||
if (xQueueSendFromISR(self->queue_, &b, &wake) != pdTRUE) self->overflow_ = true;
|
||||
offset += b.count;
|
||||
}
|
||||
return wake == pdTRUE;
|
||||
}
|
||||
|
||||
bool PulseReceiver::nextRmtEdge(Edge &edge) {
|
||||
for (;;) {
|
||||
if (blockIndex_ >= block_.count) {
|
||||
if (xQueueReceive(queue_, &block_, 0) != pdTRUE) return false;
|
||||
blockIndex_ = 0; phase_ = 0;
|
||||
}
|
||||
const rmt_symbol_word_t &s = block_.symbols[blockIndex_];
|
||||
const bool nextLevel = phase_ == 0 ? s.level0 : s.level1;
|
||||
const uint32_t duration = phase_ == 0 ? s.duration0 : s.duration1;
|
||||
phase_ ^= 1;
|
||||
if (phase_ == 0) ++blockIndex_;
|
||||
if (!duration) continue;
|
||||
if (!haveLevel_) { haveLevel_ = true; level_ = nextLevel; rmtTick_ += duration; continue; }
|
||||
if (nextLevel != level_) {
|
||||
level_ = nextLevel; edge = {rmtTick_, static_cast<uint8_t>(nextLevel)};
|
||||
rmtTick_ += duration; return true;
|
||||
}
|
||||
rmtTick_ += duration;
|
||||
}
|
||||
}
|
||||
|
||||
bool PulseReceiver::poll(PulsePeriod &period) {
|
||||
Edge e;
|
||||
while (nextRmtEdge(e)) if (consumeEdge(e, period)) return true;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
void IRAM_ATTR PulseReceiver::onGpio(void *ctx) {
|
||||
PulseReceiver *self = static_cast<PulseReceiver *>(ctx);
|
||||
bool level = gpio_get_level(static_cast<gpio_num_t>(GPIO_RX));
|
||||
if (RX_SIGNAL_INVERTED) level = !level;
|
||||
Edge e = {esp_cpu_get_cycle_count(), static_cast<uint8_t>(level)};
|
||||
BaseType_t wake = pdFALSE;
|
||||
if (xQueueSendFromISR(self->queue_, &e, &wake) != pdTRUE) self->overflow_ = true;
|
||||
if (wake) portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
bool PulseReceiver::poll(PulsePeriod &period) {
|
||||
Edge e;
|
||||
while (xQueueReceive(queue_, &e, 0) == pdTRUE) if (consumeEdge(e, period)) return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user