mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-04-28 03:08:08 +00:00
fix msgTypeReceive and isReceive
This commit is contained in:
174
ir_protocol_gate_runs_sim.py
Normal file
174
ir_protocol_gate_runs_sim.py
Normal file
@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Симуляция логики IR_Encoder::buildGateRuns (IR-protocol) и утилиты CRC8.
|
||||
Запуск из корня репозитория: python docs/scripts/ir_protocol_gate_runs_sim.py
|
||||
Или: python ir_protocol_gate_runs_sim.py из каталога scripts/
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
# --- IR_config.h (фрагмент) ---
|
||||
bitPauseTakts = 12
|
||||
bitActiveTakts = 25
|
||||
preambPulse = 3
|
||||
syncBits = 3
|
||||
bitPerByte = 8
|
||||
preambToggle = ((bitPauseTakts * 2 + bitActiveTakts) * 2 - 1)
|
||||
bitHigh = [(bitPauseTakts) * 2 - 1, (bitActiveTakts) * 2 - 1]
|
||||
bitLow = [(bitPauseTakts // 2 + bitActiveTakts) * 2 - 1, (bitPauseTakts) - 1]
|
||||
|
||||
preamb, data, sync, noSignal = 0, 1, 2, 3
|
||||
HIGH = True
|
||||
|
||||
|
||||
def crc8(data: bytes, start: int, end: int, poly: int) -> int:
|
||||
"""Как IR_FOX::crc8 в IR_config.cpp: [start, end)."""
|
||||
crc = 0xFF
|
||||
for i in range(start, end):
|
||||
crc ^= data[i]
|
||||
for _ in range(8):
|
||||
if (crc & 0x80) != 0:
|
||||
crc = ((crc << 1) ^ poly) & 0xFF
|
||||
else:
|
||||
crc = (crc << 1) & 0xFF
|
||||
return crc
|
||||
|
||||
|
||||
def crc_pair_over_wire(packet: bytes) -> tuple[int, int]:
|
||||
"""Два байта CRC как в IR_Encoder::sendDataFULL (poly1 старший, poly2 младший)."""
|
||||
ps = len(packet)
|
||||
if ps < 2:
|
||||
return 0, 0
|
||||
b1 = crc8(packet, 0, ps - 2, 0x31) & 0xFF
|
||||
b2 = crc8(packet, 0, ps - 1, 0x8C) & 0xFF
|
||||
return b1, b2
|
||||
|
||||
|
||||
# Как dataByteSizeMax в IR_config.h (msg+addr+addr+bytePerPack+crc)
|
||||
DATA_BYTE_SIZE_MAX = 1 + 2 + 2 + 31 + 2
|
||||
|
||||
|
||||
def build_gate_runs(packet: bytes):
|
||||
"""
|
||||
Повторяет IR_Encoder::buildGateRuns: список (gate: bool, lenTicks: int), сумма lenTicks = totalTicks DMA.
|
||||
Буфер дополняется нулями до dataByteSizeMax, как sendBufferLocal[dataByteSizeMax] в C++.
|
||||
"""
|
||||
send_len = len(packet)
|
||||
send_buf = bytearray(packet) + bytes(max(0, DATA_BYTE_SIZE_MAX - len(packet)))
|
||||
|
||||
toggle = preambToggle
|
||||
data_bit = bitPerByte - 1
|
||||
data_byte = 0
|
||||
preamb_front = preambPulse * 2 - 1
|
||||
data_seq = bitPerByte * 2
|
||||
sync_seq = syncBits * 2
|
||||
sync_last = False
|
||||
sig = preamb
|
||||
state = HIGH
|
||||
cur_seq = bitHigh
|
||||
|
||||
runs: list[tuple[bool, int]] = []
|
||||
outer_steps = 0
|
||||
|
||||
while True:
|
||||
outer_steps += 1
|
||||
gate = state
|
||||
run_len = toggle + 1 # как в C++: (uint16_t)toggleCounterLocal + 1U
|
||||
|
||||
if runs and runs[-1][0] == gate:
|
||||
g, ln = runs[-1]
|
||||
runs[-1] = (g, ln + run_len)
|
||||
else:
|
||||
runs.append((gate, run_len))
|
||||
|
||||
while True:
|
||||
if sig == noSignal:
|
||||
return runs, outer_steps
|
||||
|
||||
if sig == preamb:
|
||||
if preamb_front:
|
||||
preamb_front -= 1
|
||||
toggle = preambToggle
|
||||
break
|
||||
sig = data
|
||||
state = not False
|
||||
continue
|
||||
|
||||
if sig == data:
|
||||
if data_seq:
|
||||
if not (data_seq & 1):
|
||||
cur_seq = bitHigh if ((send_buf[data_byte] >> data_bit) & 1) else bitLow
|
||||
data_bit -= 1
|
||||
toggle = cur_seq[not state]
|
||||
data_seq -= 1
|
||||
break
|
||||
sync_last = send_buf[data_byte] & 1
|
||||
data_byte += 1
|
||||
data_bit = bitPerByte - 1
|
||||
data_seq = bitPerByte * 2
|
||||
sig = sync
|
||||
continue
|
||||
|
||||
if sig == sync:
|
||||
if sync_seq:
|
||||
if not (sync_seq & 1):
|
||||
if sync_seq == 2:
|
||||
cur_seq = bitLow if (send_buf[data_byte] & 0x80) else bitHigh
|
||||
else:
|
||||
cur_seq = bitLow if sync_last else bitHigh
|
||||
sync_last = not sync_last
|
||||
toggle = cur_seq[not state]
|
||||
sync_seq -= 1
|
||||
break
|
||||
sig = data
|
||||
sync_seq = syncBits * 2
|
||||
if data_byte >= send_len:
|
||||
sig = noSignal
|
||||
continue
|
||||
|
||||
return [], 0
|
||||
|
||||
state = not state
|
||||
|
||||
|
||||
def main() -> int:
|
||||
print("IR-protocol: preambToggle =", preambToggle)
|
||||
print()
|
||||
|
||||
# Пример из лога: 8-байтный эхо-пакет Version_Query (CRC OK на приёме)
|
||||
echo = bytes.fromhex("C8 FA 2A FD E8 5D AA B4")
|
||||
c1, c2 = crc_pair_over_wire(echo)
|
||||
print("8 байт (эхо): CRC вычисленный:", f"{c1:02X}", f"{c2:02X}", "| на проводе:", f"{echo[6]:02X}", f"{echo[7]:02X}")
|
||||
|
||||
runs8, steps8 = build_gate_runs(echo)
|
||||
total8 = sum(r[1] for r in runs8)
|
||||
print(" buildGateRuns: внешних шагов FSM =", steps8, ", totalTicks =", total8, ", число run-сегментов =", len(runs8))
|
||||
print()
|
||||
|
||||
# 31 байт из лога Frame reject (пример)
|
||||
reject = bytes.fromhex(
|
||||
"DF 00 00 FA 2A 5E 43 61 72 5F 76 34 2E 33 2E 38 5F 5B 31 32 4D 68 7A 5D 6B ED 1D 9A 53 96 62"
|
||||
)
|
||||
if len(reject) == 31:
|
||||
c1, c2 = crc_pair_over_wire(reject)
|
||||
print("31 байт (reject): CRC по телу 0..28 должен быть:", f"{c1:02X}", f"{c2:02X}", "| байты [29:31]:", f"{reject[29]:02X}", f"{reject[30]:02X}")
|
||||
print(" Совпадение с формулой:", c1 == reject[29] and c2 == reject[30])
|
||||
|
||||
runs31, steps31 = build_gate_runs(reject)
|
||||
total31 = sum(r[1] for r in runs31)
|
||||
print(" buildGateRuns: внешних шагов =", steps31, ", totalTicks =", total31, ", run-сегментов =", len(runs31))
|
||||
print()
|
||||
|
||||
# Связь totalTicks с моделью «N тиков на сегмент до шага FSM»
|
||||
# total_build = sum(toggle_i + 1); если бы было sum(toggle_i), разница = steps
|
||||
theoretical_isr_ticks = total31 - steps31
|
||||
print("Для 31-байт пакета: totalTicks (buildGateRuns) =", total31)
|
||||
print(" Если каждый внешний шаг даёт +1 к длине сегмента относительно ISR (runLen = toggle+1 vs toggle),")
|
||||
print(" оценка «ISR-тиков» как totalTicks - outer_steps =", theoretical_isr_ticks)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user