From 5bcaf4092a8ddfbc59ed4df1d10eb1352ffa780e Mon Sep 17 00:00:00 2001 From: DashyFox Date: Tue, 28 Jul 2026 18:22:44 +0300 Subject: [PATCH] =?UTF-8?q?perf(rx):=20=D0=B1=D0=B0=D1=82=D1=87-=D0=B2?= =?UTF-8?q?=D1=8B=D0=B5=D0=BC=D0=BA=D0=B0=20=D1=84=D1=80=D0=BE=D0=BD=D1=82?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=B2=20tick=20(IR=5FRX=5FTICK=5FBATCH=3D16)=20?= =?UTF-8?q?=E2=80=94=20=D0=BF=D1=80=D0=B8=D1=91=D0=BC=20=D1=80=D0=B0=D0=B7?= =?UTF-8?q?=D0=B2=D1=8F=D0=B7=D0=B0=D0=BD=20=D0=BE=D1=82=20=D1=87=D0=B0?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D1=82=D1=8B=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Было: 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) --- IR_DecoderRaw.cpp | 37 +++++++++++++++++++++++-------------- IR_config.h | 7 +++++++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/IR_DecoderRaw.cpp b/IR_DecoderRaw.cpp index 66482f2..a230806 100644 --- a/IR_DecoderRaw.cpp +++ b/IR_DecoderRaw.cpp @@ -402,11 +402,15 @@ void IR_DecoderRaw::tick() FrontStorage rawFront; bool processedFront = false; - const bool hasRawFront = subBuffer.pop(rawFront); // B5: копия под одной критсекцией (без торн-рида) - - if (IR_INPUT_MIN_PULSE_US > 0U) + // Батч-выемка (IR_RX_TICK_BATCH): раньше 1 фронт/tick — приём был привязан + // к частоте loop, буфер 250 фронтов (~120мс эфира) переполнялся на медленном + // 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); FrontStorage confirmedFront; @@ -418,19 +422,24 @@ void IR_DecoderRaw::tick() } else { - const uint32_t nowUs = micros(); - FrontStorage confirmedFront; - while (pulseFilterTryFlushOne(nowUs, confirmedFront)) - { - processDecodedFront(confirmedFront); - processedFront = true; - } + processDecodedFront(rawFront); + processedFront = true; } + if (--batchBudget == 0U) + { + break; + } + hasRawFront = subBuffer.pop(rawFront); } - else if (hasRawFront) + if (!hasRawFront && IR_INPUT_MIN_PULSE_US > 0U) { - processDecodedFront(rawFront); - processedFront = true; + const uint32_t nowUs = micros(); + FrontStorage confirmedFront; + while (pulseFilterTryFlushOne(nowUs, confirmedFront)) + { + processDecodedFront(confirmedFront); + processedFront = true; + } } if (!processedFront) diff --git a/IR_config.h b/IR_config.h index d585d9e..afdfff5 100644 --- a/IR_config.h +++ b/IR_config.h @@ -179,6 +179,13 @@ typedef uint16_t crc_t; #ifndef IR_INPUT_MIN_PULSE_US #define IR_INPUT_MIN_PULSE_US 0 #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 #define IR_INPUT_FILTER_HOLDBACK_EDGES 3U