Toutes les trames suivent un format bien spécifique :
| Champ | Taille (octets) | Longueur totale (octets) | Description |
|---|---|---|---|
| SOH | 1 | 1 | Début de la trame (0x01) |
| LEN | 1 | 2 | Longueur de la trame |
| ~LEN | 1 | 3 | Négation de LEN |
| ADDR_RECV | 1 | 4 | Adresse du module receveur |
| ADDR_EMIT | 1 | 5 | Adresse du module emetteur |
| FCT_CODE | 1 | 6 | Code fonction |
| ID | 1 | 7 | Identifiant de la trame |
| CRC_HEADER | 2 | 9 | Checksum des octets 0 à 6 |
| DATA | n | 9+n | Données |
| CRC_DATA | 2 | 11+n | Checksum des octets 9 à n+8 |
Plusieurs validation sont effectuées lors de la réception de données :
- Longueur de la trame (trop petite ou grande)
- Les premier et dernier octets doivent correspondre à
XB_FRAME_SOHetXB_FRAME_EOTrespectivement - Le deuxième octet (longueur de la trame) doit être égual à la négation du troisième octet
- Le deuxième octet (longueur de l'octet) doit être égual à la longueur de la trame reçue
- Validation des checksum (XOR de chaque octet avec
0x0000initialement)
Les checksum sont calculés de la même manière :
uint16_t XBee::computeChecksum(const std::vector<uint8_t> &frame, uint8_t start, uint8_t length) {
uint8_t checksum = 0x0000;
// On applique un XOR pour chaque octet
for (uint8_t i = start; i < length; i++)
checksum ^= frame[i];
// On ne peut transmettre que des octets donc on sépare le checksum en deux
// 0x50 permet de faciliter l'échantillonnage du signal
uint8_t checksumLSB = (checksum & 0x0F) | 0x50;
uint8_t checksumMSB = (checksum & 0xF0) >> 4 | 0x50;
return checksumMSB << 8 | checksumLSB;
}