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;