TP03 : Station météo BLE (broadcaster)
Avec ce travail pratique, nous introduisons une nouvelle dimension à notre station météo avec un module de communication BLE. La communication BLE sera réalisée dans deux travaux pratiques successifs :
- Dans ce TP, nous réaliserons uniquement le broadcaster, qui diffuse les données environnementales dans des paquets d’advertising BLE.
- Dans le TP 5, nous réaliserons l’observer, qui aura pour mission de scanner les paquets d’advertising pour en extraire les données et les afficher.
Le système final (après le TP 05) sera donc composé de deux appareils (cibles) :
- une cible se charge de prendre des mesures environnementales et de les diffuser (broadcast) avec le BLE;
- une deuxième cible reçoit ou observe les mesures diffusées par BLE et les affiche sur l’écran.
Objectifs du TP
Ce TP a pour but de réaliser un broadcaster BLE.
À la fin de ce TP, les étudiants :
- auront intégré les composants BLE à leur solution ;
- auront intégré le broadcasting des données environnementales par BLE;
- auront réalisé des analyses statiques de code et corrigé les erreurs rapportées ;
- auront rédigé un journal de travail et déposé le PDF sur Teams.
Les livrables sont :
- un release avec le tag “tp03” doit être créé sur votre dépôt.
- la correction des issues du TP 02 qui ont été créés lors de la correction du TP 02.
- un journal de travail déposé sur Teams.
Temps accordé : 8 périodes de 45 minutes en classe + travail personnel à la maison
Délai
Les dates de rendu des TPs sont indiquées sur le plan de cours.
Matériel
Pour ce TP, vous avez besoin du module X-NUCLEO-BNRG2A1. Assurez-vous de configurer la carte correctement en mettant le jumper J14 sur la gauche (position 1) :
Le module BLE est placé entre le “STM32F412-DISCO” et la carte “Arduino Click Shield” :
Configuration de Mbed OS et de PlatformIO
Pour utiliser le module BLE, vous devez configurer votre projet de la manière suivante :
Fichier platformio.ini
Dans le fichier platformio.ini
, ajoutez la librairie BLE aux dépendances de votre projet (ligne 3) :
1 2 3 4 |
|
Dossier mbedignore
Le dossier mbedignore
permet de supprimer des composants de Mbed OS pour accélérer
la compilation et l’édition de liens (linker) du programme. Jusqu’ici, nous avions
ignoré la partie BLE et nous devons la ré-activer pour ce TP :
Editez le fichier mbedignore/connectivity/.mbedignore
et supprimez les lignes suivantes :
drivers/ble/*
et
FEATURE_BLE/*
Fichier mbed_app.json
Les bibliothèques pour Mbed OS telles que la bibliothèque BLE sont
souvent accompagnées de paramètres qui influencent le comportement de la
bibliothèque et de sa compilation. Pour la bibliothèque BLE que nous
utilisons, les paramètres sont décrits dans ce fichier
mbed_lib.json
Pour modifier les valeurs par défaut, éditez le fichier mbed_app.json
de votre
projet et ajoutez les lignes suivantes :
{
"target_overrides": {
"*": {
...
"platform.minimal-printf-set-floating-point-max-decimals": 4,
"ble.ble-role-observer": true,
"ble.ble-role-broadcaster": true,
"ble.ble-role-central": false,
"ble.ble-role-peripheral": false,
"ble.ble-feature-gatt-client": false,
"ble.ble-feature-gatt-server": false,
"ble.ble-feature-security": false,
"ble.ble-feature-secure-connections": false,
"ble.ble-feature-signing": false,
"ble.ble-feature-whitelist": false,
"ble.ble-feature-privacy": false,
"ble.ble-feature-phy-management": false,
"ble.ble-feature-extended-advertising": false,
"ble.ble-feature-periodic-advertising": false,
"ble.ble-security-database-filesystem": false,
"ble.ble-security-database-kvstore": false,
"ble.ble-security-database-max-entries": 5,
"ble.ble-gap-max-advertising-sets": 15,
"ble.ble-gap-host-based-private-address-resolution": false,
"ble.ble-gap-max-advertising-reports-pending-address-resolution": 16,
"ble.ble-gap-host-privacy-resolved-cache-size": 16,
"ble.ble-passkey-display-reversed-digits-deprecation": true
},
...
Vous devez également modifier le fichier mbed_app.json
pour l’utilisation de
la bibliothèque BLE et pour la configuration des pins du module BLE en
ajoutant les définitions suivantes :
"DISCO_HEIAFR": {
...
"target.components_add": ["BlueNRG_2"],
"target.features_add": ["BLE"],
"target.extra_labels_add": ["CORDIO"],
"bluenrg_2.SPI_MOSI": "D11",
"bluenrg_2.SPI_MISO": "D12",
"bluenrg_2.SPI_nCS": "A1",
"bluenrg_2.SPI_RESET": "D7",
"bluenrg_2.SPI_IRQ": "A0",
"bluenrg_2.SPI_SCK": "D13"
}
Réalisation
Classe permettant d’encapsuler la production et la consommation de données
Le point de départ pour ce TP est votre réalisation du TP 02. Dans le TP03 et le TP 05, le mécanisme de production et de consommation doit être réalisé par les composants de deux applications, le broadcaster et l’observer.
Le broadcaster développé dans ce TP fonctionne sur le dispositif muni du capteur et d’un module BLE. Pour cette application, le processus de production et de consommation est réalisé de la manière suivante :
- Comme dans le TP02, la classe
SensorDataServer
est un producteur de données. Cette classe a pour mission de lire les données provenant des capteurs et de les mettre à disposition d’un consommateur. - Dans le TP02, le consommateur des données produites par l’instance de
SensorDataServer
est le composant qui affiche les données sur l’écran LCD. Dans ce TP, le consommateur de ces données est le broadcaster BLE, qui diffuse ces données pour qu’un observer BLE puisse les recevoir.
L’observer qui sera développée dans le TP 05 fonctionne sur le dispositif muni d’un module BLE et d’un écran LCD. Pour cette application, le processus de production et de consommation sera réalisé de la manière suivante :
- L’observer BLE est un producteur de données. Les données produites sont celles reçues dans les paquets d’advertising. Les données reçues sont mises à disposition d’un consommateur.
- Le consommateur des données produites par l’instance d’observer est le composant qui affiche les données sur l’écran LCD.
Afin de réaliser le comportement de production et de consommation de manière
uniforme, vous devez encapsuler ces comportements dans une classe DataMailbox
.
Cette classe définit le type de données représentant une mesure, possède une
instance de Mail
et fournit deux méthodes :
class DataMailbox
{
public:
struct message_t
{
double temperature;
double pressure;
double humidity;
time_t time;
};
...
bool produceData(const message_t& message);
bool consumeData(message_t& message);
...
Après avoir réalisé cette classe, vous pouvez l’intégrer dans votre réalisation du TP 02 et tester à nouveau le bon comportement de votre application. Le comportement doit être le même que votre application du TP02.
L’API BLE fournie par Mbed OS
Comme pour la plupart des API fournies par Mbed OS, l’API BLE est disponible sous forme de classes C++. Cela permet de programmer une application BLE fonctionnant avec tous les modules BLE compatibles, en réduisant la complexité. Pour notre application, vous devez utiliser les classes suivantes :
- la classe
BLE
qui permet d’obtenir un singleton représentant le device et qui permet d’initialiser ce dernier. Le concept de singleton est expliqué par exemple sous singleton pattern. - la classe
Gap
qui permet d’accéder aux fonctionnalités de découverte des dispositifs et de gestion de l’advertising et du scanning.
Avant de détailler l’utilisation de ces classes, il est important de mentionner les points suivants concernant l’API BLE de Mbed OS :
- De nombreux appels à l’API sont asynchrones et le résultat de ces appels est donc fourni via des fonctions ou méthodes de callback.
- L’API n’est pas thread safe. Cela signifie que tous les appels à la librairie et que le traitement asynchrone des messages doivent être effectués depuis le même thread.
La classe GAPDevice
Afin de faciliter votre travail d’intégration de la librairie BLE dans votre
application, le squelette d’une classe GapDevice
est donné ci-dessous :
#ifndef GAP_DEVICE_HPP_
#define GAP_DEVICE_HPP_
#include <mbed.h>
#include "ble/BLE.h"
#include "ble/Gap.h"
class GAPDevice : private mbed::NonCopyable<GAPDevice>,
public ble::Gap::EventHandler {
public:
GAPDevice();
~GAPDevice();
void start();
protected:
// protected methods (may be called by inheriting classes)
template <typename T, typename R>
void scheduleCall(T* obj, R (T::*method)())
{
eventQueue_.call(obj, method);
}
// This is called by inheriting classes when BLE interface is initialised
virtual void onInitComplete(
BLE::InitializationCompleteCallbackContext* context) = 0;
// helper methods
static void uint16_encode(uint16_t value, uint8_t* p_encoded_data);
static void int16_encode(int16_t value, uint8_t* p_encoded_data);
static void uint32_encode(uint32_t value, uint8_t* p_encoded_data);
static uint16_t uint16_decode(uint8_t* p_encoded_data);
static int16_t int16_decode(uint8_t* p_encoded_data);
static uint32_t uint32_decode(uint8_t* p_encoded_data);
private:
void scheduleBleEvents(BLE::OnEventsToProcessCallbackContext* context);
events::EventQueue eventQueue_;
Thread bleThread_;
};
#endif /* GAP_DEVICE_HPP_ */
#include "gap_device.hpp"
#include "mbed_trace.h"
#if defined(MBED_CONF_MBED_TRACE_ENABLE)
#define TRACE_GROUP "GAPDevice"
#endif // MBED_CONF_MBED_TRACE_ENABLE
// constructor
GAPDevice::GAPDevice()
: // TODO : Initialize attributs
{
}
GAPDevice::~GAPDevice()
{
// TODO : Shutdown BLE instance if initialized
}
void GAPDevice::start()
{
// errors in this method are considered fatal (stop the system)
// check whether the BLE instance is already initialized
// (it should not be)
if (BLE::Instance().hasInitialized()) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_APPLICATION,
MBED_ERROR_CODE_INITIALIZATION_FAILED),
"Ble instance already initialised");
}
// this will inform us off all events so we can schedule their handling
// using our event queue
BLE::Instance().onEventsToProcess(
makeFunctionPointer(this, &GAPDevice::scheduleBleEvents));
// set this instance as the event handler for all gap events
BLE::Instance().gap().setEventHandler(this);
// initialize the ble component
ble_error_t error = BLE::Instance().init(this, &GAPDevice::onInitComplete);
if (error != BLE_ERROR_NONE) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_APPLICATION, error),
"Error returned by BLE::init");
}
osStatus status =
bleThread_.start(callback(&eventQueue_, &EventQueue::dispatch_forever));
if (status != osOK) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_APPLICATION, status),
"Error when starting ble thread");
}
}
// Schedule processing of events from the BLE API in our event queue (served
// by blethread_)
void GAPDevice::scheduleBleEvents(
BLE::OnEventsToProcessCallbackContext* context)
{
eventQueue_.call(Callback<void()>(&context->ble, &BLE::processEvents));
}
void GAPDevice::uint16_encode(uint16_t value, uint8_t* p_encoded_data)
{
// TODO
}
void GAPDevice::int16_encode(int16_t value, uint8_t* p_encoded_data)
{
// TODO
}
void GAPDevice::uint32_encode(uint32_t value, uint8_t* p_encoded_data)
{
// TODO
}
uint16_t GAPDevice::uint16_decode(uint8_t* p_encoded_data)
{
// TODO
}
int16_t GAPDevice::int16_decode(uint8_t* p_encoded_data)
{
// TODO
}
uint32_t GAPDevice::uint32_decode(uint8_t* p_encoded_data)
{
// TODO
}
Cette classe servira de base aux composants que vous devez développer pour votre
application. Vous devrez utiliser cette classe par héritage pour les composants
BLEBroadcaster
(TP 03) et BLEObserver
(TP 05) que vous devrez développer.
Les principes mis
en œuvre dans la classe GAPDevice
sont les suivants :
-
L’API BLE de Mbed OS requiert que tous les appels aux méthodes de l’API soient exécutés par un seul et même thread. Ce thread doit être créé et démarré par l’application. L’API fournit donc une méthode
ble::BLE::onEventsToProcess
qui permet de signaler à l’application quand des événements de l’API doivent être traités et l’API fournit également une méthodeble::BLE::processEvents
pour traiter ces événements. Ce mécanisme est réalisé pour votre application dans la classeGAPDevice
(voir les méthodesGAPDevice::start()
etGAPDevice::scheduleBleEvents()
). -
D’autres opérations dans les classes
BLE
etGap
sont effectuées de manière asynchrone. Afin de recevoir les résultats de ces opérations asynchrones, il est nécessaire d’enregistrer des callbacks pour traiter les résultats. Pour la classeble::Gap
, cet enregistrement se fait avec la méthodeble::Gap::setEventHandler()
. La classeGAPDevice
hérite de la classeble::Gap::EventHandler
et dans la méthodeGAPDevice::start()
, nous pouvons enregistrer l’instance deGAPDevice
courante comme traitant les événements générés par la classeble::Gap
. Afin de traiter un événement généré par la classeble::Gap
, il suffit de redéfinir une des méthodes de la classeble::Gap::EventHandler
dans la classeGAPDevice
- veuillez noter qu’aucune de ces méthodes n’est redéfinie à ce stade. -
Un mécanisme similaire de callback est utilisé pour l’appel à la méthode
ble::BLE::init()
pour laquelle le callback est la méthodeGAPDevice::onInitComplete()
. Cette méthode est une méthode abstraite qui devra être redéfinie par les classesBLEBroadcaster
etBLEObserver
héritant deGAPDevice
. Plus de détails sont donnés ci-dessous concernant les méthodes virtuelles et abstraites. -
Afin d’obtenir une référence sur l’instance
ble::BLE
singleton, les méthodes de la classeGAPDevice
font appel à la méthodeble::BLE::Instance()
. -
Afin d’obtenir une référence sur l’instance
ble::Gap
singleton, les méthodes de la classeGAPDevice
font appel à la méthodeble::BLE::Instance().Gap()
Les méthodes virtuelles
Pour rappel, les méthodes
virtuelles
d’une classe sont des méthodes qui peuvent être redéfinies par une classe
dérivant de cette classe. Lorsqu’une classe redéfinit une méthode virtuelle,
c’est bien la méthode redéfinie dans cette classe qui sera appelée lorsque cette
méthode sera invoquée. Lorsqu’une classe redéfinit une méthode virtuelle, le mot
clé override
devrait être ajouté à la déclaration de la méthode selon la
notation void f() override
. Une méthode virtuelle peut être définie comme
pure
virtual
dans une classe de base avec la notation virtual ... = 0
. Dans ce cas, le type
de la classe de base devient abstrait et la méthode doit être définie dans une
classe dérivante afin que cette classe soit instanciable.
Le principe des méthodes virtuelles et pure virtuelles est également présenté dans le cours EduTools, sous le chapitre “From Java to C++ -> Classes and inheritance”. Veuillez vous y référer pour plus de détails et pour les exemples.
En rapport à l’utilisation d’un singleton, il est intéressant de mettre en
évidence les points suivants dans la classe BLE
:
class BLE
{
public:
...
// Prevent copy construction and copy assignment of BLE.
BLE(const BLE &) = delete;
BLE &operator=(const BLE &) = delete;
...
};
Comme commenté dans le code, les notations = delete
suivant la déclaration du
copy constructor
et de l’opérateur d’affectation permettent d’empêcher
l’utilisation de ces mécanismes. En d’autres termes, il n’est pas possible pour
un programme de copier une instance de la classe BLE
, ce qui est nécessaire
lorsque l’on utilise des singletons. Ce mécanisme est expliqué de manière
détaillée sous deleted
functions.
Questions
Expliquez pourquoi le mécanisme de singleton
doit déclarer le copy
constructor
et l’opérateur d’affectation avec un = delete
. Démontrez avec
un exemple comment il serait possible de dupliquer un singleton.
La classe BLEBroadcaster
La classe BLEBroadcaster
est utilisée par l’application afin de diffuser les
données de capteurs en mode advertising. Cette classe représente donc un rôle
de broadcaster au sens de la terminologie BLE.
Vous devez créer la classe BLEBroadcaster
avec les caractéristiques suivantes :
- La classe hérite de la classe
GAPDevice
. - La classe redéfinit la méthode abstraite privée
onInitComplete
. - La classe définit une méthode privée
startAdvertising
qui est appelée lorsque l’initialisation du dispositif a été effectuée avec succès. - La classe définit une méthode publique
setAdvertisementPayload
qui sera appelée par l’application pour publier les données environnementales dans les paquets d’advertising. - La classe définit une méthode privée
setServiceData
qui est utilisée pour construire les données d’advertising. - La classe définit un attribut de type
ble::AdvertisingDataBuilder
. Cet attribut sera utilisé dans différentes méthodes afin d’initialiser les données d’advertising et afin de les mettre à jour lorsque de nouvelles données de capteurs sont disponibles. Cet attribut doit être initialisé à l’aide d’un buffer de typeuint8_t
de la taille maximale des données d’advertising (définie parble::LEGACY_ADVERTISING_MAX_SIZE
).
La méthode BLEBroadcaster::onInitComplete
La méthode BLEBroadcaster::onInitComplete
doit être réalisée en tenant compte
des points suivants :
- Si une erreur est survenue lors de l’initialisation, le champ
error
du paramètre de typeble::BLE::InitializationCompleteCallbackContext
passé à l’appel de la méthode contient l’identifiant de l’erreur. Si l’initialisation s’est déroulée sans erreur, alors le champerror
contient la valeurBLE_ERROR_NONE
. Si une erreur est survenue, il faut considérer cette erreur comme fatale et stopper le système. - En utilisant la fonction
print_mac_address()
de la bibliothèque mbed-os-ble-utils, vous pouvez afficher l’adresse MAC du dispositif sur la console. - Finalement, la méthode doit démarrer l’advertising. Comme déjà énoncé, tous
les appels à l’API BLE de Mbed OS doivent être effectués par un seul et
même thread, dans notre cas le thread nommé
bleThread_
défini dans la classeGAPdevice
. Afin de démarrer l’advertising, vous devez donc utiliser la méthodeGAPDevice::scheduleCall
en spécifiant la méthodeBLEBroadcaster::startAdvertising
en paramètre.
La méthode BLEBroadcaster::startAdvertising
La méthode BLEBroadcaster::startAdvertising
doit être réalisée en tenant
compte des points suivants :
- Toute erreur survenant dans cette méthode doit être considérée comme fatale et doit donc stopper le système. Cela signifie bien sûr que le code de retour de toutes les méthodes appelées doit être vérifié.
- Les paramètres
d’advertising
doivent être définis en appelant la méthode
Gap::setAdvertisingParameters
. Pour notre broadcaster, le type d’advertising estadvertising_type_t::NON_CONNECTABLE_UNDIRECTED
et l’intervalle d’advertising est un paramètre de votre application. - Le champ Flags (AD Type
0x01
) doit être initialisé en appelant la méthodeble::AdvertisingDataBuilder::setFlags
. Les flags à enclencher dans notre application sontble::adv_data_flags_t::LE_GENERAL_DISCOVERABLE
etble::adv_data_flags_t::BREDR_NOT_SUPPORTED
. - Le champ Name (AD Type
0x09
) doit être initialisé en appelant la méthodeble::AdvertisingDataBuilder::setName
. Choisissez un nom spécifique, d’une taille permettant de respecter la limite totale de 31 octets pour les données d’advertising. - Les données d’advertising du dispositif GAP - initialisées dans la classe
BLEBroadcaster
à l’aide de l’attributble::AdvertisingDataBuilder
- doivent être mises à jour à l’aide de la méthodeGap::setAdvertisingPayload
. - Finalement, le processus d’advertising doit être démarré à l’aide de la
méthode
Gap::startAdvertising
. Dans le cas de notre application broadcaster, vous pouvez utiliser les paramètres par défaut de la méthode.
Après avoir réalisé la méthode BLEBroadcaster::startAdvertising
, votre
dispositif devrait envoyer des paquets d’advertising à l’intervalle fixé par
l’application. Pour tester ce comportement, vous devez instancier un
BLEBroadcaster
dans votre application et appeler la méthode
BLEBroadcaster::start
. Votre dispositif devrait apparaître si vous effectuez
un scan à l’aide d’une application comme Nordic Semiconductor nRF Connect
for
Mobile
ou LightBlue.
Avant de poursuivre la réalisation, vous devez vous assurer que l’advertising fonctionne correctement. La suite de la réalisation permettra de mettre à jour les données d’advertising afin que celles-ci contiennent les données de capteurs.
La méthode BLEBroadcaster::setServiceData
La méthode BLEBroadcaster::setServiceData
est mise à disposition ci-dessous :
ble_error_t BLEBroadcaster::setServiceData(UUID serviceUUID,
const uint8_t* pServiceData,
uint16_t serviceDataLength)
{
// set the local service list
ble_error_t error = advDataBuilder_.setLocalServiceList(
mbed::make_Span(&serviceUUID, 1), true);
if (error != BLE_ERROR_NONE) {
tr_error("Error in setServiceData: %d", error);
return error;
}
// set the service data
error = advDataBuilder_.setServiceData(
serviceUUID, mbed::make_Span(pServiceData, serviceDataLength));
if (error != BLE_ERROR_NONE) {
tr_error("Error in setServiceData: %d", error);
return error;
}
// set the advertising payload
error = BLE::Instance().gap().setAdvertisingPayload(
ble::LEGACY_ADVERTISING_HANDLE, advDataBuilder_.getAdvertisingData());
if (error != BLE_ERROR_NONE) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_APPLICATION, error),
"Error in gap().setAdvertisingPayload");
}
return BLE_ERROR_NONE;
}
Cette méthode peut être utilisée par la méthode
BLEBroadcaster::setAdvertisementPayload
à développer. Elle prend en paramètre
l’UUID du service et un buffer contenant les données de services. Ces
données correspondent au champ Service Data du payload d’advertising
(AD type 0x16). La méthode utilise l’attribut
ble::AdvertisingDataBuilder
et doit donc être adaptée au nom de l’attribut
que vous aurez choisi pour votre classe BLEBroadcaster
.
Remarque importante
La méthode BLEBroadcaster::setServiceData
pourrait être appelée alors que
l’initialisation du dispositif BLE n’est pas terminée - c’est-à-dire avant
que la méthode onInitComplete()
ait été appelée. Comme l’API BLE n’est
pas thread safe, il est possible qu’un tel appel produise un comportement
inattendu et difficile à détecter. Vous devez éviter un tel scénario en retournant
immédiatement de la méthode si l’initialisation n’est pas terminée, comme illustré
ci-dessous
// return silently when init is not complete
if (! isInitComplete_) {
return BLE_ERROR_NONE;
}
isInitComplete_
doit être initialisé à false
et mis à true
lorsque l’initialisation du dispositif BLE est terminé.
La méthode BLEBroadcaster::setAdvertisementPayload
La méthode BLEBroadcaster::setAdvertisementPayload
doit être réalisée en tenant
compte des points suivants :
- La méthode prend en paramètres les données de capteurs.
- Un buffer de 8 octets doit être créé sur le stack pour sauvegarder les données de service.
- Les données de capteurs doivent être encodées dans le buffer à l’aide des
méthodes statiques
uint16_encode
,int16_encode
etuint32_encode
définies dans la classeGAPDevice
. Si vous le préférez, vous pouvez également utiliser les macros définies dans le fichier ‘bstream.h’ qui fait partie de la librairie BLE de Mbed OS. - Après avoir encodé les données de capteurs dans le buffer, la méthode
setServiceData
doit être appelée. L’UUID du service à utiliser estGattService::UUID_ENVIRONMENTAL_SERVICE
.
À ce stade, votre BLEBroadcaster
devrait être entièrement fonctionnel. Vous
devez modifier votre programme principal et appeler la méthode
BLEBroadcaster::setAdvertisementPayload
lorsque des données de capteurs sont
disponibles. Vous devez suivre le même modèle de programmation que celui utilisé
pour l’affichage des données sur l’écran LCD. Vous pouvez vérifier le
comportement de votre application broadcaster à l’aide de l’application
Nordic Semiconductor nRF Connect for
Mobile
ou de LightBlue.
L’application ne permet pas d’interpréter les données de service, mais vous
devriez constater que ces données sont modifiées lorsque les valeurs des mesures
de capteurs changent.
Explication des valeurs:
LEN. | TYPE | VALUE |
---|---|---|
2 | 0x01 | 0x06 |
7 | 0x09 | 0x544845524D4F |
3 | 0x03 | 0x1A18 |
11 | 0x16 | 0x1A180C250000A00A6BOE |
- 0x544845524D4F = “THERMO”
- 0C250000 = 9516 = 951.6 mbar
- A00A = 2720 = 27.2°
- 6BOE = 3691 = 37.2%
Le programme principal
Afin de simplifier la réalisation des scénarios de broadcaster et
d’observer, vous pouvez réaliser les deux comportements (TP 03 et 05) dans une seule
application. Dans cette application, vous pouvez tester la présence du capteur
Weather click. Si le capteur est présent, l’application réalise le scénario du
broadcaster, avec une instance de DataMailbox
utilisée pour échanger des
données entre le SensorDataServer
et le BLEBroadcaster
.
Dans le TP 05, si le capteur n’est pas présent, l’application réalisera le
scénario de l’observer, avec une instance de DataMailbox
utilisée pour
échanger des données entre le BLEObserver
et le programme affichant des
données sur l’écran LCD. Vous pourrez ainsi flasher le même programme sur
deux dispositifs différents, les deux étant équipés d’un module X-NUCLEO-BNRG2A1
et un seul étant équipé d’un capteur Weather click.
Tests et validations
Vous devez effectuer un test qui démontre que votre broadcaster fonctionne. Dans le cadre du TP 03, il suffit de démontrer que les données broadcastées par votre broadcaster sont reçus par un smartphone en utilisant l’application Nordic Semiconductor nRF Connect for Mobile. Pour cela, vous devez ajouter une copie d’écran du téléphone avec un nom de broadcaster “XX_YY”, “XX” et “YY” étant les initiales de vos noms/prénoms.
Aucun test automatique n’est exigé. Par contre, vous devez configurer l’analyse
statique de code de manière plus stricte. Dans le fichier .gitlab-ci.yml
,
configurez l’analyse statique pour alerter lors de problèmes de niveau low.
Ajoutez pour cela l’option --fail-on-defect=low
à la commande pio check
:
1 2 3 4 5 6 |
|
À ne pas oublier
- Choisissez de bons noms pour les classes, les méthodes et les variables.
- Implémentez les bibliothèques avec un haut niveau d’abstraction pour pouvoir réutiliser les méthodes dans d’autres projets.
- Faites des “git commit” régulièrement avec de bons commentaires.
- Utilisez des assertions dans votre code pour le documenter et le rendre plus robuste.
Journal de travail
- Rédigez un rapport (journal de travail) avec les indications suivantes :
- Une page de titre avec au minimum :
- le nom et le logo officiel de l’école
- le nom du cours : Module Acquisition et traitement de données : Internet des Objets
- le titre de votre document : Travail Pratique 3 : Station météo BLE broadcaster
- le numéro de votre groupe
- les noms des auteurs (vous) avec la classe dans laquelle vous êtes
- la date à laquelle vous avez terminé le rapport
- éventuellement la version du rapport
- Une introduction pour poser le contexte
- Un résumé des notions que vous avez apprises pendant ce TP en précisant si c’est
- non acquis
- acquis, mais encore à exercer
- parfaitement acquis
- Un résumé des points qui vous semblent importants et que vous devez retenir
- Les réponses aux questions.
- Le code source bien formaté et avec du “syntax highlighting” de votre code source.
- Une conclusion par laquelle vous donnez vos impressions sur le TP, ce que vous avez aimé, ce que vous avez moins aimé, et éventuellement des suggestions pour des changements. Indiquez également le nombre d’heures que vous avez passées, par personne, en dehors des heures de TP en classe.
Important
Déposez votre rapport dans le devoir Teams correspondant avec le nom report03.pdf
.