# IR RX Brief Log

Краткий лог включается через:

```cpp
#define IR_RX_BRIEF_LOG 1
#define IR_RX_BRIEF_LOG_REJECT_ONLY 1 // только отклонённые/ошибочные события
```

Лог печатается короткими строками вида:

```text
IRRX t=1234567 rsn=CRC len=25 err=3
IRRX t=1234000 rsn=MUTE_BEGIN
IRRX t=1234988 rsn=MUTE_END cnt=42
```

Где:

- `t` — uptime МК в `micros()`
- `rsn` — краткий код причины
- остальные поля зависят от причины

## Коды `rsn`

| Код | Смысл | Типичные поля |
|-----|-------|---------------|
| `MUTE_BEGIN` | Началось окно mute: RX временно игнорирует вход, пока активен связанный TX | - |
| `MUTE_END` | Окно mute завершилось; `cnt` показывает число заблокированных фронтов за всё окно | `cnt` |
| `QRAW` | Потеря фронтов из-за переполнения сырой очереди `subBuffer` | `cnt` |
| `QFLT` | Потеря фронтов из-за переполнения очереди после входного фильтра | `total` |
| `HOLD` | Переполнен holdback фильтра до выпуска фронтов | `total` |
| `GLITCH` | Фронт/пара фронтов отброшены как глитч | `total` |
| `TIME` | Плохой тайминг фронтов/битов, кадр не может нормально разбираться | `rp`, `hp` |
| `PREAMB` | Кандидат преамбулы не залочился или был перезапущен | `good`, `per` |
| `SYNC` | Ошибка sync-бита привела к reject кадра | `err` |
| `BUF` | Переполнен битовый буфер кадра | `bits` |
| `TIMEOUT` | Кадр оборвался по таймауту до завершения; после записи в лог вызываются `isReciveRaw=false` и `firstRX()` (полный сброс декодера) | `bits`, `exp` |
| `CRC` | Кадр дошёл до конца по длине, но CRC не сошёлся | `len`, `err` |
| `OK` | Кадр успешно распознан | `len`, `err` |

## Поля

- `cnt` — число событий/фронтов, накопленных за окно или пакетную группу
- `total` — накопленный счётчик отбраковок данного типа
- `rp` — `risePeriod`
- `hp` — `highTime`
- `good` — число подряд подходящих периодов преамбулы перед срывом
- `per` — период преамбулы/кандидата
- `err` — суммарные ошибки `lowSignal + highSignal + other` либо счётчик sync-ошибок
- `bits` — сколько data-бит успело накопиться
- `exp` — ожидаемая длина кадра из первого байта, если уже известна
- `len` — полная длина кадра в байтах

## Когда смотреть подробный debug

- `listenStart` / `checkTimeout` — в конце обработки фронта (`END:`) и во ветке «нет фронта» в `tick()`; не в начале до `pop`, иначе после таймаута `lastEdgeTime` расходится с метками ISR из очереди → ложные `TIMEOUT` (`bits=0`).
- Пока в `subBuffer` или в hold фильтра есть необработанные фронты, таймаут по `micros() - lastEdgeTime` **не оценивается** (`rxTimeoutPipelineBusy`): иначе при хвосте очереди «тихая пауза» считается слишком длинной и снова ложный `TIMEOUT`.
- Если нужен полный поток битов и sync: включать `IRDEBUG_SERIAL_PACK`
- Если нужно понять, какие именно фронты пришли в ISR: включать `IR_EDGE_TRACE`
- `IR_RX_BRIEF_LOG` нужен как короткий always-on-ish индикатор сути проблемы, без длинного дампа
- `IR_RX_BRIEF_LOG_REJECT_ONLY=1` скрывает `OK` и `PREAMB`, оставляя только отклонения/ошибки
