Глобальная переделка. тест сделан по длине импульса и заданной частоте шим, а не меандру
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
#include "Receiver.h"
|
||||
#include "Config.h"
|
||||
#include <string.h>
|
||||
#if !OPTICAL_USE_RMT_DMA
|
||||
#include "Log.h"
|
||||
#include <math.h>
|
||||
#if !OPTICAL_USE_MCPWM_CAPTURE
|
||||
#include <esp_cpu.h>
|
||||
#include <esp32-hal-cpu.h>
|
||||
#endif
|
||||
|
||||
uint32_t PulseReceiver::tickHz() const {
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||
return captureResolutionHz_;
|
||||
#else
|
||||
return cpuTickHz_;
|
||||
@@ -15,31 +15,48 @@ uint32_t PulseReceiver::tickHz() const {
|
||||
}
|
||||
|
||||
uint32_t PulseReceiver::plannedTickHz(uint32_t expectedHz, float expectedDutyPct) const {
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
if (!expectedHz || expectedDutyPct <= 0.0f || expectedDutyPct >= 100.0f)
|
||||
return CAPTURE_RESOLUTION_OPTIONS_HZ[0];
|
||||
uint32_t dutyX100 = static_cast<uint32_t>(expectedDutyPct * 100.0f + 0.5f);
|
||||
if (dutyX100 < 5000U) dutyX100 = 10000U - dutyX100;
|
||||
for (int i = static_cast<int>(countOf(CAPTURE_RESOLUTION_OPTIONS_HZ)) - 1; i >= 0; --i) {
|
||||
const uint32_t resolution = CAPTURE_RESOLUTION_OPTIONS_HZ[i];
|
||||
const uint64_t levelTicksX100 = static_cast<uint64_t>(resolution) * dutyX100;
|
||||
const uint64_t limitX100 = static_cast<uint64_t>(expectedHz) * 10000ULL * RMT_MAX_LEVEL_TICKS;
|
||||
if (levelTicksX100 <= limitX100) return resolution;
|
||||
}
|
||||
return CAPTURE_RESOLUTION_OPTIONS_HZ[0];
|
||||
if (!expectedHz || expectedDutyPct <= 0.0f || expectedDutyPct >= 100.0f) return 0;
|
||||
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||
return captureResolutionHz_ ? captureResolutionHz_ :
|
||||
MCPWM_CAPTURE_RESOLUTION_HZ;
|
||||
#else
|
||||
(void)expectedHz; (void)expectedDutyPct;
|
||||
return cpuTickHz_;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PulseReceiver::begin() {
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
queue_ = xQueueCreate(RMT_QUEUE_BLOCKS, sizeof(SymbolBlock));
|
||||
return queue_ && configureRmt(CAPTURE_RESOLUTION_OPTIONS_HZ[0]);
|
||||
#else
|
||||
queue_ = xQueueCreate(256, sizeof(Edge));
|
||||
queue_ = xQueueCreate(512, sizeof(Edge));
|
||||
if (!queue_) return false;
|
||||
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||
// PWM generation uses MCPWM group 0. Group 1 is dedicated to input capture,
|
||||
// so RX cannot exhaust or conflict with the generator's resources.
|
||||
mcpwm_capture_timer_config_t timerConfig = {};
|
||||
timerConfig.group_id = 1;
|
||||
timerConfig.clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT;
|
||||
timerConfig.resolution_hz = MCPWM_CAPTURE_RESOLUTION_HZ;
|
||||
if (mcpwm_new_capture_timer(&timerConfig, &captureTimer_) != ESP_OK) return false;
|
||||
if (mcpwm_capture_timer_get_resolution(captureTimer_, &captureResolutionHz_) != ESP_OK ||
|
||||
!captureResolutionHz_) return false;
|
||||
|
||||
mcpwm_capture_channel_config_t channelConfig = {};
|
||||
channelConfig.gpio_num = GPIO_RX;
|
||||
channelConfig.prescale = 1;
|
||||
channelConfig.flags.pos_edge = true;
|
||||
channelConfig.flags.neg_edge = false;
|
||||
if (mcpwm_new_capture_channel(captureTimer_, &channelConfig, &risingChannel_) != ESP_OK)
|
||||
return false;
|
||||
mcpwm_capture_event_callbacks_t callbacks = {};
|
||||
callbacks.on_cap = onCapture;
|
||||
if (mcpwm_capture_channel_register_event_callbacks(
|
||||
risingChannel_, &callbacks, this) != ESP_OK) return false;
|
||||
|
||||
channelConfig.flags.pos_edge = false;
|
||||
channelConfig.flags.neg_edge = true;
|
||||
if (mcpwm_new_capture_channel(captureTimer_, &channelConfig, &fallingChannel_) != ESP_OK)
|
||||
return false;
|
||||
return mcpwm_capture_channel_register_event_callbacks(
|
||||
fallingChannel_, &callbacks, this) == ESP_OK;
|
||||
#else
|
||||
pinMode(GPIO_RX, INPUT);
|
||||
cpuTickHz_ = getCpuFrequencyMhz() * 1000000UL;
|
||||
attachInterruptArg(GPIO_RX, onGpio, this, CHANGE);
|
||||
@@ -47,178 +64,195 @@ bool PulseReceiver::begin() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
bool PulseReceiver::configureRmt(uint32_t resolutionHz) {
|
||||
if (channel_ && captureResolutionHz_ == resolutionHz) return true;
|
||||
stop();
|
||||
if (channel_) {
|
||||
if (rmt_del_channel(channel_) != ESP_OK) return false;
|
||||
channel_ = nullptr;
|
||||
}
|
||||
rmt_rx_channel_config_t cfg = {};
|
||||
cfg.clk_src = RMT_CLK_SRC_DEFAULT; cfg.resolution_hz = resolutionHz;
|
||||
cfg.gpio_num = static_cast<gpio_num_t>(GPIO_RX);
|
||||
// Internally the measurement code always treats HIGH as the active phase.
|
||||
cfg.flags.invert_in = RX_ACTIVE_LEVEL == LOW;
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
cfg.mem_block_symbols = 512;
|
||||
cfg.flags.with_dma = true;
|
||||
#else
|
||||
// C3 has 48 RMT symbols per channel and no RMT DMA. A request for 512
|
||||
// consumes all available blocks and fails with "no free rx channels".
|
||||
cfg.mem_block_symbols = RMT_MIN_RECEIVE_SYMBOLS;
|
||||
cfg.flags.with_dma = false; // C3 uses hardware RMT ping-pong partial reception
|
||||
#endif
|
||||
if (rmt_new_rx_channel(&cfg, &channel_) != ESP_OK) return false;
|
||||
rmt_rx_event_callbacks_t callbacks = {}; callbacks.on_recv_done = onRmt;
|
||||
if (rmt_rx_register_event_callbacks(channel_, &callbacks, this) != ESP_OK) {
|
||||
rmt_del_channel(channel_); channel_ = nullptr; return false;
|
||||
}
|
||||
captureResolutionHz_ = resolutionHz;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool PulseReceiver::start(uint32_t expectedHz, float expectedDutyPct) {
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
const uint32_t resolutionHz = plannedTickHz(expectedHz, expectedDutyPct);
|
||||
if (!configureRmt(resolutionHz)) return false;
|
||||
#else
|
||||
(void)expectedHz; (void)expectedDutyPct;
|
||||
if (!plannedTickHz(expectedHz, expectedDutyPct)) return false;
|
||||
expectedHz_ = expectedHz;
|
||||
expectedDutyPct_ = expectedDutyPct;
|
||||
#if !OPTICAL_USE_MCPWM_CAPTURE
|
||||
cpuTickHz_ = getCpuFrequencyMhz() * 1000000UL;
|
||||
if (!cpuTickHz_) return false;
|
||||
#endif
|
||||
resetStream();
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
// In partial RX mode the callback is delivered when this user buffer fills.
|
||||
// Keep chunks near 5 ms so low-frequency input is reported before NO SIGNAL.
|
||||
uint64_t symbols = (static_cast<uint64_t>(expectedHz) * RMT_TARGET_CHUNK_US + 999999ULL) / 1000000ULL;
|
||||
if (symbols < RMT_MIN_RECEIVE_SYMBOLS) symbols = RMT_MIN_RECEIVE_SYMBOLS;
|
||||
if (symbols > RMT_MAX_RECEIVE_SYMBOLS) symbols = RMT_MAX_RECEIVE_SYMBOLS;
|
||||
receiveChunkSymbols_ = static_cast<uint16_t>(symbols);
|
||||
if (rmt_enable(channel_) != ESP_OK) return false;
|
||||
rmt_receive_config_t cfg = {};
|
||||
cfg.signal_range_min_ns = 1000000000UL / captureResolutionHz_;
|
||||
const uint64_t maxNs = 4000000000ULL / (expectedHz ? expectedHz : 1);
|
||||
// A duration field is 15 bits. Keep the driver's end-of-signal threshold
|
||||
// strictly below that hardware limit (IDF rejects larger values).
|
||||
const uint64_t hardwareMaxNs = static_cast<uint64_t>(RMT_MAX_LEVEL_TICKS) * 1000000000ULL / captureResolutionHz_;
|
||||
cfg.signal_range_max_ns = static_cast<uint32_t>(maxNs > hardwareMaxNs ? hardwareMaxNs : maxNs);
|
||||
cfg.flags.en_partial_rx = true;
|
||||
if (rmt_receive(channel_, receiveBuffer_,
|
||||
receiveChunkSymbols_ * sizeof(receiveBuffer_[0]), &cfg) != ESP_OK) {
|
||||
rmt_disable(channel_); return false;
|
||||
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||
// Progress updates keep one capture session alive. Pulse-width stages stop
|
||||
// capture only after PWM is quiet, so resetStream never races the ISR.
|
||||
if (running_) return true;
|
||||
if (mcpwm_capture_timer_enable(captureTimer_) != ESP_OK) return false;
|
||||
if (mcpwm_capture_channel_enable(risingChannel_) != ESP_OK) {
|
||||
mcpwm_capture_timer_disable(captureTimer_);
|
||||
return false;
|
||||
}
|
||||
if (mcpwm_capture_channel_enable(fallingChannel_) != ESP_OK) {
|
||||
mcpwm_capture_channel_disable(risingChannel_);
|
||||
mcpwm_capture_timer_disable(captureTimer_);
|
||||
return false;
|
||||
}
|
||||
running_ = true;
|
||||
if (mcpwm_capture_timer_start(captureTimer_) != ESP_OK) {
|
||||
running_ = false;
|
||||
mcpwm_capture_channel_disable(fallingChannel_);
|
||||
mcpwm_capture_channel_disable(risingChannel_);
|
||||
mcpwm_capture_timer_disable(captureTimer_);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
running_ = true;
|
||||
#endif
|
||||
running_ = true; return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PulseReceiver::stop() {
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
if (running_) rmt_disable(channel_);
|
||||
#endif
|
||||
const bool wasRunning = running_;
|
||||
running_ = false;
|
||||
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||
if (wasRunning) {
|
||||
// Mask both edge interrupts before stopping the shared capture timer.
|
||||
mcpwm_capture_channel_disable(fallingChannel_);
|
||||
mcpwm_capture_channel_disable(risingChannel_);
|
||||
mcpwm_capture_timer_stop(captureTimer_);
|
||||
mcpwm_capture_timer_disable(captureTimer_);
|
||||
}
|
||||
#else
|
||||
(void)wasRunning;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PulseReceiver::resetStream() {
|
||||
if (queue_) xQueueReset(queue_);
|
||||
overflow_ = false; droppedItems_ = 0; 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
|
||||
haveReorderEdge_ = false;
|
||||
droppedItems_ = 0;
|
||||
polarityKnown_ = false;
|
||||
activeStartRising_ = false;
|
||||
syncEdgeCount_ = 0;
|
||||
waitingForActiveEnd_ = true;
|
||||
activeStart_ = activeEnd_ = 0;
|
||||
haveRawTick_ = false;
|
||||
lastRawTick_ = 0;
|
||||
tickEpoch_ = 0;
|
||||
}
|
||||
|
||||
bool PulseReceiver::consumeEdge(const Edge &e, PulsePeriod &out) {
|
||||
PulseReceiver::TimedEdge PulseReceiver::extendEdge(const Edge &e) {
|
||||
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;
|
||||
}
|
||||
// Reception can begin in the middle of a HIGH pulse. In that case the first
|
||||
// observable edge is falling and there is no complete period to validate.
|
||||
// Ignore only this leading partial pulse and synchronize on the next rise.
|
||||
if (!haveRise_) return false;
|
||||
if (haveFall_) { overflow_ = true; return false; }
|
||||
fall_ = tick; haveFall_ = true; return false;
|
||||
return {tickEpoch_ + e.tick, e.rising != 0};
|
||||
}
|
||||
|
||||
bool PulseReceiver::overflowed() {
|
||||
const bool value = overflow_; overflow_ = false; return value;
|
||||
bool PulseReceiver::consumeEdge(const Edge &rawEdge, PulsePeriod &out) {
|
||||
const TimedEdge edge = extendEdge(rawEdge);
|
||||
if (polarityKnown_) {
|
||||
// Deliberately ignore edge type after synchronization. A PWM waveform is
|
||||
// just alternating intervals: active, inactive, active, inactive. An
|
||||
// extra or missing edge therefore becomes a concrete wrong pulse/period
|
||||
// instead of an ambiguous GLITCH state.
|
||||
if (waitingForActiveEnd_) {
|
||||
activeEnd_ = edge.tick;
|
||||
waitingForActiveEnd_ = false;
|
||||
return false;
|
||||
}
|
||||
const uint64_t periodTicks = edge.tick - activeStart_;
|
||||
const uint64_t activeTicks = activeEnd_ - activeStart_;
|
||||
out = {activeStart_, static_cast<uint32_t>(periodTicks),
|
||||
static_cast<uint32_t>(activeTicks), tickHz()};
|
||||
activeStart_ = edge.tick;
|
||||
waitingForActiveEnd_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
syncEdges_[syncEdgeCount_++] = edge;
|
||||
if (syncEdgeCount_ < 3U) return false;
|
||||
|
||||
const uint64_t firstTicks = syncEdges_[1].tick - syncEdges_[0].tick;
|
||||
const uint64_t secondTicks = syncEdges_[2].tick - syncEdges_[1].tick;
|
||||
const double expectedTicks = static_cast<double>(tickHz()) * expectedDutyPct_ /
|
||||
(100.0 * expectedHz_);
|
||||
const double firstError = fabs(static_cast<double>(firstTicks) - expectedTicks);
|
||||
const double secondError = fabs(static_cast<double>(secondTicks) - expectedTicks);
|
||||
activeStartRising_ = firstError <= secondError ? syncEdges_[0].rising : syncEdges_[1].rising;
|
||||
polarityKnown_ = true;
|
||||
Log::printf("CAPTURE", "RX polarity auto: active starts on %s, first=%lluns second=%lluns",
|
||||
activeStartRising_ ? "RISING" : "FALLING",
|
||||
static_cast<unsigned long long>(firstTicks * 1000000000ULL / tickHz()),
|
||||
static_cast<unsigned long long>(secondTicks * 1000000000ULL / tickHz()));
|
||||
|
||||
bool produced = false;
|
||||
if (firstError <= secondError) {
|
||||
activeStart_ = syncEdges_[0].tick;
|
||||
activeEnd_ = syncEdges_[1].tick;
|
||||
const uint64_t periodTicks = syncEdges_[2].tick - activeStart_;
|
||||
out = {activeStart_, static_cast<uint32_t>(periodTicks),
|
||||
static_cast<uint32_t>(activeEnd_ - activeStart_), tickHz()};
|
||||
activeStart_ = syncEdges_[2].tick;
|
||||
waitingForActiveEnd_ = true;
|
||||
produced = true;
|
||||
} else {
|
||||
activeStart_ = syncEdges_[1].tick;
|
||||
activeEnd_ = syncEdges_[2].tick;
|
||||
waitingForActiveEnd_ = false;
|
||||
}
|
||||
syncEdgeCount_ = 0;
|
||||
return produced;
|
||||
}
|
||||
|
||||
uint32_t PulseReceiver::takeDroppedItems() {
|
||||
return __atomic_exchange_n(&droppedItems_, 0, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
#if OPTICAL_USE_RMT_DMA
|
||||
bool IRAM_ATTR PulseReceiver::onRmt(rmt_channel_handle_t, const rmt_rx_done_event_data_t *data, void *ctx) {
|
||||
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||
bool IRAM_ATTR PulseReceiver::onCapture(mcpwm_cap_channel_handle_t,
|
||||
const mcpwm_capture_event_data_t *data,
|
||||
void *ctx) {
|
||||
PulseReceiver *self = static_cast<PulseReceiver *>(ctx);
|
||||
if (!self->running_) return false;
|
||||
const bool rawRising = data->cap_edge == MCPWM_CAP_EDGE_POS;
|
||||
const Edge edge = {data->cap_value, static_cast<uint8_t>(rawRising)};
|
||||
BaseType_t wake = pdFALSE;
|
||||
size_t offset = 0;
|
||||
while (offset < data->num_symbols) {
|
||||
SymbolBlock &b = self->isrBlock_;
|
||||
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)
|
||||
__atomic_fetch_add(&self->droppedItems_, b.count, __ATOMIC_RELAXED);
|
||||
offset += b.count;
|
||||
}
|
||||
if (xQueueSendFromISR(self->queue_, &edge, &wake) != pdTRUE)
|
||||
__atomic_fetch_add(&self->droppedItems_, 1U, __ATOMIC_RELAXED);
|
||||
return wake == pdTRUE;
|
||||
}
|
||||
|
||||
bool PulseReceiver::nextRmtEdge(Edge &edge, TickType_t waitTicks) {
|
||||
for (;;) {
|
||||
if (blockIndex_ >= block_.count) {
|
||||
if (xQueueReceive(queue_, &block_, waitTicks) != pdTRUE) return false;
|
||||
blockIndex_ = 0; phase_ = 0;
|
||||
waitTicks = 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;
|
||||
}
|
||||
}
|
||||
|
||||
size_t PulseReceiver::readPeriods(PulsePeriod *periods, size_t capacity, TickType_t waitTicks) {
|
||||
size_t count = 0;
|
||||
Edge e;
|
||||
while (count < capacity && nextRmtEdge(e, count ? 0 : waitTicks))
|
||||
if (consumeEdge(e, periods[count])) ++count;
|
||||
return count;
|
||||
}
|
||||
#else
|
||||
void IRAM_ATTR PulseReceiver::onGpio(void *ctx) {
|
||||
PulseReceiver *self = static_cast<PulseReceiver *>(ctx);
|
||||
if (!self->running_) return;
|
||||
bool level = gpio_get_level(static_cast<gpio_num_t>(GPIO_RX));
|
||||
if (RX_ACTIVE_LEVEL == LOW) level = !level;
|
||||
Edge e = {esp_cpu_get_cycle_count(), static_cast<uint8_t>(level)};
|
||||
const Edge edge = {esp_cpu_get_cycle_count(), static_cast<uint8_t>(level)};
|
||||
BaseType_t wake = pdFALSE;
|
||||
if (xQueueSendFromISR(self->queue_, &e, &wake) != pdTRUE)
|
||||
if (xQueueSendFromISR(self->queue_, &edge, &wake) != pdTRUE)
|
||||
__atomic_fetch_add(&self->droppedItems_, 1U, __ATOMIC_RELAXED);
|
||||
if (wake) portYIELD_FROM_ISR();
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t PulseReceiver::readPeriods(PulsePeriod *periods, size_t capacity, TickType_t waitTicks) {
|
||||
bool PulseReceiver::nextOrderedEdge(Edge &edge, TickType_t waitTicks) {
|
||||
if (!haveReorderEdge_) {
|
||||
if (xQueueReceive(queue_, &reorderEdge_, waitTicks) != pdTRUE) return false;
|
||||
haveReorderEdge_ = true;
|
||||
}
|
||||
Edge next = {};
|
||||
// Keep one-event look-ahead. If both channel interrupts were pending while
|
||||
// OLED/I2C ran, the MCPWM driver may dispatch them by channel number rather
|
||||
// than timestamp. The signed modular comparison restores their real order.
|
||||
if (xQueueReceive(queue_, &next, waitTicks) != pdTRUE) return false;
|
||||
if (static_cast<int32_t>(next.tick - reorderEdge_.tick) < 0) {
|
||||
edge = next;
|
||||
} else {
|
||||
edge = reorderEdge_;
|
||||
reorderEdge_ = next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t PulseReceiver::readPeriods(PulsePeriod *periods, size_t capacity,
|
||||
TickType_t waitTicks) {
|
||||
size_t count = 0;
|
||||
Edge e;
|
||||
while (count < capacity && xQueueReceive(queue_, &e, count ? 0 : waitTicks) == pdTRUE)
|
||||
if (consumeEdge(e, periods[count])) ++count;
|
||||
Edge edge = {};
|
||||
while (count < capacity && nextOrderedEdge(edge, count ? 0 : waitTicks)) {
|
||||
if (consumeEdge(edge, periods[count])) {
|
||||
periods[count].activeTickHz = tickHz();
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user