Files
ls2tp/docs/TP_FORMAT_NOTES.md

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

  1. Le terminateur/descripteur (0xE2+len pour len≤8, DC pour len=9 — formule exacte à confirmer pour len>8)
  2. L'encodage des instructions (opcodes + arguments) — c'est le verrou principal restant
  3. Le descripteur de position (UF/UT/config) — 4 octets, sens exact à décoder

⏭️ Prochaines étapes

  1. Caler le framing 8+1 de la zone instruction — retrouver l'offset de départ et l'intervalle exact des octets de contrôle (≥ 0x80)
  2. Décoder les terminaisons (FINE, CNT100, CNT50, CNT0) via jba_joint
  3. Construire la table complète des opcodes (J, L, C, CALL, IF, JMP, LBL, R[n]=, PR[n]=, UTOOL_NUM, END...)
  4. 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.