Préambule
La trame AX25 se termine par deux octets
destinés au contrôle de l'intégrité
de la trame après transmission.
Ces deux octets représentent le CRC (Cyclic Redundancy
Check) ou FCS (Frame-Check Sequence)
L'abondante documentation disponible sur Internet concernant
le calcul du FCS est souvent contradictoire et quand deux documents
décrivent la même méthode (la plupart du
temps de façon incomplète) il est fort probable
que l'un a copié sur l'autre...
Faute d'avoir pu retrouver la méthode qui permet de retrouver
le FCS transmis dans les trames entendues sur le réseau,
nous avons choisi arbitrairement la méthode décrite
ici. Nous remplacerons celle-ci par la bonne quand nous l'aurons
trouvée...
Méthode de construction des
deux octets du FCS
La méthode
répond à 3 questions :
- sur quelles données appliquer le calcul ?
- quelle est la formule de calcul ?
- comment sont transmis les deux octets ?
Sur quelles données appliquer
le calcul
Les
deux octets du FCS sont transmis en fin de trame mais on pourrait
fort bien le calculer à diverses étapes :
- chaine de caractères ASCII en clair avec, par exemple
le caractère 5 sous sa forme normale "00110101"
(Control = 0x03 et PID = 0xF0)
- caractères dont les bits ont été transposés,
le caractère 5 étant sous la forme "01010110"
(Control = Ox30 et PID = 0x0F)
- après l'opération de bourrage des zéros
Cette dernière option semblerait
la plus logique pour les raisons suivantes :
- le FCS tient compte de ces bits de bourrage
- les autres opérations de manipulation de bits ne l'affectent
pas
- comme il est transmis en dernier, il peut donc être calculé
au fur et à mesure de la transmission.
Mais le FCS lui-même peut prendre
une valeur qui inclut une suite de bits égale à
"111111" et être pris pour un flag. L'examen
des trames captées sur le réseau APRS montre bien
que les octets du FCS sont parfois "bourrés",
le calcul du FCS sera donc effectué juste avant l'opération
de "bit-stuffing".
Formule de calcul
Le principe est très simple, il
s'applique sur tous les octets de la trame sauf les deux octets
du FCS, bien entendu.
L'algorithme le plus court est celui qui décrit le calcul
bit à bit.
1) déclarer une variable CRC de type entier sur 4 octets
(int) et l'initialiser avec 0xFFFF
2) dans une boucle balayant chaque bit de la trame :
- lire le bit de poids faible de la variable CRC et le comparer
au bit de la trame
- si les deux bits sont différents, appliquer un OU exclusif
sur le contenu de la variable CRC avec la valeur 0x8408
- exécuter un décalage logique de 1 bit vers la
droite du contenu de CRC
3) Calculer le complément à 1 de la valeur de CRC
en fin de boucle
Voici un exemple en Java qui ne contient
aucune astuce de programmation. Ce n'est qu'un simple exemple
que chacun pourra améliorer.
La fonction crc16b(byte[]
data)prend un tableau
de bytes comme argument et retourne la valeur du FCS calculé.
Le tableau de bytes contient en fait les quelques centaines de
bits de la trame à raison d'un byte par élément
0 ou 1. Le dernier élément contient la valeur "2"
placée là après le remplissage du tableau
pour faciliter la sortie de la boucle de calcul.
public
static int crc16b(byte[] data) //
data est le tableau contenant tous les bits de la trame
{ int valCRC = 0xFFFF; // initialisation de la valeur du CRC
avec 0xFFFF
int bitShift=0;
int compteur=0;
do
{ bitShift=valCRC & 0x0001; // valeur du bit à supprimer
à droite
valCRC = (valCRC >>> 1); //décalage
à droite de 1 bit, remplissage à gauche avec un
0
if (data[compteur]!=bitShift)
{ valCRC = valCRC ^ 0x8408 ; //XOR de valCRC avec
0x8048
}
compteur++;
}
while (data[compteur]!=2); //
la valeur "2" a été placée précédemment
pour indiquer la fin du tableau
valCRC = ~valCRC; // complément à 1 bit à
bit (inversion)
return valCRC & 0xFFFF; //
retour
}
A la réception, il suffira de
refaire le calcul et de vérifier que les deux valeurs,
le FCS reçu et le FCS recalculé sont bien identiques
Transmission des deux octets du
FCS
La documentation est confuse. On peut
lire dans une spécification que l'octet de poids faible
est transmis en premier et le contraire dans une autre. Et une
troisième préconise d'inverser les bits.
Nous suivrons la spécification "AX.25 Link Access
Protocol for Amateur Packet Radio" de juillet 1998 qui indique
"The FCS field of an AX.25 frame is sent most-significant
bit first" et précise plus loin : "FCS
is transmitted bit 15 first."
Exemple : si la valeur du FCS est "0x7E02" le
premier octet à transmettre contiendra 0x7E.
Documentation
Sites
en français :
Contrôle
d'erreur (CRC) : une bonne initiation sur "Comment ça
marche"
Documents en anglais :
CRC_for_AX25.pdf
de Bill Newhall, KB2BRD. Exemple avec Matlab
1200 Baud Packet Radio
Details : site de N1VG. Enoncé du principe retenu
ici.
A Painless
guide to CRC error detection algorithms de Ross Williams
Cyclic Redundancy
Check de Enrico Marinoni
Optimized
CRC Calculation : un exemple en C++
How
to Send AX.25 UI Frames Using Inexpensive PIC Microprocessors
par John Hansen, W2FS
|