Saltar al contenido
Kira

· 3 min de lectura

El checksum que no era CRC: cómo decodifiqué el protocolo del JamJum JP-1

Bitácora de ingeniería inversa de un controlador MIDI: capturas USB, una hipótesis equivocada y la pieza que faltaba para que el aparato aceptara color arbitrario por pad.

#ingeniería inversa#midi#usb#python
Read this post in English

El JamJum JP-1 es un controlador MIDI de 16 pads RGB, 8 knobs y 6 botones de transporte. Funciona bien, pero su app oficial es limitada y el fabricante no publica el protocolo. Quería editarlo en lote, con mis propios efectos de luz, desde el navegador. Para eso había que aprender a hablarle.

Paso 1: escuchar la conversación

El aparato es USB-MIDI estándar, así que el tráfico se puede capturar con USBPcap y leer en Wireshark. La app oficial manda mensajes SysEx propietarios con esta forma:

F0 78 32 <comando de 3 bytes> <contenido> F7

El contenido no son bytes «normales». Es un flujo de bits de 7 bits por byte, LSB primero: de cada byte se toman sus 7 bits bajos y se concatenan. Por eso un campo puede empezar a la mitad de un byte y terminar en el siguiente. Antes de entender cualquier valor, hubo que escribir un decodificador de ese flujo.

Paso 2: cambiar una sola cosa a la vez

El método que funcionó fue el más aburrido: cambiar un parámetro en la app oficial, capturar, y comparar bit a bit contra la captura anterior. Así salió el mapa de cada pad: canal, tipo (nota, CC, programa), número y rango de velocidad, en registros de 32 bits.

Y en cada bloque, al final, dos bytes que cambiaban «sin razón»: el checksum.

Paso 3: la hipótesis equivocada

Un checksum de dos bytes que cambia con todo suena a CRC. Probé si el sistema era lineal sobre GF(2) —como un CRC— y la prueba dijo que sí. El problema: tenía muy pocas ecuaciones para tantas incógnitas, y con pocos datos casi cualquier modelo «encaja». La hipótesis era falsa y me costó varias pruebas en el aparato descubrirlo.

La lección quedó anotada en la bitácora del proyecto: una prueba de solvencia infradeterminada no demuestra nada.

Paso 4: sumas modulares

Al replantearlo como una suma modular ponderada, todo empezó a cerrar. El de los pads, por ejemplo:

checksum_pads.py
def checksum_pads(pads: list[dict]) -> tuple[int, int]:
s = sum(p["canal"] + 16 * p["tipo"] + p["nota"] + p["min"] + p["max"] for p in pads)
c = (510 - 2 * s) % 512
return c & 0x7F, (c >> 7) & 0x7F # bytes 76 y 77

Lo verifiqué contra los 63 bloques oficiales que tenía capturados: idénticos byte por byte. Luego cayeron los de botones (8175 − 32·Σ) mod 8192 y knobs (15456 − 32·Σ) mod 16384. Misma familia.

Paso 5: el color se resistió

Con el color pasó algo engañoso. Un modelo «uniforme» encajaba perfecto en mis primeras capturas… porque esas capturas no tenían suficiente variedad: el modelo encajaba por alias, no porque fuera correcto. En el aparato, fallaba.

La salida fue diseñar una captura nueva, pensada para romper el modelo: los 16 pads con colores independientes, brillos variados e índices distintos. Con esos datos, una búsqueda de la forma (K + w·Σ) mod M sobre varias definiciones de Σ encontró la respuesta exacta:

checksum_color.py
def checksum_color(canales: list[int], indice_pad: int) -> tuple[int, int]:
"""canales: los 48 valores de 8 bits (16 pads × G, R, B)."""
s = sum(canales) + indice_pad # ← la pieza que faltaba
chk = (2720 - 32 * s) % 8192
return chk & 0x7F, (chk >> 7) & 0x7F # bytes 64 y 65

La pieza que faltaba era sumar el índice del pad. Sin él, dos bloques con los mismos colores pero distinto índice daban el mismo resultado, y eso era imposible de conciliar con las capturas.

Resultado: 384 de 384 bloques reproducidos byte por byte, y un arcoíris arbitrario —16 colores distintos generados por mi código— aceptado por el aparato.

Lo que me llevo

  1. Diseña la captura que puede tumbar tu hipótesis, no la que la confirma.
  2. Verifica en el hardware, no solo en la computadora. El aparato es el único juez.
  3. Prueba la capa que usa la persona. Validé el motor desde la consola y la interfaz tenía otro error; ahora pruebo de punta a punta.

Hoy la app (JamJum Studio, en Web MIDI) lee la configuración al conectar, edita pads, knobs, botones y color, y suma efectos de luz que la app oficial no tiene. El caso completo está en proyectos.