perf(rx): батч-выемка фронтов в tick (IR_RX_TICK_BATCH=16) — приём развязан от частоты loop

Было: 1 сырой фронт за tick() -> RX-пропускная способность привязана к loop;
медленный loop (телеметрия/дисплей/КУ-печать) переполнял ISR-буфер 250 фронтов
(~120мс эфира) и кадры гибли молча (вероятная составляющая 'КУ отвечает не на
каждый пакет'). Стало: до IR_RX_TICK_BATCH фронтов за tick; idle-семантика
сохранена (flush пульс-фильтра только при пустом буфере; listenStart/
checkTimeout как раньше). Переопределяемо дефайном до include.
Компил-чек: LaserTestCheck (G491) собирается.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-28 18:22:44 +03:00
parent 873277e59f
commit 5bcaf4092a
2 changed files with 30 additions and 14 deletions

View File

@ -402,11 +402,15 @@ void IR_DecoderRaw::tick()
FrontStorage rawFront; FrontStorage rawFront;
bool processedFront = false; bool processedFront = false;
const bool hasRawFront = subBuffer.pop(rawFront); // B5: копия под одной критсекцией (без торн-рида) // Батч-выемка (IR_RX_TICK_BATCH): раньше 1 фронт/tick — приём был привязан
// к частоте loop, буфер 250 фронтов (~120мс эфира) переполнялся на медленном
if (IR_INPUT_MIN_PULSE_US > 0U) // loop и кадры гибли молча. Семантика idle-пути сохранена: flush
// пульс-фильтра — только когда буфер пуст (как прежняя else-ветка).
uint8_t batchBudget = IR_RX_TICK_BATCH;
bool hasRawFront = subBuffer.pop(rawFront); // B5: копия под одной критсекцией (без торн-рида)
while (hasRawFront)
{ {
if (hasRawFront) if (IR_INPUT_MIN_PULSE_US > 0U)
{ {
pulseFilterPushRaw(rawFront); pulseFilterPushRaw(rawFront);
FrontStorage confirmedFront; FrontStorage confirmedFront;
@ -417,6 +421,17 @@ void IR_DecoderRaw::tick()
} }
} }
else else
{
processDecodedFront(rawFront);
processedFront = true;
}
if (--batchBudget == 0U)
{
break;
}
hasRawFront = subBuffer.pop(rawFront);
}
if (!hasRawFront && IR_INPUT_MIN_PULSE_US > 0U)
{ {
const uint32_t nowUs = micros(); const uint32_t nowUs = micros();
FrontStorage confirmedFront; FrontStorage confirmedFront;
@ -426,12 +441,6 @@ void IR_DecoderRaw::tick()
processedFront = true; processedFront = true;
} }
} }
}
else if (hasRawFront)
{
processDecodedFront(rawFront);
processedFront = true;
}
if (!processedFront) if (!processedFront)
{ {

View File

@ -179,6 +179,13 @@ typedef uint16_t crc_t;
#ifndef IR_INPUT_MIN_PULSE_US #ifndef IR_INPUT_MIN_PULSE_US
#define IR_INPUT_MIN_PULSE_US 0 #define IR_INPUT_MIN_PULSE_US 0
#endif #endif
/** Сколько сырых фронтов забирать из ISR-буфера за один tick() (батч-выемка).
* 1 фронт/tick привязывал RX-пропускную способность к частоте loop: медленный
* loop (телеметрия/дисплей) переполнял буфер 250 фронтов (~120мс эфира) и
* кадры терялись молча. Батч развязывает приём от темпа loop. */
#ifndef IR_RX_TICK_BATCH
#define IR_RX_TICK_BATCH 16U
#endif
/** Сколько подтверждённых фронтов держать перед выпуском в декодер (потоковая задержка). */ /** Сколько подтверждённых фронтов держать перед выпуском в декодер (потоковая задержка). */
#ifndef IR_INPUT_FILTER_HOLDBACK_EDGES #ifndef IR_INPUT_FILTER_HOLDBACK_EDGES
#define IR_INPUT_FILTER_HOLDBACK_EDGES 3U #define IR_INPUT_FILTER_HOLDBACK_EDGES 3U