Comment débuter en C++ avec les modules Yoctopuce

Comment débuter en C++ avec les modules Yoctopuce

Cette semaine, nous continuons notre série d'articles "pour les débutants" et on va parler de C++. Le C++ n'est pas vraiment un langage facile à prendre en main et encore moins pour quelqu'un qui n'a jamais programmé, il est cependant toujours d'actualité lorsque l'on utilise des machines où l'espace disque est limité. C'est pourquoi nous allons voir comment réaliser son premier programme en utilisant notre librairie C++





Pour cet exemple, nous allons écrire un petit programme qui contrôle la sortie d'un Yocto-PowerRelay en fonction de la température mesurée par un Yocto-Temperature.

Nous partons du principe que vous savez déjà programmer en C++ car le but de cet article n'est pas de faire un tutoriel sur ce langage mais d'apprendre à utiliser notre la libraire C++. De la même manière, si vous n'êtes pas familier avec les modules Yoctopuce, nous vous recommandons de commencer par la lecture des précédents articles de cette série, en particulier celui sur la structure logique des modules Yoctopuce.

Le programme


Comme nous l'avons dit, le but est d'écrire un petit programme qui bascule un relais quand la température passe au dessus d'un seuil, par exemple 25°C.

Commençons par ajouter les directives #include nécessaires. Il faut inclure au minimum "yocto_api.h", et ensuite le fichier "yocto_xxx.h" correspondant à la fonctionnalité que l'on doit utiliser. Dans notre cas, nous allons utiliser un capteur de température et un relais, il faut donc inclure "yocto_temperature.h" et "yocto_relay.h".

Notre fichier doit donc commencer comme ceci:

#include "yocto_api.h"
#include "yocto_temperature.h"
#include "yocto_relay.h"



Il faut ensuite initialiser l'API en lui indiquant que l'on désire travailler en mode USB, c'est-à-dire que l'on veut détecter uniquement les modules qui sont branchés sur les ports USB de la machine.

Pour ce faire, il faut appeler la méthode RegisterHub de la classe YAPI en lui passant "usb" comme paramètre.

string errmsg;
if (YAPI::RegisterHub("usb", errmsg) != YAPI::SUCCESS) {
  cerr << "RegisterHub error: " << errmsg << endl;
  return 1;
}



L'appel retourne YAPI::SUCCESS si tout s'est bien passé, dans le cas contraire le message d'erreur est copié dans la chaîne de caractères errmsg passée par référence. La cause la plus commune d'erreur à ce stade est qu'il y a déjà un autre programme qui utilise l'API en mode USB, c'est le cas par exemple si vous avez déjà le VirtualHub qui tourne. Vous trouverez plus de détails sur divers usages de registerHub dans un autre article.

L'autre erreur classique, si vous travaillez sous Linux, est de ne pas avoir les droits suffisants pour accéder aux ports USB. Dans ce cas, vous pouvez soit exécuter votre programme en tant que root ou modifier vos règles udev. Nous avons un article complet sur ce sujet: Comment débuter sous Linux.

Récupération des fonctionnalités


Comme vous avez lu l'article sur la structure logique des modules Yoctopuce, vous savez que le Yocto-Temperature et le Yocto-PowerRelay fournissent différentes fonctionnalités parmi lesquelles on trouve temperature et relay. Ce sont ces deux fonctionnalités qui nous intéressent. Pour les récupérer, il y a plusieurs manières.

FirstXXX


Si vous êtes sûr de n'avoir qu'une seule fonctionnalité temperature et une seule fonctionnalité relay disponible, vous pouvez faire au plus simple et utiliser la méthode FirstXXX des classes YTemperature et YRelay.

YTemperature* t = YTemperature::FirstTemperature();
if (t == NULL) {
  cerr << "No temperature sensor found" << endl;
  return 1;
}

YRelay* r = YRelay::FirstRelay();
if (r == NULL) {
    cerr << "No relay found" << endl;
    return 1;
}


Ces méthodes renvoient la première occurrence de la fonctionnalité cherchée, ou NULL si rien ne correspond. Attention toutefois si vous avez deux modules Yoctopuce qui proposent la même fonctionnalité, rien ne vous garantie l'ordre dans lequel sont énumérés les modules.

FindXXX et numéro de série


Vous pouvez aussi utiliser les méthodes FindXXX des classes YTemperature et YRelay avec le numéro de série des modules. Supposons que le numéro de série du Yocto-Temperature soit TMPSENS1-3EA8F et que le numéro de série du Yocto-PowerRelay soit RELAYHI1-56FC0, vous pouvez utiliser:

YTemperature* t = YTemperature::FindTemperature("TMPSENS1-3EA8F.temperature");
if (t->isOnline()) {
  cerr << "TMPSENS1-3EA8F.temperature sensor not found" << endl;
  return 1;
}

YRelay* r = YRelay::FindRelay("RELAYHI1-56FC0.relay1");
if (r->isOnline()) {
    cerr << "RELAYHI1-56FC0.relay1 not found" << endl;
    return 1;
}


A la différence de FirstXXX, FindXXX renvoie toujours un objet valide, c'est pourquoi il faut tester s'il correspond bien à un module connecté avec la méthode isOnline(). Cela permet d'instancier des objets qui correspondent à des modules qui pourront être connectés plus tard dans la vie du programme.

FindXXX et noms logique

A la place du numéro de série, vous pouvez utiliser un nom logique que vous aurez par exemple affecté à l'aide du VirtualHub.

Affection d'un nom logique au relais du Yocto-PowerRelay
Affection d'un nom logique au relais du Yocto-PowerRelay


Mettons que vous ayez appelé le relay "myRelay" et capteur de température "myTemp". Il vous suffira alors d'écrire:

YTemperature* t = YTemperature::FindTemperature("myTemp");
if (t->isOnline()) {
  cerr << "myTemp sensor not found" << endl;
  return 1;
}

YRelay* r = YRelay::FindRelay("myRelay");
if (r->isOnline()) {
    cerr << "myRelay not found" << endl;
    return 1;
}


L'intérêt des noms logiques est double: d'une part ils permettent de s'y retrouver plus facilement dans les systèmes complexes composés de nombreux modules Yoctopuce et, d'autre part, ils permettent de fabriquer des systèmes en plusieurs exemplaires sans avoir à adapter le code aux numéros de séries des modules de chaque exemplaire.


La boucle principale


La boucle principale de notre programme consiste à lire la température du capteur, puis à ajuster la position du relais en fonction de cette température, tant que nos deux modules sont connectés.

while (t->isOnline() && r->isOnline()) {
  double value = t->get_currentValue();
  if (value > 25) {
    r->set_state(YRelay::STATE_B);
  }
  if (value < 24) {
    r->set_state(YRelay::STATE_A);
  }
}



Vous remarquerez qu'on passe le relais à l'état B si la température passe au dessus de 25°C alors qu'on ne revient à l'état A que si la température passe en dessous de 24°C. Cela s'appelle un Schmitt trigger et évite que le relais ne se mette à osciller quand la température se trouve juste à la limite de déclenchement.

On pourrait s'arrêter là, mais il n'est pas forcément nécessaire de faire tourner cette boucle à la vitesse maximale. De toute manière, la fréquence de rafraîchissement du Yocto-Temperature est de 10Hz. On peut donc insérer une petite pause de 100ms dans la boucle sans que cela n'affecte la réactivité du système.

  YAPI::Sleep(100, errmsg);



Notez qu'il vaut mieux utiliser YAPI::Sleep() plutôt que usleep() car cette dernière bloque complètement l'exécution de programme alors que celle de YAPI permet à l'api de continuer à gérer son petit business interne avec les modules pendant la pause. En plus, usleep() n'est pas disponible sous Windows alors que YAPI::Sleep() oui :-)

Stopper la librairie


Avant de quitter le programme, il faut appeler la méthode YAPI::FreeAPI qui va libérer toutes les ressources utilisées par la librairie mais surtout s'assurer que toutes les communications soient terminées correctement.

  YAPI::FreeAPI();



Une fois toutes les pièces mises bout à bout, voici le code complet de notre programme:

#include <iostream>

#include "yocto_api.h"
#include "yocto_temperature.h"
#include "yocto_relay.h"

using namespace std;

int main(int argc, const char* argv[])
{
  string errmsg;
  if (YAPI::RegisterHub("usb", errmsg) != YAPI::SUCCESS) {
    cerr << "RegisterHub error: " << errmsg << endl;
    return 1;
  }

  YTemperature* t = YTemperature::FirstTemperature();
  if (t == NULL) {
    cerr << "No temperature sensor found" << endl;
    return 1;
  }

  YRelay* r = YRelay::FirstRelay();
  if (r == NULL) {
    cerr << "No relay found" << endl;
    return 1;
  }

  while (t->isOnline() && r->isOnline()) {
    double value = t->get_currentValue();
    if (value > 25) {
      r->set_state(YRelay::STATE_B);
    }
    if (value < 24) {
      r->set_state(YRelay::STATE_A);
    }
    YAPI::Sleep(100, errmsg);
  }
  YAPI::FreeAPI();
  return 0;
}



L'allocation des objets Yxxxxx


Vous noterez que les fonctions de la librairies retournent toujours des pointeurs sur des objets et que ces objets ne sont pas explicitement alloués ou libérés avec les opérateurs new et delete.

Vous n'avez pas besoin d'allouer ou libérer les objets qui sont retournés par la librairie Yoctopuce. La librairie garde une référence sur touts ces objets retournés et gère toute seule l'allocation et la libération de ces objets. Si vous appelez dix fois de suite la méthode YTemperature::FindTemperature("myTemp"), un seul objet sera alloué la première fois et les appels suivants retourneront le même objet. Ces objets seront gardés en mémoire jusqu’à ce que la librairie soit stoppée à l'aide de la méthode YAPI::FreeAPI().

Il ne faut donc jamais appeler delete sur un objet Yxxx sinon la librairie va continuer à utiliser le pointeur vers cet objet et faire planter le programme.


Téléchargement de la librairie Yoctopuce C++


Vous pouvez soit télécharger fichier zip sur sur notre page, soit utiliser Git et cloner la librairie depuis GitHub. L'archive contient un répertoire avec la documentation de l'API et un autre répertoire avec des exemples.

Le répertoire le plus important est le répertoire Sources qui comme son nom l'indique contient les fichiers sources en C++ de la librairie. Dans ce répertoire se trouve aussi un sous-répertoire yapi qui contient les fichiers sources C de la librairie.


Compiler le programme


Maintenant que nous avons vu le code à écrire et que nous avons téléchargé la librairie, il reste à compiler ce programme pour générer un exécutable. La manière la plus simple de réaliser cette étape est d'utiliser un IDE.

Dans un précèdent article, nous avons expliqué en détail comment inclure la librairie dans un projet "Visual Studio, Code::Block, C++ Builder et XCode.

Si vous désirez compiler ce programme à l'ancienne, voici les étapes à effectuer:

  1. Copier le répertoire Sources/yapi dans le répertoire du programme
  2. Copier les fichiers yocto_api.h et yocto_api.cpp du répertoire Sources/yapi dans le répertoire du programme
  3. Copier les fichiers yocto_temperature.h et yocto_temperature.cpp du répertoire Sources/yapi dans le répertoire du programme
  4. Copier les fichiers yocto_relay.h et yocto_relay.cpp du répertoire Sources/yapi dans le répertoire du programme
  5. Compiler les fichiers C du répertoire yapi (options -c de gcc)
  6. Compiler les fichiers C++ yocto_api.cpp, yocto_temperature.cpp et yocto_relay.cpp (options -c de gcc)
  7. Compiler et linker l'exemple en incluant les fichiers compilés précédemment et la librairie pthread et usb-1.0


Voici les commandes pour compiler l'exemple que nous venons de réaliser sous Linux à l'aide de gcc.

gcc yapi/yapi.c -c gcc yapi/yfifo.c -c gcc yapi/yhash.c -c gcc yapi/yjni.c -c gcc yapi/yjson.c -c gcc yapi/ykey.c -c gcc yapi/ymemory.c -c gcc yapi/ypkt_lin.c -c gcc yapi/ypkt_osx.c -c gcc yapi/ypkt_win.c -c gcc yapi/yprog.c -c gcc yapi/ystream.c -c gcc yapi/ytcp.c -c gcc yapi/ythread.c -c g++ yocto_api.cpp -c g++ yocto_relay.cpp -c g++ yocto_temperature.cpp -c g++ main.cpp *.o -lpthread -lusb-1.0


Attention, si vous chercher à cross compiler ce programme, par exemple pour générer un binaire pour OpenWRT, il faudra quelques variables d’environnement afin que le compilateur utilise les header et les librairies de votre toolchain.

Le répertoire complet de cet exemple est disponible sur GitHub: https://github.com/yoctopuce-examples/cpp_beginners;

Conclusion


Nous avons gardé cet exemple simple car le but de cet article est vous aider à démarrer et écrire votre premier programme. Mais maintenant que vous avez réussi à commuter un relais, il y a fort à parier que vous aimeriez réaliser quelque chose de plus complexe. Dans ce cas, vous risquez de trouver intéressant la lecture des articles suivants:

Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.