Files
IR-protocol/ref/IR_EDGE_TRACE_FORMAT.md
2026-04-02 17:25:10 +03:00

88 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Формат журнала фронтов ИК (`IR_EDGE_TRACE`)
Включается в `IR_config.h`: раскомментируйте `#define IR_EDGE_TRACE`.
Размер кольца задаётся `IR_EDGE_TRACE_CAPACITY` (по умолчанию 512 записей).
Память: примерно `IR_EDGE_TRACE_CAPACITY × 6` байт на экземпляр `IR_DecoderRaw`.
## Назначение
В ISR на каждый аппаратный фронт на линии приёмника пишется запись: абсолютное время `micros()`, уровень линии после фронта, флаги. Это **отдельное** кольцо от `subBuffer`: при переполнении `subBuffer` фронты в журнале всё равно сохраняются, пока не заполнится это кольцо.
При **передаче ИК по DMA** на STM32 важно, чтобы **прерывание приёма (EXTI)** имело **более высокий приоритет NVIC**, чем DMA канала передачи — иначе метки времени и сам поток фронтов в логе искажаются. См. **[`IR_DMA_ISR_signal_analysis.md`](../IR_DMA_ISR_signal_analysis.md)** (раздел 2.1).
## Вывод в Serial
При включённом `IR_EDGE_TRACE` протокол **сам** сбрасывает накопленные фронты в конце каждого `IR_DecoderRaw::tick()` (и на ветке «subBuffer пуст»): в цикле вызывается `edgeTraceFlushChunk(Serial, 48)`, пока в кольце есть записи.
Вручную тот же смысл: `edgeTraceFlushChunk(Print &out, maxRec)` печатает **ровно одну строку** (если есть что выгрузить; при пустом кольце выход без печати):
1. Символ перевода строки `\n` (отделяет блок от предыдущего вывода).
2. Литеральный префикс **`@IRF1v1:`** (удобно grep-ать; не используйте этот текст в других `Serial.print`, чтобы строки не сливались).
3. **Нижний регистр hex** без пробелов: полезная нагрузка бинарного блока ниже.
4. `\n` в конце.
Другой текст (например `IR raw:` из `IRDEBUG_SERIAL_PACK`) не содержит `@IRF1v1:`, поэтому визуально и по парсеру блоки разделимы.
Если авто-сброс в `tick()` отключён или нужен другой `Print`, вызывайте `edgeTraceFlushChunk` в цикле, пока возвращаемое значение > 0.
## Бинарная полезная нагрузка (до кодирования в hex)
Все многобайтовые целые — **little-endian**, порядок байт от младшего к старшему.
| Смещение | Размер | Поле |
|----------|--------|------|
| 0 | 1 | **meta** |
| 1 | 2 | **count** — число записей в этой строке (`uint16_t`) |
| 3 | `count × 6` | Массив записей |
### meta (байт)
| Бит | Значение |
|-----|----------|
| 0 | **overflow**: кольцо хотя бы раз переполнилось с момента последнего `edgeTraceClear()`; новые фронты терялись, пока не освободилось место. Сбрасывается только `edgeTraceClear()`. |
| 1 | **truncated**: после этой выгрузки в буфере ещё есть записи (chunk урезан лимитом `maxRec` или внутренним максимумом 64). |
Биты 27 зарезервированы (0).
### Одна запись (6 байт)
| Смещение в записи | Размер | Поле |
|-------------------|--------|------|
| 0 | 4 | **t_us** — значение `micros()` на момент фронта (`uint32_t`). При переполнении `micros()` (~70 мин) разницы между соседними записями всё ещё корректны, если обрабатывать как unsigned. |
| 4 | 1 | **level** — уровень входа приёмника после фронта: `0` = LOW, `1` = HIGH (как `port->IDR & mask` в ISR). |
| 5 | 1 | **flags** |
| | | бит 0 **SKIP_DECODE** (`IR_EDGE_TRACE_F_SKIP_DECODE`): фронт записан, но в `subBuffer` **не** попал, потому что был активен `isPairSending` (пара передаёт). Алгоритм декодирования этот фронт не видит. |
## Минимальный разбор (Python 3)
```python
import binascii, re
def parse_irf1_line(line: str):
m = re.search(r"@IRF1v1:([0-9a-f]+)\s*$", line.strip())
if not m:
return None
raw = binascii.unhexlify(m.group(1))
meta, cnt_lo, cnt_hi = raw[0], raw[1], raw[2]
count = cnt_lo | (cnt_hi << 8)
recs = []
p = 3
for _ in range(count):
t = raw[p] | (raw[p+1]<<8) | (raw[p+2]<<16) | (raw[p+3]<<24)
level, flags = raw[p+4], raw[p+5]
recs.append((t, level, flags))
p += 6
return {
"overflow": bool(meta & 1),
"truncated": bool(meta & 2),
"count": count,
"records": recs,
}
```
## Рекомендации по съёму
- При очень плотном потоке фронтов кольцо всё же может переполниться до следующего `tick()` — увеличьте `IR_EDGE_TRACE_CAPACITY` или уменьшите нагрузку на ISR.
- Для «чистого» лога отключите или сильно урежьте `IRDEBUG_SERIAL_PACK`, иначе объём Serial будет очень большим.
- Для полного сброса состояния перед тестом: `edgeTraceClear()`.