Inżynieria wsteczna protokołu tablicy kolejki elektronicznej: kodowanie BCD4 i arytmetyka przeniesienia
Inżynier przeanalizował zastrzeżony protokół tablicy kolejki elektronicznej bez dokumentacji. Protokół wykorzystuje kodowanie BCD4, gdzie każdy bit danych zajmuje cały bajt dla odporności na zakłócenia na długich liniach RS-232 przy 1200 bodach. Struktura pakietu to 33 bajty ze znacznikiem, cyframi liczby, numerem okienka i polami kontrolnymi z przeniesieniem.
BCD4: kodowanie dla niezawodnej transmisji
Protokół stosuje sprzętową metodę ochrony przed zakłóceniami: każdy bit liczby (0–15) jest kodowany bajtem. 0x7F oznacza 1 (siedem jedynek dla wyraźnego impulsu), 0x00 — 0. To rozciąga 4-bitową wartość do 4 bajtów.
Przykłady kodowania:
| Liczba | Bity | Bajty BCD4 |
|--------|--------|------------------|
| 0 | 0000 | 00 00 00 00 |
| 1 | 0001 | 7F 00 00 00 |
| 2 | 0010 | 00 7F 00 00 |
| 5 | 0101 | 7F 00 7F 00 |
| 9 | 1001 | 7F 00 00 7F |
| 12 | 1100 | 00 00 7F 7F |
Implementacja w Pythonie:
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
Prędkość 1200 bodów zapewnia niezawodność, kosztem przepustowości.
Struktura pakietu dla wyświetlania numeru
Pakiet o długości 33 bajtów do wyświetlenia liczby na okienku:
- Bajt 0:
0x55— znacznik startowy. - Bajty 1–4: nagłówek trybu.
- Bajty 5–8: BCD4(jedności liczby).
- Bajty 9–12: BCD4(dziesiątki liczby).
- Bajty 13–16: BCD4(setki liczby).
- Bajty 17–20: BCD4(jedności okienka).
- Bajty 21–24: BCD4(dziesiątki okienka).
- Bajty 25–28: BCD4(c1) — młodsza część sumy kontrolnej.
- Bajty 29–32: BCD4(c2) — starsza część z uwzględnieniem przeniesienia.
Przykład dla liczby 487 na okienku 19:
55 00 7F 00 00 # nagłówek
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)
[pola kontrolne]
Obliczanie sumy kontrolnej z przeniesieniem
Pola kontrolne c1 i c2 tworzą 8-bitową wartość z mechaniką przeniesienia:
- Obliczane jest raw_c1 jako liniowa kombinacja pól pakietu.
- Jeśli raw_c1 >= 16: carry = 1, c1 = raw_c1 - 16.
- W przeciwnym razie: carry = 0, c1 = raw_c1.
- c2 jest obliczane z udziałem carry z innych pól.
Przeniesienie występuje przy liczbach takich jak 80–90 w zależności od okienka. SI (Claude) wykryło wzór na podstawie 30 przykładów pakietów po doprecyzowaniu hipotezy: dwa 4-bitowe półbajty z przeniesieniem jak w arytmetyce.
Dla trybu "wszystkie okienka" (25 bajtów) przeniesienie nie występuje, formuła jest prostsza.
Tryb programowania okienka używa dwóch niezależnych łańcuchów przeniesienia z mnożeniem i stałymi:
- Łańcuch A: raw_A od W_lo, carry_A = raw_A >> 4, field_A1 = raw_A & 0xF, field_A2 od W_hi i carry_A.
- Łańcuch B: analogicznie dla innej funkcji liniowej.
Budowanie i wysyłanie pakietu
Funkcja budowania pakietu:
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)
Pakiet jest wysyłany do portu COM.
Integracja z systemem webowym
Serwer Python przyjmuje HTTP POST:
POST / {"window": 5, "ticket": "487"}
Parsuje JSON, buduje pakiet, zapisuje do portu. Mechanizm heartbeat przywraca połączenie:
- Interwał 60 sekund przy OK.
- 10 sekund przy błędzie.
def _heartbeat_loop():
while True:
ok = _try_register(...)
was = _server_state['connected']
_server_state['connected'] = ok
if not was and ok:
print("[OK] Połączenie przywrócone")
elif was and not ok:
print("[WARN] Połączenie utracone")
time.sleep(60 if ok else 10)
Co jest ważne
- Kodowanie BCD4 rozciąga 1 bit do bajta dla odporności na zakłócenia przy 1200 bodach.
- Suma kontrolna używa przeniesienia między półbajtami c1/c2.
- Inżynieria wsteczna z SI jest efektywna przy precyzyjnej hipotezie i przykładach pakietów.
- Serwer zapewnia płynną integrację starszego sprzętu z webem.
- Protokół: 33 bajty, znacznik 0x55, cyfry + okienko + suma kontrolna.
— Editorial Team
Brak komentarzy.