Zpět na domů

Reverz protokolu tabule fronty BCD4

Článek popisuje reverz proprietárního protokolu tabule elektronické fronty s kódováním BCD4 a carry v kontrolní součtě. Uvedena struktura paketů, Python-kód sestavení a integrace do webové systému přes HTTP a COM-port. Užitečné pro práci s legacy zařízením.

BCD4 a carry v reverzi tabule fronty
Advertisement 728x90

Reverzní inženýrství protokolu pro zobrazovač elektronické fronty: BCD4 kódování a přenosová aritmetika

Inženýr rozebral proprietární protokol zobrazovače elektronické fronty bez dokumentace. Protokol používá BCD4 kódování, kde každý bit dat zabírá celý bajt pro odolnost proti rušení na dlouhých linkách RS-232 při 1200 bodech. Struktura paketu je 33 bajtů s markerem, číslicemi čísla, číslem okna a kontrolními poli s přenosem.

BCD4: kódování pro spolehlivý přenos

Protokol využívá hardwarovou metodu ochrany proti rušení: každý bit čísla (0–15) je zakódován bajtem. 0x7F označuje 1 (sedm jedniček pro jasný impuls), 0x00 — 0. Tím se 4bitová hodnota roztaží na 4 bajty.

Příklady kódování:

Google AdInline article slot

| Číslo | Bity | BCD4-bajty |

|-------|--------|------------------|

| 0 | 0000 | 00 00 00 00 |

Google AdInline article slot

| 1 | 0001 | 7F 00 00 00 |

| 2 | 0010 | 00 7F 00 00 |

| 5 | 0101 | 7F 00 7F 00 |

Google AdInline article slot

| 9 | 1001 | 7F 00 00 7F |

| 12 | 1100 | 00 00 7F 7F |

Implementace v Pythonu:

def _bcd4(value: int) -> bytes:
    return bytes([0x7F if value & (1 << i) else 0x00 for i in range(4)])

print(_bcd4(5).hex(' '))  # 7f 00 7f 00
print(_bcd4(9).hex(' '))  # 7f 00 00 7f

Rychlost 1200 bodů zajišťuje spolehlivost na úkor propustnosti.

Struktura paketu pro zobrazení čísla

Paket o délce 33 bajtů pro zobrazení čísla na okně:

  • Bajt 0: 0x55 — startovní marker.
  • Bajty 1–4: hlavička režimu.
  • Bajty 5–8: BCD4(jednotky čísla).
  • Bajty 9–12: BCD4(desítky čísla).
  • Bajty 13–16: BCD4(stovky čísla).
  • Bajty 17–20: BCD4(jednotky okna).
  • Bajty 21–24: BCD4(desítky okna).
  • Bajty 25–28: BCD4(c1) — nižší část kontrolního součtu.
  • Bajty 29–32: BCD4(c2) — vyšší část s přihlédnutím k přenosu.

Příklad pro číslo 487 na okně 19:

55 00 7F 00 00          # hlavička
7F 7F 7F 00             # BCD4(7)
00 00 00 7F             # BCD4(8)
00 00 7F 00             # BCD4(4)
7F 00 00 7F             # BCD4(9)
7F 00 00 00             # BCD4(1)
[kontrolní pole]

Výpočet kontrolního součtu s přenosem

Kontrolní pole c1 a c2 tvoří 8bitovou hodnotu s přenosovou mechanikou:

  • Vypočte se raw_c1 jako lineární kombinace polí paketu.
  • Pokud raw_c1 >= 16: přenos = 1, c1 = raw_c1 - 16.
  • Jinak: přenos = 0, c1 = raw_c1.
  • c2 se vypočte s účastí přenosu z jiných polí.

Přenos se projevuje na číslech jako 80–90 v závislosti na okně. AI (Claude) odhalil zákonitost na 30 příkladech paketů po upřesnění hypotézy: dva 4bitové nibbly s přenosem jako v aritmetice.

Pro režim "všechna okna" (25 bajtů) přenos chybí, vzorec je jednodušší.

Režim programování okna využívá dvě nezávislé přenosové řetězce s násobením a konstantami:

  • Řetězec A: raw_A od W_lo, přenos_A = raw_A >> 4, pole_A1 = raw_A & 0xF, pole_A2 od W_hi a přenos_A.
  • Řetězec B: podobně pro jinou lineární funkci.

Sestavení a odeslání paketu

Funkce sestavení paketu:

def build_window_packet(window: int, number: int) -> bytes:
    d1 = number % 10
    d2 = (number // 10) % 10
    d3 = (number // 100) % 10
    w_lo = window % 10
    w_hi = window // 10

    c1, c2 = _checksum(d1, d2, d3, w_lo, w_hi)

    packet = bytearray(b'\x55\x00\x7F\x00\x00')
    packet += _bcd4(d1) + _bcd4(d2) + _bcd4(d3)
    packet += _bcd4(w_lo) + _bcd4(w_hi)
    packet += _bcd4(c1) + _bcd4(c2)

    assert len(packet) == 33
    return bytes(packet)

Paket se odešle do COM portu.

Integrace do webového systému

Python server přijímá HTTP POST:

POST / {"window": 5, "ticket": "487"}

Rozebírá JSON, sestaví paket, zapíše do portu. Heartbeat mechanismus obnovuje spojení:

  • 60 sekund interval při OK.
  • 10 sekund při chybě.
def _heartbeat_loop():
    while True:
        ok = _try_register(...)
        was = _server_state['connected']
        _server_state['connected'] = ok
        if not was and ok:
            print("[OK] Spojení obnoveno")
        elif was and not ok:
            print("[WARN] Spojení ztraceno")
        time.sleep(60 if ok else 10)

Co je důležité

  • BCD4 kódování roztahuje 1 bit na bajt pro odolnost proti rušení na 1200 bodech.
  • Kontrolní součet využívá přenos mezi nibbly c1/c2.
  • Reverzní inženýrství s AI je efektivní při přesné hypotéze a příkladech paketů.
  • Server zajišťuje bezproblémovou integraci zastaralého zařízení s webem.
  • Protokol: 33 bajtů, marker 0x55, číslice + okno + checksum.

— Editorial Team

Advertisement 728x90

Číst dál