5.2 KiB
Analyse du format binaire TP Fanuc — Rétro-ingénierie (Tier 1)
Basé sur 6 paires LS/TP fournies par l'utilisateur (R-30iB Mate Plus, V9.x). Fichiers : jba_empty, jba_movj, jba_moovl, jba_movc, jba_joint, jba_cart.
✅ FAITS CONFIRMÉS (paires propres de l'utilisateur)
1. Magic signature
FE EF 00 01
Commune aux 6 fichiers. Signature du format TP Fanuc.
2. Structure du header (13 octets fixes)
| Offset | Taille | Champ | Valeurs observées |
|---|---|---|---|
| 0x00 | 2 | Magic | FE EF |
| 0x02 | 2 | Version | 00 01 |
| 0x04 | 4 | Champ taille | 00 00 XX XX |
| 0x08 | 1 | Séparateur | FF |
| 0x09 | 2 | Constante | 00 00 |
| 0x0B | 1 | Groupe/flag | 01 ou 03 |
| 0x0C | 1 | Constante | 00 |
| 0x0D+ | — | Nom | encodé |
3. ENCODAGE DES POSITIONS — DÉCOUVERTE MAJEURE
Les positions sont stockées en float32 big-endian, avec des octets de contrôle insérés tous les 9 octets (8 données + 1 contrôle).
Positions articulaires (joint)
- 6 valeurs J1-J6 en RADIANS (pas en degrés !)
- Structure :
[4 octets J1][contrôle][8 octets J2J3][contrôle][8 octets J4J5][contrôle][J6...]
Décodage validé (jba_joint.tp, P[1]) :
J1 = 26.565° (0.4636 rad) ✓
J2 = 46.572° (0.8128 rad) ✓
J3 = -61.774° (-1.0782 rad) ✓
J4 = -30.233° (-0.5277 rad) ✓
J5 = -100.390° (-1.7521 rad) ✓
J6 = -9.782° (-0.1707 rad) ✓
Positions cartésiennes
- X, Y, Z en mm (float32 BE)
- W, P, R en degrés (float32 BE)
- Préfixe de 2 octets avant les données
Décodage validé (jba_movj.tp, P[1]) :
X = 459.635 mm ✓
Y = 188.266 mm ✓
Z = -104.044 mm ✓
W = 104.105 deg ✓
P = 4.296 deg ✓
R = -93.058 deg ✓
4. Schéma des octets de contrôle
Les données (texte ET binaire) sont stockées en groupes de 8 octets suivis
d'un octet de contrôle (≥ 0x80). Le schéma est [8 octets][1 contrôle] répété,
avec un préfixe de longueur variable au début de chaque champ.
Exemple — nom "JBA_EMPTY" (9 chars) :
"JBA_" + 9F + "EMPTY" + DC
[4 chars][contrôle][5 chars][contrôle]
5. Champ taille (0x04-0x07) vs PROG_SIZE
| Fichier | Size field | PROG_SIZE (LS) | Taille TP |
|---|---|---|---|
| jba_empty | 0x0086 (134) | 132 | 80 |
| jba_movj | 0x00A0 (160) | 453 | 129 |
| jba_moovl | 0x00B8 (184) | 453 | 134 |
| jba_movc | 0x00D7 (215) | 518 | 182 |
| jba_joint | 0x019A (410) | 734 | 245 |
| jba_cart | 0x01AD (429) | 800 | 277 |
→ Pour le programme vide, size field ≈ PROG_SIZE. Pour les autres, le size field est plus petit (taille compressée de la partie instruction).
🔬 Outils développés
tools/tp_parse.py— décode le header + nom (validé sur 6 fichiers)tools/tp_positions.py— décode les positions (joint en radians, cart en mm/deg)tools/tp_dump.py— hex dump + analyse structurelle
🔑 DÉCOUVERTE MAJEURE : framing 8+1 = bitmask de longueur
L'octet de contrôle est un bitmask
L'octet de contrôle inséré dans le flux vaut :
contrôle = 0xFF ^ (1 << R)
où R = nombre d'octets valides dans le groupe (0-7). Le bit R (depuis le
LSB) mis à 0 marque « R octets valides, puis fin ». 0xFF (R=8) = groupe
plein, continuation.
Vérifié sur le corpus (noms) :
| Longueur nom | R (reste) | Contrôle | Terminateur |
|---|---|---|---|
| 4 | 0 | FE |
E6 |
| 5 | 1 | FD |
E7 |
| 6 | 2 | FB |
E8 |
| 7 | 3 | F7 |
E9 |
| 8 | 4 | EF |
EA |
| 9 | 5 | 9F |
DC |
| 11 | 7 | 7F |
DC |
| 12 | 8 | FF |
variable |
Formule terminateur (nom ≤ 8 chars) : 0xE2 + len.
Nom encodé = [4 chars][contrôle][chars restants][terminateur].
Framing des données (positions)
Le flux binaire est découpé en groupes de 8 octets, chaque groupe suivi d'un octet de contrôle. Les contrôles coupent les float32 en deux.
Décodage validé (jba_movj2, X=500) :
descripteur = 20 12 00 02
X=500.000 Y=188.266 Z=-104.044 W=104.105 P=4.296 R=-93.058 ✓
Pourquoi le diff cascade
Changer une coordonnée ou la terminaison décale le framing (la longueur des données change → les octets de contrôle changent → tout le flux se décale). C'est la signature observée sur les paires minimales (104 octets modifiés pour un seul changement de X).
⚠️ Reste à casser
- Le terminateur/descripteur (0xE2+len pour len≤8, DC pour len=9 — formule exacte à confirmer pour len>8)
- L'encodage des instructions (opcodes + arguments) — c'est le verrou principal restant
- Le descripteur de position (UF/UT/config) — 4 octets, sens exact à décoder
⏭️ Prochaines étapes
- Caler le framing
8+1de la zone instruction — retrouver l'offset de départ et l'intervalle exact des octets de contrôle (≥ 0x80) - Décoder les terminaisons (FINE, CNT100, CNT50, CNT0) via jba_joint
- Construire la table complète des opcodes (J, L, C, CALL, IF, JMP, LBL, R[n]=, PR[n]=, UTOOL_NUM, END...)
- Tester à l'aveugle : convertir un LS du corpus et comparer au TP réel
📦 Fichiers
Voir tests/fixtures/pairs/ pour les paires Tier 1 de l'utilisateur.