Code Correcteur d'Erreur |
Je me suis donc lancé dans l'exercice. Voici donc l'interface de notre application WinForm :
WinForm C# de Calcul du CRC d'une trame (Requête) |
Au delà d'implémenter et de valider l'algorithme de calcul du CRC sur 16 bits d'une trame par exemple de protocole ModBus, cet exemple est intéressant à plusieurs titres :
- manipulation des strings en chars et conversion en byte[] et réciproquement
- filtrage des caractères dans une TextBox pour n'obtenir que les caractères hexadécimaux
Petit rappel rapide sur le calcul hexadécimal
En binaire, sur 4 bits, on peut compter jusqu'à (1111) binaire = (15) décimal = (F) hexadécimalSur un octet (8 bits = 1 Byte = 2 fois 4 bits) (1111 1111) binaire = (255) décimal = (FF) hexadécimal
Notation : binaire/hexadécimale :
1 = 1
11 = 3
111 = 7
1000 = 8
1010 = A
1011 = B
1100 = C
1101 = D
1110 = E
1111 = F
Sur un octet : FF que l'on notera (0xFF) hexadécimal = (255) décimal
Donc dans notre TextBox, on ne pourra entrer qu'un nombre pair de caractères correspondant à un nombre d'octets de la trame (ou Requête) en notation hexadécimal.
Algorithme du CRC 16 en C#
En C#, c'est à dire très proche du C ou du C++, j'écris l'algorithme de la façon suivante :int CalculCRC16(byte[] octets)
{
int crc = 0xFFFF;
int i, done = 0;
byte todo;
int nb = octets.Length;
if (nb >= 0)
{do
{
todo = octets[done];
crc ^= todo;
for (i = 0; i < 8; i++)
{
if (crc % 2 != 0)
{
crc = (crc >> 1) ^ 0xA001;
}
else
{
crc = crc >> 1;
}
}
done++;
} while (done < nb);
}
return crc;
}Afin d'utiliser les opérateurs de l'algèbre de bool :
^ : XOR ou OU exclusif
>> 1 : décalage à droite de 1 bit
l'algorithme prend en entré un tableau de byte : byte[] et retourne le CRC en int sur 16 bits.
Conversion d'une string en byte[]
Mon TextBox possède une propriété Text que je transforme en byte[] grâce à la fonction :static public byte[] StringHexaToByteArray(string str)
{
char[] s = str.ToCharArray();
byte[] b = new byte[s.Length/2];
int oct = 0;
for (int i = 0; i < s.Length/2; i++){
string octet = string.Concat(s[oct], s[oct + 1]);
oct = oct + 2;
int hexa = int.Parse(octet, System.Globalization.NumberStyles.HexNumber);
b[i] = (byte)hexa;
}
return b;
}On voit ici apparaître le faite qu'un byte est une paire de caractères de la chaîne str passée en paramètre c'est à dire la string TextBox.Text.
On note au passage une instruction bien sympa qui permet d'afficher un int en hexa :
string hexa = crc.ToString("X");
Simple, non ?
Filtrage des caractères non hexadécimaux
En ce qui concerne les caractères tapés au clavier le filtrage se fait dans la fonction :private void textBoxRequete_KeyPress(object sender, KeyPressEventArgs e)
{
char [] _hexa = {'A','B','C','D','E','F'};
List<char> hexa = new List<char>(_hexa);
if (char.IsLower(e.KeyChar))
{e.KeyChar = char.ToUpper(e.KeyChar);
}
if (char.IsLetterOrDigit(e.KeyChar) == false && char.IsControl(e.KeyChar) == false)
{
e.Handled = true;
}
if (char.IsLetter(e.KeyChar) == true && hexa.Contains(e.KeyChar) == false)
{e.Handled = true;
}
}
La bibliothèque de fonctions static de char ne possède pas de fonction IsHexa, on est donc obligé d'y palier en ajoutant un petit traitement de List<T>.
Cette fonction est câblée sur le KeyPressEventHandler mais cela ne suffit pas car l'utilisateur peut encore copier/coller une chaîne de texte dans la TextBox. On cablera donc sur EventHandler la fonction :
private void textBoxRequete_TextChanged(object sender, EventArgs e)
{
char[] _hexa = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
List<char> hexa = new List<char>(_hexa);
string filter = string.Empty;
char f;foreach (char c in textBoxRequete.Text)
{
f = char.ToUpper(c);
if (hexa.Contains(f))
{
filter += f;
}
}
textBoxRequete.Text = filter;
}
Pour les explications du code s'est fini ! Et pour le reste c'est de la tambouille de programmeur.
Quelques exemples de validation :
CRC16(0x00) = 0x40BF
Calcul du CRC de la trame 0x00 |
CRC16(0x02062329000D) = 0x7092
Donc pour vérifier l'implémentation (valider) :
Donc pour vérifier l'implémentation (valider) :
Calcul du CRC de la trame 0x02062329000D |
On peut penser que l'implémentation de notre algorithme est correcte.
Bibliographie CRC
Pour optimiser cet algo il faut précalculer des tables dont certaine exeplications se trouvent ici :
Et sur ce site bien plus que le calcul de CRC :
Download source code in C#
Requirements :
- Visual Studio 2010
- Langage C#