Analyser et lire le cadre de données en C?

J’écris un programme qui lit les données du port série sous Linux. Les données sont envoyées par un autre appareil avec le format de trame suivant:

|start | Command | Data | CRC | End | |0x02 | 0x41 | (0-127 octets) | | 0x03| ---------------------------------------------------- 

Le champ de données contient 127 octets comme indiqué et l’octet 1, 2 contient un type de données; l’octet 3,4 contient une autre donnée. J’ai besoin d’obtenir ces données

Je sais comment écrire et lire des données vers et depuis un port série sous Linux, mais c’est juste pour écrire et lire une chaîne simple (comme “ABD”)

Mon problème est que je ne sais pas comment parsingr le bloc de données formaté comme ci-dessus pour pouvoir:

  • obtenir les données en octet 1,2 dans le champ de données
  • obtenir les données en octet 3,4 dans le champ de données
  • récupère la valeur dans le champ CRC pour vérifier la cohérence des données

Voici un exemple de code permettant de lire et d’écrire une chaîne simple depuis et vers un port série sous Linux:

 int writeport(int fd, char *chars) { int len = strlen(chars); chars[len] = 0x0d; // stick a  after the command chars[len+1] = 0x00; // terminate the ssortingng properly int n = write(fd, chars, strlen(chars)); if (n < 0) { fputs("write failed!\n", stderr); return 0; } return 1; } int readport(int fd, char *result) { int iIn = read(fd, result, 254); result[iIn-1] = 0x00; if (iIn < 0) { if (errno == EAGAIN) { printf("SERIAL EAGAIN ERROR\n"); return 0; } else { printf("SERIAL read error %d %s\n", errno, strerror(errno)); return 0; } } return 1; } 

Est-ce que quelqu’un a des idées, s’il vous plaît?

result est un tableau de caractères d’une largeur d’un octet.

lire octet n utilisation:

 char octet_n = result[n]; 

Donc, pour faire ce que vous voulez, il vous faut:

 // skip the start and command fields char *data_field = result + 2; int octet_1_2 = data_field[1] | (data_field[2] << 8); int octet_3_4 = data_field[3] | (data_field[4] << 8); // crc is at byte 128 + 2 = 130 int crc = result[130]; 

Edit : Une explication pour cette ligne:

 int octet_1_2 = data_field[1] | (data_field[2] << 8); 

Vous voulez lire deux octets consécutifs dans un mot de 16 bits:

  1 bits 5 8 7 0 -------------------- octet_1_2 = | octet 2 | octet 1| -------------------- 

Donc, vous voulez prendre les bits 7: 0 de l'octet 1 et les mettre dans les bits 7: 0 de l' octet_1_2 :

 octet_1_2 = data_field[1]; 

Ensuite, vous voulez prendre les bits 7: 0 de l'octet 2 et les mettre dans les bits 15: 8 de l' octet_1_2 . Vous faites cela en décalant l'octet 2 à 8 bits vers la gauche et en octet_1_2 le résultat en octet_1_2 :

 octet_1_2 |= data_field[2] << 8; 

Ces deux lignes peuvent être fusionnées en une seule comme je l’ai fait précédemment.

La meilleure chose à lire des données formatées en C est de lire une structure. Étant donné le format du cadre que vous avez, je ferais ce qui suit.

 typedef struct special_data { char first_data[2]; char second data[2]; } special_data_t; union data_u { special_data_t my_special_data; char whole_data[128]; }; typedef struct data_frame { unsigned char start; unsigned char cmd; union data_u data; unsigned char crc; unsigned char end; } data_frame_t; void func_read(int fd) { data_frame_t my_data; if (read(fd, &my_data, sizeof(my_data)) != -1) { // Do something } return; } 

De cette façon, vous pouvez accéder aux données dont vous avez besoin via les champs de structure. La première structure et l’union ne sont que des aides pour accéder aux octets dont vous avez besoin dans le champ de données du cadre.