From baac9fbf46433f63acd7e1a5f6aebd38e533c163 Mon Sep 17 00:00:00 2001 From: DashyFox Date: Wed, 9 Sep 2026 16:09:55 +0300 Subject: [PATCH] =?UTF-8?q?fix(rx):=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D1=8B=D0=B2=D0=B0=20=D0=BA=D0=B0=D0=B4=D1=80?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=B5=20=D1=82=D1=80=D0=B5=D0=B1=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=2030=20=D0=BC=D1=81=20=D1=82=D0=B8=D1=88?= =?UTF-8?q?=D0=B8=D0=BD=D1=8B=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D1=8B=D0=BC=20=D0=BA=D0=B0=D0=BD=D0=B4=D0=B8=D0=B4?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D0=BC=20=D0=BF=D1=80=D0=B5=D0=B0=D0=BC=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D1=8B=20(releasePreambleGuard)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prevRise (последний декодированный фронт) не сбрасывался при abortFrame, а отброшенные гвардом фронты его не двигают — валидный кадр, начавшийся через <30 мс после обрыва мусора, проглатывался целиком без счётчика. Стенд 09.09: КУ теряла пинг машинки после обрывков чужого заднего и всплеска её дальномера за 24 мс до пинга (V-серия 75–83 %, после правки 100 %). Хост-тест (настоящий IR_DecoderRaw.cpp + шим Arduino): после abort кадр через 5…28 мс — терялся, теперь принимается; чистый конец кадра не тронут (мин. пауза 26.25 мс), хвост оборванного кадра ложных захватов не даёт, 200/200 валидных среди мусора, стресс 166→176/200. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01AeA1K5dBUKrnoXVwyoVjzq --- IR_DecoderRaw.cpp | 13 +++++++++++++ IR_DecoderRaw.h | 1 + 2 files changed, 14 insertions(+) diff --git a/IR_DecoderRaw.cpp b/IR_DecoderRaw.cpp index 7359dc8..5892546 100644 --- a/IR_DecoderRaw.cpp +++ b/IR_DecoderRaw.cpp @@ -440,6 +440,19 @@ void IR_DecoderRaw::abortFrame(uint32_t tUs) isReciveRaw = false; msgTypeReceive = 0; firstRX(); + releasePreambleGuard(tUs); +} + +// После обрыва кадра «длинная тишина» (IR_timeout × 2 ≈ 30 мс) перед новым кандидатом преамбулы не требуется. +// prevRise — последний ДЕКОДИРОВАННЫЙ фронт; после abort он свежий, а фронты, отброшенные гвардом, его не двигают, +// поэтому валидный кадр, начавшийся через <30 мс после обрыва мусора, проглатывался целиком без счётчика +// (стенд 09.09: КУ теряла пинг машинки после обрывков чужого заднего и всплеска её дальномера за 24 мс до пинга). +// Ложных захватов это не добавляет: хвост оборванного кадра (период фронтов 962 мкс, синхробиты ~1100) не проходит +// грубый фильтр периода преамбулы (2116…3270 мкс), а настоящая преамбула перезапускает кандидата по паузе > IR_timeout. +// После чистого конца кадра гвард остаётся: там он отсекает хвост синхробитов. +void IR_DecoderRaw::releasePreambleGuard(uint32_t tUs) +{ + prevRise = tUs - IR_timeout * 2U - 1U; // «тишина уже была»: (front.time - prevRise) > longSilence для следующего фронта } void IR_DecoderRaw::expirePreambleCandidate() diff --git a/IR_DecoderRaw.h b/IR_DecoderRaw.h index 4b12363..b3309e8 100644 --- a/IR_DecoderRaw.h +++ b/IR_DecoderRaw.h @@ -186,6 +186,7 @@ private: RxEndInfo rxEnd; void noteRxEnd(RxEndReason reason, uint32_t tUs); // терминал: фиксирует тип/длину/расчётный конец void abortFrame(uint32_t tUs); // немедленный сброс битого кадра (sync/длина/overflow) + void releasePreambleGuard(uint32_t tUs); // после abort: новый кандидат преамбулы без ожидания длинной тишины void expirePreambleCandidate(); // кандидат без фронтов дольше таймаута → Idle uint8_t preambleGoodPeriods = 0; uint16_t preambleMeanPeriod = 0;