[Bluetooth 4.0][BLE] Lire/Parser valeur d'un Characteristic

Je n'arrive pas à comprendre comment sont structurées les données

Le problème exposé dans ce sujet a été résolu.

Bonjour à tous,

J’espère pouvoir trouver quelqu’un qui a déjà fait face à ce problème

Je suis en train de tenter d’intégrer un périphérique BLE (Bluetooth Low Energy) pour comprendre comment le protocole fonctionne mais là je sèche après plusieurs tentatives infructueuses.

J’arrive à me connecter au périphérique, récupérer les Services ainsi que les Characteristics, ainsi que souscrire à ces dernières afin de récupérer les valeurs.

Seulement voilà, je ne comprends pas comment sont empaquetées les données et j’avance à l’aveugle.

J’utilise Python pour la partie software et la documentation du protocole Bluetooth 4.0 (Voir)

Quand on sélectionne un Characteristic, on obtient un fichier .xml avec toutes les infos que je dois, je le pense, besoin pour me dépatouiller. Mais je n’y comprends pas grand-chose.

J’ai bien ma donnée de type <bytes> mais je ne sait pas comment la découper pour récupérer ce qui m’intéresse. Je ne sais pas non plus comment lire les "fields" ni les "Flags".

Merci d’avance

EDIT: Un peu plus de précisions tout de même: la notion de boutisme (endianness) est acquise, d’ailleurs de ce que j’ai saisi, le protocole transmet les données en little-endian (petit boutisme). Je cherche juste le moyen d’interpréter le fichier .xml et de sortir les données au format "human-readable"

+0 -0

Bonsoir,

Je peux te donner un exemple de donnée mais il n’y a pas de requête à proprement parler. On parle plus de souscription à une notification d’un Characteristic. On lit simplement la donnée. Les données sont structurées de la même façon pour un Characteristic générique (Ceux de la norme Bluetooth 4.0). En cherchant un peu plus, je suis déjà sûr de l’endianness (little-endian). Si j’ai bien suivi la documentation, il faut lire des champs (fields), je suppose qu’il s’agit de bitfield. Mais même en suivant cette logique, j’échoue. Peut-être n’ai-je pas compris comment lire comme il faut.

Voici la donnée: b’3032323465343037303130633136306231633030303037303033' Cette donnée est de type <bytes> (Python 3), et contient la donnée envoyée par le Characteristic en héxadécimal. Seulement, ce n’est pas aussi bête que de convertir un nombre héxadécimal en ASCII. Cela semble être des structures C empaquetées et pour cela il y a le module python struct.

Et voici le fichier .xml qui selon moi explique comment lire ces données: Ici

J’ai pourtant essayé de me déplacer d’offset en offset mais aucun résultat. Je dois vraiment mal m’y prendre je pense.

Merci d’avance

EDIT: Un autre indice que j’ai pu obtenir, c’est qu’en comparant plusieurs données envoyées dans un laps de temps court (1 seconde) il n’y a que certains nombres héxadécimaux qui changent.

+0 -0

Si la donnée correspond bien au schéma, cela semble assez simple.

Les données sont effectivement envoyées de l’octet de poids faible vers l’octet de poids fort. Qui est aussi l’ordre de lecture du document normalement.

Les deux premiers octets est effectivement un champ de bits. Il te permet de dire si certains champs sont présents ou absents et le système d’unité employé pour les mesures. Tu dois donc lire ces 16 bits, bit par bit pour obtenir la signification.

Ensuite globalement tu as plusieurs champs de données, sur un ou deux octets que tu dois parser dans l’ordre. Ils te précisent même l’unité de représentation. Je ne suis pas sur mais je présume que les données envoyées ont une taille variable suivant le nombre de champs présents, donc tu lis dans l’ordre et grâce au premier champ de bits tu peux savoir quelle donnée est où. Mais cela devrait se vérifier si jamais le nombre de données renvoyées est plus ou moins grande.

+1 -0

Bon, vu la chaîne, ça ressemble à de l’ASCII

0224e407010c160b1c00007003

et du coup on va décoder ça:
Flags: 0x2402
Unité SI
Timestamp present (C3)
Weight present (C12)
ReservedForFutureUse = 1 <- Ca c’est bizarre

Timestamp: e407010c160b1c
year 0x07e4 = 2020
month 0x01 = January
Day 0x0c = 12
Hour 0x16 = 22
Minutes 0x0b = 11
Seconds 0x1c = 28

Weight: 0000
0kg

Reserved for future use: 7003

Autant la date semble cohérente, autant j’ai pas d’interprétation pour le reste, sauf si tu as pesé un objet de 4kg.

+0 -0

Bonsoir,

Salut @Jacen. Effectivement j’ai bien pesé un objet de 4kg, c’est mon avocatier, je ne voulais pas poster mes données biométriques ;)

Par contre, je tombe de haut concernant l’ASCII, je ne comprends pas pourquoi mais effectivement j’obtient la même chaîne héxadécimale que toi.

Pourquoi as-tu inversé la valeur héxadécimale des flags ? Est-ce dû as cette histoire de bit de poids fort ou faible ?

C’est exactement ce que je cherche à comprendre, car je pédale dans la semoule côté bitwise operations et tout ce qui en découle. J’ai les bases concernant le binaire et l’héxadécimal mais il est vrai que dès qu’il faut faire ces calculs, je décède.

Effectivement il y a bien un dernier champ nommé "ReservedForFutureUse", je pense que la norme Bluetooth 4.0 l’a implémenté afin d’y ajouter quelque chose plus tard.

Merci à toi @Renault d’avoir confirmé mes pensées et levé une bonne partie du brouillard

EDIT: Je viens de comprendre pour l’ASCII :euh: -> Cette chaîne est passée par la fonction hexlify() du module binascii dans mon code source qui n’a plus rien à faire ici…

EDIT v2: L’inversion des octets de la chaîne héxadécimale c’est en fait l’endianness ?

EDIT v3: J’ai trouvé le poids. Cela correspond à la valeur que tu trouve en dernier car sur plusieurs mesures, c’est elle qui change. On converti la valeur ASCII 3033 (Les quatres derniers) en héxadécimal ce qui donne 0x7003 donc en big-endian 0x0370. En décimal cela vaut 880. Comme indiqué dans la documentation, le poids en unités SI a une résolution de 0.005. En multipliant la valeur décimale par la résolution on obtient 4.4 qui est le poids de la plante. J’ai testé avec mon poids et la valeur est identique à la balance. Ceci dit, la documentation précise que si un champ n’existe pas, il ne sera pas présent dans la donnée. Or le dernier field valide est la taille (Height) et dans le bitfield il est marqué à zéro. Donc ça colle.

+0 -0

Ce qui me gène c’est pas que les bits soient réservés pour un usage futur, c’est que j’ai un bit à 1 dans ce champ. 0x2000 c’est le bit 13 à 1, si je ne m’abuse.

l’inversion des octets pour lire les chiffres est effectivement lié à l’endianess. Comme on est en little endian, il faut les inverser pour retrouver les nombres tels qu’on a l’habitude de les lire.

Mais tel que je lis le XML, il ne devrait pas y avoir de champs à 0x0000 dans la trame, je ne comprends pas ce qu’il fait là. J’ai fait le calcul de poids pour le dernier champs par acquis de conscience, et sans savoir s’il s’agit de SI ou d’unités impériales (à partir du moment où une donnée n’est plus à sa place, je m’attends à tout): la valeur ne change que de 10% entre les 10^-2 livres et les 5.10^-3 kg.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte