Volver al inicio

Ingeniería inversa del protocolo de visualización de cola BCD4

El artículo describe la ingeniería inversa de un protocolo propietario de visualización de cola electrónica con codificación BCD4 y acarreo en el checksum. Se proporciona la estructura de paquetes, código de ensamblaje Python e integración en sistema web vía HTTP y puerto COM. Útil para trabajar con equipos legados.

BCD4 y acarreo en ingeniería inversa de visualización de cola
Advertisement 728x90

Ingeniería Inversa de un Protocolo de Visualización de Colas: Codificación BCD4 y Aritmética de Acarreo

Un ingeniero realizó ingeniería inversa de un protocolo propietario de visualización de colas sin documentación. El protocolo utiliza codificación BCD4, donde cada bit de datos ocupa un byte completo para inmunidad al ruido en líneas RS-232 largas a 1200 baudios. La estructura del paquete es de 33 bytes con un marcador, dígitos numéricos, número de ventana y campos de suma de verificación con acarreo.

BCD4: Codificación para Transmisión Confiable

El protocolo emplea un método de hardware para protección contra ruido: cada bit de un número (0–15) se codifica como un byte. 0x7F denota 1 (siete unos para un pulso claro), 0x00 denota 0. Esto expande un valor de 4 bits a 4 bytes.

Ejemplos de codificación:

Google AdInline article slot

| Número | Bits | Bytes BCD4 |

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

| 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 |

Implementación en Python:

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

La velocidad de 1200 baudios garantiza confiabilidad a costa del rendimiento.

Estructura del Paquete para Visualización de Números

Un paquete de 33 bytes muestra un número en una ventana:

  • Byte 0: 0x55 — marcador de inicio.
  • Bytes 1–4: cabecera de modo.
  • Bytes 5–8: BCD4(dígito de unidades).
  • Bytes 9–12: BCD4(dígito de decenas).
  • Bytes 13–16: BCD4(dígito de centenas).
  • Bytes 17–20: BCD4(dígito de unidades de ventana).
  • Bytes 21–24: BCD4(dígito de decenas de ventana).
  • Bytes 25–28: BCD4(c1) — parte inferior de la suma de verificación.
  • Bytes 29–32: BCD4(c2) — parte superior con acarreo.

Ejemplo para el número 487 en la ventana 19:

55 00 7F 00 00          # cabecera
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)
[campos de suma de verificación]

Cálculo de la Suma de Verificación con Acarreo

Los campos de suma de verificación c1 y c2 forman un valor de 8 bits con mecánica de acarreo:

  • Calcular raw_c1 como una combinación lineal de los campos del paquete.
  • Si raw_c1 >= 16: acarreo = 1, c1 = raw_c1 - 16.
  • De lo contrario: acarreo = 0, c1 = raw_c1.
  • c2 se calcula con acarreo de otros campos.

El acarreo ocurre con números como 80–90 dependiendo de la ventana. La IA (Claude) identificó el patrón a partir de 30 ejemplos de paquetes después de refinar la hipótesis: dos nibbles de 4 bits con acarreo como en aritmética.

Para el modo "todas las ventanas" (25 bytes), no hay acarreo y la fórmula es más simple.

El modo de programación de ventanas utiliza dos cadenas de acarreo independientes con multiplicación y constantes:

  • Cadena A: raw_A desde W_lo, carry_A = raw_A >> 4, field_A1 = raw_A & 0xF, field_A2 desde W_hi y carry_A.
  • Cadena B: similar para otra función lineal.

Ensamblado y Envío del Paquete

Función de ensamblado de paquetes:

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)

El paquete se envía a un puerto COM.

Integración en un Sistema Web

Un servidor Python acepta HTTP POST:

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

Analiza JSON, construye el paquete y escribe en el puerto. Un mecanismo de latido restaura la conexión:

  • Intervalo de 60 segundos cuando está OK.
  • 10 segundos en error.
def _heartbeat_loop():
    while True:
        ok = _try_register(...)
        was = _server_state['connected']
        _server_state['connected'] = ok
        if not was and ok:
            print("[OK] Conexión restaurada")
        elif was and not ok:
            print("[WARN] Conexión perdida")
        time.sleep(60 if ok else 10)

Conclusiones Clave

  • La codificación BCD4 expande 1 bit a un byte para inmunidad al ruido a 1200 baudios.
  • La suma de verificación utiliza acarreo entre nibbles c1/c2.
  • La ingeniería inversa con IA es efectiva con hipótesis precisas y ejemplos de paquetes.
  • El servidor permite integración fluida de equipos heredados con la web.
  • Protocolo: 33 bytes, marcador 0x55, dígitos + ventana + suma de verificación.

— Editorial Team

Advertisement 728x90

Leer después