6.0 KiB
Формат журнала фронтов ИК (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 (раздел 2.1).
Вывод в Serial
При включённом IR_EDGE_TRACE протокол сам сбрасывает накопленные фронты в конце каждого IR_DecoderRaw::tick() (и на ветке «subBuffer пуст»): в цикле вызывается edgeTraceFlushChunk(Serial, 48), пока в кольце есть записи.
Вручную тот же смысл: edgeTraceFlushChunk(Print &out, maxRec) печатает ровно одну строку (если есть что выгрузить; при пустом кольце выход без печати):
- Символ перевода строки
\n(отделяет блок от предыдущего вывода). - Литеральный префикс
@IRF1v1:(удобно grep-ать; не используйте этот текст в другихSerial.print, чтобы строки не сливались). - Нижний регистр hex без пробелов: полезная нагрузка бинарного блока ниже.
\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). |
Биты 2–7 зарезервированы (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)
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().