feat(rx): always-on счётчики причин RX-событий (rxReasonCnt) + RXSTAT-сводка

rxBriefLog теперь безусловен: ВСЕГДА инкрементирует rxReasonCnt[reason]
(наблюдаемость по контракту живучести — работает в проде без печати),
печать события — только при IR_RX_BRIEF_LOG. 14 точек вызова развёрнуты
из-под #if (Glitch/Timing/Preamble/Sync/BufOverflow/Timeout/Crc/Ok +
pulse-filter пути); ISR-агрегатные MuteBegin/End/RawOverflow остаются
только при логе (их флаш живёт в brief-механике). Публичное API:
rxReasonCounters() / rxReasonCountersClear() / printRxReasonStats(Print&)
-> 'RXSTAT,GLITCH=..,TIME=..,...,OK=..'.
Компил-чек: LaserTestCheck (G4, флаг выкл) и Plan_B (F4, флаг вкл) — чисто.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-28 23:05:50 +03:00
parent 5bcaf4092a
commit 08ea71eb5e
2 changed files with 41 additions and 29 deletions

View File

@ -65,6 +65,14 @@ public:
uint16_t edgeTraceFlushChunk(Print &out, uint16_t maxRec = 48);
#endif
/// Always-on счётчики RX-событий по причинам (см. RxBriefReason: 6=Glitch,
/// 7=Timing, 8=Preamble, 9=Sync, 10=BufOverflow, 11=Timeout, 12=Crc, 13=Ok).
/// MuteBegin/End и RawOverflow(1..3) тикают только при IR_RX_BRIEF_LOG (ISR-агрегат).
const uint16_t *rxReasonCounters() const { return rxReasonCnt; }
void rxReasonCountersClear() { for (uint8_t i = 0; i < 14; i++) rxReasonCnt[i] = 0; }
/// Однострочная сводка: "RXSTAT,GLITCH=..,TIME=..,PREAMB=..,SYNC=..,BUF=..,TIMEOUT=..,CRC=..,OK=.."
void printRxReasonStats(Print &out) const;
/// Кадр собран по длине из заголовка, но CRC не сошёлся — один раз можно прочитать копию сырых байтов.
bool availableReject();
uint8_t getRejectSize() const { return rejectPackSize; }
@ -235,9 +243,13 @@ bool isReciveRaw = false;
/// @return Результат
uint16_t ceil_div(uint16_t val, uint16_t divider);
// rxBriefLog безусловен: ВСЕГДА инкрементирует rxReasonCnt[reason]
// (always-on наблюдаемость по контракту живучести), печать события —
// только при IR_RX_BRIEF_LOG. Вызовы в местах отказов тоже безусловны.
void rxBriefLog(RxBriefReason reason, uint16_t a = 0, uint16_t b = 0, uint32_t tUs = 0);
uint16_t rxReasonCnt[14] = {}; // индекс = (uint8_t)RxBriefReason, 1..13
#if IR_RX_BRIEF_LOG
static const __FlashStringHelper *rxBriefReasonTag(RxBriefReason reason);
void rxBriefLog(RxBriefReason reason, uint16_t a = 0, uint16_t b = 0, uint32_t tUs = 0);
void rxBriefNoteMuteBlockedIsr(uint32_t tUs);
void rxBriefNoteRawOverflowIsr(uint32_t tUs);
void rxBriefFlushDeferredIsrLogs();