Afficheur AM-03127-LED

Cette étude porte sur l'afficheur AM-03127-LCD pourvu d'une seule ligne d'affichage. Nous allons réaliser une série de développements à la fois en mode console, mais aussi en mode fenétrée. D'autre part, nous testerons notre afficheur depuis un simple PC, mais aussi à l'aide de la carte pcDuino. Dans ce dernier cas, l'afficheur sera donc directement connecté à la carte et nous réaliserons du cross-développement. Après une phase de test, les différents travaux que nous mènerons sur le PC sera essentiellement des applications en mode fenêtrée. Enfin, nous terminerons par des applications qui seront développées à la fois sur le PC et sur la carte pcDuino qui nous permettra de communiquer au travers du réseau à l'aide du protocole WebSocket.

Sommaire de l'étude

Développement en mode console sur pcDuino

Ce chapitre va nous permettre de découvrir les fonctionnalités de l'afficheur AM-03127-LCD. L'objectif dans un premier temps sera de comprendre les différentes balises à transmettre à l'afficheur au travers d'une trame qui devra être respectée à la lettre. Pour le premier développement, nous le ferons en mode console et sur un PC classique. Tous les autres se feront ensuite sur la carte pcDuino.

Liste des différentes études
Ressources nécessaires

Tout au long de ce chapitre, nous aurons besoin, pour communiquer favorablement avec l'afficheur, d'une classe nommée seriallib qui est spécialisée dans la communication série, sachant que l'afficheur se connecte à l'aide d'une prise USB Comme son nom l'indique, une interface USB est aussi une interface série. Pour tous vos développements, vous aurez donc besoin d'intégrer à la fois le fichier en-tête et le fichier de définition de cette classe serialib. Enfin, pour bien maîtriser toutes les fonctionnalités de l'afficheur, je vous donne le document concernant l'ensemble des balises. Tout ceci se trouve dans les liens ci-dessous :

Premières expériences

Pour notre premier développement, je vous propose de connecter l'afficheur sur un simple PC classique. Dans un programme rudimentaire, nous allons envoyer une trame sous forme de chaîne de caractères avec déjà toutes les bonnes balises qui nous servira à vérifier la validité de la connexion. Ce message affichera sur la première page de l'afficheur soit bonjour, soit salut, avec un texte défilant en vert et un temps d'affichage fixe de 2 secondes.

Description de la trame

Je vous invite à regarder le document concernant l'afficheur AM-03127-LCD. La trame à envoyer est une chaîne de caractères avec un certain nombre de balises. Voici quelques remarques que nous pouvons faire sur la constitution de cette trame :

  1. Identification de l'afficheur : Il est possible de connecter plusieurs afficheurs sur la liaison série, il faut donc pouvoir choisir celui avec lequel nous devons communiquer. Chaque afficheur possède donc un identifiant qui d'origine est à 01. Nous pouvons également communiquer avec l'ensemble des afficheurs sur une même liaison série broadcast en donnant comme identifiant la valeur 00 tout le monde. L'ossature minimum de la trame est donc la suivante :
    <IDXX> . . . CS<E>
    • La première balise <ID> pour IDentifiant comporte le numéro de l'afficheur avec lequel communiquer.
    • La dernière balise <E> pour End termine systématiquement toute trame quelque soit ce que vous désirez faire.
    • La somme de contrôle CS  évalue le contenu de la trame placé entre les deux balises précédentes. Le contrôle ici est de type XOR codé sur un simple octet mais traduit à l'aide de deux caractères consécutifs donnant les valeurs hexadécimales équivalentes toute la trame est une chaîne de caratères .
    Ainsi, si vous désirez communiquer avec le premier afficheur de la liste :
    <ID01> . . . CS<E>
  2. Afficher un message : L'une des fonctions principales d'un afficheur est bien entendu d'afficher le message de votre choix. Voici la trame minimale que vous devez placer entre les deux balises d'identification et de fin :
    <Ln><Pn><FX><MX><WX><FY>Votre message
    • Ligne de l'afficheur <L.> pour Ligne : l'afficheur que nous utilisons ne possède qu'une seule ligne, donc la valeur numérique à spécifier sera toujours 1.
    • Page de l'afficheur <P.> pour Page : Il est possible d'afficher jusqu'à 26 pages sur un même afficheur. Ces pages seront lues les unes à la suite des autres. Pour identifier la page sur laquelle nous désirons proposer un nouveau message, vous devez spécifier une des lettres de l'alphabet A ... Z.
    • Fonction d'apparition du message <F.> : Il existe plusieurs façons d'afficher votre message : immédiatement, en le faisant défiler vers la droite ou vers la gauche, en le faisant apparaître depuis la partie haute de l'afficheur, etc.
    • Méthode d'affichage <M.> : Il est possible d'afficher le message normalement ou avec un clignotement plus ou moins rapide.
    • Temps d'apparition du message <W.> pour Wait : Vous spécifiez à l'aide d'un chiffre le temps de lecture de la page en cours.
    • Disparition du message <F.> : Comme pour le faire apparaître, vous devez spécifier sa disparition avec la même balise que précédemment.
  3. Autres balises utiles pour la gestion des messages : Il possible de rajouter une balise à votre message qui offre une fonctionnalité supplémentaire. Voici les balises que nous pouvons rajouter :
    • <AX> : Modifie la police d'affichage, les caractères seront plus ou moins gros.
    • <BX> : Émet un son plus ou moins long sur la page en cours.
    • <CX> : Choisit une couleur pour le message : pour cet afficheur, toutes les couleurs proposées ne sont pas pris en compte.
    • <KX> : Permet d'intégrer une date ou une heure préformatée.
    • <UXX> : Permet de rajouter des caractères avec des accents.
    • <NX> : Permet de placer le message non plus à gauche par défaut mais à partir d'une colonne spécifique.
  4. Organisation des pages affichées <Tn> : Il est possible de spécifier toutes les pages qui vont être affichées, à partir de quel moment et dans quel ordre vous désirez les faire apparaître.
  5. Supprimer une page <DLXPn> : Vous pouvez supprimer le contenu actuel d'une page. Attention, cela ne veut pas dire qu'elle ne sera plus affichée. Si vous ne désirez plus la voir du tout, il est nécessaire de passer pas la commande d'organisation des pages.
  6. Supprimer une organisation de pages <DTn> : Il est possible d'avoir plusieurs organisations de pages. À tout moment, vous pouvez supprimer une organisation spécifique. Vous pouvez même supprimer toutes les organisations. Vous pouvez alors utiliser une page par défaut. Par contre, dans ce cas là, une seule page est visible.
  7. Tout supprimer <D*> : Si vous désirez retrouver votre afficheur tel qu'il était au départ, vous pouvez grâce à cette balise, tout effacer.
  8. Proposer une page par défaut <RPn> : Si vous ne dérirez avoir qu'une seule page d'afficher, vous pouvez utiliser cette commande.
  9. Agir sur la luminosité globale de l'afficheur <BX> : Enfin, vous pouvez contrôler la luminosité de l'afficheur suivant quatre valeurs possibles de 25% à 100%.
Afficher un message de bienvenue qui dure deux secondes avec un défilement et de couleur verte

Après avoir pris connaissance avec les différents éléments qui constituent la trame à envoyer à l'afficheur, je vous propose de réaliser notre premier programme extrêmement simple qui permet d'afficher un message de bienvenue.

N'oubliez pas qu'en mode console, il est systématiquement nécessaire d'intégrer dans votre projet la classe serialib. Pour l'utiliser correctement, il suffit de créer un objet par défaut de cette classe. Il faut ensuite ouvrir la connexion série USB, à l'aide de la méthode Open() de cet objet. Cette méthode attend deux arguments. Le premier concerne le device correspondant à la connexion de l'afficheur sur le port USB. Ici, il s'agit de la valeur /dev/ttyUSB0 même valeur pour un PC classique ou pour le pcDuino. Le deuxième permet de spécifier la vitesse de transmission série l'afficheur est réglé à 9600 bauds. Si l'ouverture sur le port USB se passe correctement, la méthode renvoie la valeur 1. Enfin, pour envoyer la trame de votre choix, il suffit de faire appel à la méthode WriteString().

Après toutes ces considérations, vous pouvez maintenant mettre en oeuvre votre programme. Vous testerez les deux trames ci-dessous elles seront intégrées en dur dans le code :

<ID01><L1><PA><FE><MA><WC><FE><CE>bonjour11<E>
<ID01><L1><PA><FE><MA><WC><FE><CE>salut0F<E>
Vous testerez votre programme à la fois avec un PC classique, mais aussi sur la carte pcDuino.
main.cpp Il ne faut le visualiser qu'après avoir codé
#include "serialib.h"
#include <iostream>
using namespace std;

int main()
{
  serialib usb;
  int connexion = usb.Open("/dev/ttyUSB0", 9600);
  if (connexion==1)
  {
    cout << "Afficheur connecté" << endl;
    const char *trame = "<ID01><L1><PA><FE><MA><WC><FE><CE>salut0F<E>";
    usb.WriteString(trame);
    usleep(50000); // il faut laisser le temps de la transmission avant la clôture (50 ms)
  }
  else cout << "Afficheur non connecté" << endl;
  return 0;
}

Trames en ligne de commande

Au lieu de placer les trames directement dans le code, je vous propose maintenant de faire en sorte que la trame soit donnée en paramètre à la suite du programme que vous exécutez dans le mode console. Par ailleurs, pour nous simplifier grandement la tâche, nous allons faire en sorte de calculer systématiquement le checksum de la trame à étudier, ce qui nous servira pour l'étude suivante.

Trame en ligne de commande

Nous allons tout simplement reprendre le programme précédent en plaçant cette fois-ci la chaîne de caractères correspondant à la trame juste après la commande d'exécution comme cela vous est montré ci-dessous. Modifier votre code de telle sorte que le programme soit capable de récupérer cette information en ligne de commande.

main.cpp
#include "serialib.h"
#include <iostream>
using namespace std;

int main(int nombre, char *options[])
{
  if (nombre==2)
  {
    serialib usb;
    int connexion = usb.Open("/dev/ttyUSB0", 9600);
    if (connexion==1)
    {
      cout << "Afficheur connecté" << endl;
      usb.WriteString(options[1]);
      usleep(50000);
    }
    else cout << "Afficheur non connecté" << endl;
  }
  return 0;
}
Calcul du checksum

Je vous propose maintenant de réaliser un petit programme que calcule automatiquement le checksum d'une trame proposée en ligne de commande sans tenir compte de l'en-tête et de l'en-queue de la trame.Je rappelle que la somme de contrôle CS  évalue le contenu de la trame placé entre les deux balises <ID01> et <E>. Le contrôle ici est de type XOR codé sur un simple octet mais traduit à l'aide de deux caractères consécutifs donnant les valeurs hexadécimales équivalentes toute la trame est une chaîne de caratères.

main.cpp
##include <iostream>
using namespace std;

int main(int nombre, char *options[])
{
  if (nombre==2)
  {
      string trame = options[1];
      char calcul = 0;
      for (char octet : trame) calcul^=octet;
      char bas = calcul & 0b00001111;
      char haut = (calcul & 0b11110000) >> 4;
      bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
      haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
      string checksum = {haut, bas};
      cout << "Checksum = " << checksum << endl;
  }
  return 0;
}
Afficher un message avec calcul automatique du checksum

Pour finir, nous allons cumuler les deux petites études précédentes afin de réaliser un programme qui permet d'exécuter une trame passée en ligne de commande avec le calcul automatique du checksum. Le programme doit alors envoyer la trame complète à l'afficheur. Je vous propose de structurer votre programme en fabriquant une fonction checksum() à part afin de bien séparer les différents traitements.

main.cpp
#include "serialib.h"
#include <iostream>
using namespace std;

string checksum(string trame)
{
  char calcul = 0;
  for (char octet : trame) calcul^=octet;
  char bas = calcul & 0b00001111;
  char haut = (calcul & 0b11110000) >> 4;
  bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
  haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
  return {haut, bas};
}

int main(int nombre, char *options[])
{
  if (nombre==2)
  {
    serialib usb;
    int connexion = usb.Open("/dev/ttyUSB0", 9600);
    if (connexion==1)
    {
      cout << "Afficheur connecté" << endl;
      string trame = "<ID01>";
      trame += options[1];
      trame += checksum(options[1]);
      trame += "<E>";
      usb.WriteString(trame.c_str());
      usleep(50000);
    }
    else cout << "Afficheur non connecté" << endl;
  }
}

Tester l'afficheur en envoyant les bonnes trames

Nous allons profiter du programme précédent pour tester notre afficheur. L'objectif de ce chapitre n'est pas de concevoir des applications, mais simplement d'envoyer un ensemble de trames pour bien comprendre et maîtriser toutes les possibilités qu'offre cet afficheur. Ainsi, nous pourrons gérer l'ensemble des pages à afficher, les différentes couleurs, les types d'affichage comme le clignotement, le défilement vers la droite ou la gauche, le scrolling vertical, etc.

Ensemble des exercices proposés trames à retrouver.
  1. Afficher un message quelconque, clignotant, de couleur rouge qui s'affiche immédiatement sans défilement, qui dure cinq secondes et qui défile ensuite vers la droite.
  2. Trame :
    <L1><PA><FA><MB><WF><FF><CB>Bienvenue
  3. Afficher un message quelconque en gras pendant 4 seconde qui apparaît progressivement de la partie haute de l'écran sans mouvement du message lui-même et qui disparaît progressivement de nouveau vers le haut de l'écran.
  4. Trame :
    <L1><PA><FD><MA><WE><FC><AB>Bienvenue
  5. Afficher le caractère unique à pile au centre de l'afficheur. Cette lettre arrive de la gauche s'arrête au centre de l'écran pendant deux secondes et s'en va également à gauche de l'écran.
  6. Trame :
    <L1><PA><FE><MA><WC><FE><N23><U60>
  7. Afficher le message Première qui s'affiche à gauche de l'écran avec les mêmes propriétés que précédemment.
  8. Trame :
    <L1><PA><FE><MA><WC><FE>Premi<U68>re
  9. Afficher le message Bienvenue de toutes les couleurs.
  10. Trame :
    <L1><PA><FE><MA><WC><FE><CS>Bienvenue
  11. Afficher le message BA sur la deuxième page avec la première lettre en rouge et la suivante en vert.
  12. Trame :
    <L1><PB><FE><MA><WC><FE><CB>B<CE>A
  13. Faire en sorte que les trois premières pages de l'afficheur soient opérationnelles pour que ces pages s'affichent indéfiniment, il faut que l'année de début soit 00 et l'année de fin 99.
  14. Trame :
    <TA>00000000009900000000ABC
  15. Supprimer la troisième page.
  16. Trame :
    <DL1PC>
  17. Tout supprimer.
  18. Trame :
    <D*>
  19. Afficher la date d'aujourd'hui sur la première page et l'heure actuelle sur la deuxième page.
  20. Trame :
    <TA>00000000009900000000AB
    <L1><PA><FE><MA><WC><FE><KD>
    <L1><PB><FE><MA><WC><FE><KT>
  21. Agir sur la luminosité de l'écran pour que l'éclairage soit seulement à 25% du maximum.
  22. Trame :
    <BC>

Programmes utilitaires

Maintenant que nous connaissons mieux le fonctionnement des trames ainsi que le comportement global de l'afficheur, nous allons réaliser des programmes, toujours en mode console, qui nous permettrons d'afficher directement sans s'occuper des trames, un ou plusieurs messages proposés en ligne de commande. Au fur et à mesure de notre progression, nous rajouterons certaines sophistications comme la prise compte de la couleur, le mode de transition, la durée du message, etc.

Choisir le nombre de pages à afficher

Pour notre tout premier exercice, je vous propose de réaliser un programme qui permet de choisir le nombre de pages à afficher en suivant l'ordre normal d'affichage ABC...Z. Le nom du programme d'exécution doit s'appeler pages et le nombre de page doit être passé en ligne de commande. Par exemple, pour que l'écran soit capable d'afficher trois pages, voici ce que vous devez saisir :

main.cpp
#include "serialib.h"
#include <iostream>
#include <sstream>
using namespace std;

string checksum(string trame)
{
  char calcul = 0;
  for (char octet : trame) calcul^=octet;
  char bas = calcul & 0b00001111;
  char haut = (calcul & 0b11110000) >> 4;
  bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
  haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
  return {haut, bas};
}

int main(int nombre, char *options[])
{
  if (nombre==2)
  {
    serialib usb;
    int connexion = usb.Open("/dev/ttyUSB0", 9600);
    if (connexion==1)
    {
      cout << "Afficheur connecté" << endl;
      string commande = "<TA>00000000009900000000";
      istringstream saisie(options[1]);
      int pages;
      saisie >> pages;
      for (int i=0; i<pages; i++) commande += 'A'+i;
      ostringstream trame;
      trame << "<ID01>" << commande << checksum(commande) << "<E>";
      usb.WriteString(trame.str().c_str());
      usleep(50000);
    }
    else cout << "Afficheur non connecté" << endl;
  }
}
Afficher un message passé en ligne de commande

Dans notre deuxième projet, nous allons réaliser un programme rudimentaire qui permet d'afficher le message passé en ligne de commande sans plus aucune trame sur la première page de l'afficheur, avec une couleur verte. Le mode de transition doit rester classique, c'est-à-dire avec un décalage vers la gauche pour l'apparition et la disparition du message, toutefois avec une vitesse un petit peu plus lente que d'habitude.

main.cpp
#include "serialib.h"
#include <iostream>
#include <sstream>
using namespace std;

string checksum(string trame)
{
  char calcul = 0;
  for (char octet : trame) calcul^=octet;
  char bas = calcul & 0b00001111;
  char haut = (calcul & 0b11110000) >> 4;
  bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
  haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
  return {haut, bas};
}

int main(int nombre, char *options[])
{
  if (nombre==2)
  {
    serialib usb;
    int connexion = usb.Open("/dev/ttyUSB0", 9600);
    if (connexion==1)
    {
      cout << "Afficheur connecté" << endl;
      string commande = "<L1><PA><FE><MQ><WC><FE><CE>";
      commande += options[1];
      ostringstream trame;
      trame << "<ID01>" << commande << checksum(commande) << "<E>";
      usb.WriteString(trame.str().c_str());
      usleep(50000);
    }
    else cout << "Afficheur non connecté" << endl;
  }
}
Afficher un seul message sur la page de son choix

Nous reprenons le projet précédent, mais cette fois-ci nous devons spécifier la page dans lequel le message doit s'afficher à la suite du message. Par ailleurs, nous ne prennons pas en compte le choix de la couleur par défaut c'est la couleur orange qui est prise en compte.

main.cpp
#include "serialib.h"
#include <iostream>
#include <sstream>
using namespace std;

string checksum(string trame)
{
  char calcul = 0;
  for (char octet : trame) calcul^=octet;
  char bas = calcul & 0b00001111;
  char haut = (calcul & 0b11110000) >> 4;
  bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
  haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
  return {haut, bas};
}

int main(int nombre, char *options[])
{
  if (nombre==3)
  {
    serialib usb;
    int connexion = usb.Open("/dev/ttyUSB0", 9600);
    if (connexion==1)
    {
      cout << "Afficheur connecté" << endl;
      istringstream saisie(options[2]);
      int page;
      saisie >> page;
      char lettre = 'A'+page-1;
      ostringstream commande;
      commande << "<L1><P" << lettre << "><FE><MA><WC><FE>" << options[1];
      ostringstream trame;
      trame << "<ID01>" << commande.str() << checksum(commande.str()) << "<E>";
      usb.WriteString(trame.str().c_str());
      usleep(50000);
    }
    else cout << "Afficheur non connecté" << endl;
  }
}
Afficher plusieurs messages

Pour ce dernier exercice, vous allez mettre en oeuvre un programme qui permet d'afficher un ou plusieurs messages passés en ligne de commande. Dans ce cas de figure, seuls les messages proposés doivent s'afficher. Ainsi, si vous ne prévoyez qu'un seul message, seule la première page doit être active. Par ailleurs, les messages seront tous multicolores.

Pour que votre programme soit bien structuré, en plus de la fonction checksum(), je vous propose de mettre au point plusieurs fonctions spécialisées.

  • void envoyerTrame(string commande) : Cette fonction s'occupe d'envoyer la trame complète à l'afficheur à partir de la commande spécialisée.
  • int nombrePages(char *nombre) : Cette fonction envoie à l'afficheur la bonne trame qui permet d'afficher que les messages proposés. La fonction retourne le nombre de page que l'utilisateur à saisi.
  • void affichePage(int page, string message) : Cette fonction envoie le message requis sur la bonne page de l'afficheur.
main.cpp
#include "serialib.h"
#include <iostream>
#include <sstream>
using namespace std;

serialib usb; // variable globale

string checksum(string trame)
{
  char calcul = 0;
  for (char octet : trame) calcul^=octet;
  char bas = calcul & 0b00001111;
  char haut = (calcul & 0b11110000) >> 4;
  bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
  haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
  return {haut, bas};
}

void envoyerTrame(string commande)
{
  ostringstream trame;
  trame << "<ID01>" << commande << checksum(commande) << "<E>";
  usb.WriteString(trame.str().c_str());
  usleep(100000); // Attente de 1/10ème de seconde entre chaque trame
}

int nombrePages(char *nombre)
{
  string commande = "<TA>00000000009900000000";
  istringstream saisie(nombre);
  int pages;
  saisie >> pages;
  for (int i=0; i<pages; i++) commande += 'A'+i;
  envoyerTrame(commande);
  return pages;
}

void affichePage(int page, string message)
{
  char lettre = 'A'+page;
  ostringstream commande;
  commande << "<L1><P" << lettre << "><FE><MA><WC><FE><CS>" << message;
  envoyerTrame(commande.str());
}

int main(int nombre, char *options[])
{
  if (nombre>2)
  {
    int connexion = usb.Open("/dev/ttyUSB0", 9600);
    if (connexion==1)
    {
      cout << "Afficheur connecté" << endl;
      int nombre = nombrePages(options[1]);
      for (int page=0; page<nombre; page++)
        affichePage(page, options[2+page]);
    }
    else cout << "Afficheur non connecté" << endl;
  }
}

Développement à l'aide de la librairie QT sur PC classique

Maintenant que nous avons pris connaissance en profondeur sur les développements possibles avec l'afficheur AM-03127-LCD, nous allons réaliser un certain nombre de projets en utilisant cette fois-ci la librairie QT. Tous nos développements seront en mode fenêtré et seront exécuté uniquement depuis un PC classique. Nous allons juste nous servir des projets précédants pour les mettre en forme à l'aide d'une IHM.

Afficher un ensemble de messages

Pour notre premier projet en mode fenêtré, nous allons nous servir de l'étude précédente afin de pouvoir afficher un certian nombre de message. À l'aide de notre application, nous pouvons sélectionner le nombre de pages que nous souhaitons voir afficher. Dès que nous effectuez un changement de valeur dans cette zone de saisie, automatiquement l'afficheur se met à jour. Il suffit ensuite de saisir votre message, de sélectionner le type de transition et de validez ensuite vos choix à l'aide du bouton .

Lorsque vous utilisez la librairie QT, vous n'avez plus besoin de prendre les sources relatifs à la classe serialib. En effet, il existe la classe QSerialPort qui réalise les mêmes fonctionnalités. Les deux méthodes qui permettent de sélectionner le port USB utilisé et la vitesse de transmission sont, respectivement : setPortName() et setBaudRate(). Attention, pour que cette classe fonctionne correctement, il est nécessaire de préciser dans le fichier de projet que nous utilisons le module serialport.

IHM

LCD.pro
QT       += core gui serialport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = LCD
TEMPLATE = app

CONFIG   += c++11
SOURCES  += main.cpp principal.cpp
HEADERS  += principal.h
FORMS    += principal.ui
principal.h
#ifndef PRINCIPAL_H
#define PRINCIPAL_H

#include <QMainWindow>
#include <QSerialPort>
#include <string>
#include "ui_principal.h"
using namespace std;

class Principal : public QMainWindow, public Ui::Principal
{
    Q_OBJECT

public:
    explicit Principal(QWidget *parent = 0);
private slots:
    void envoyerMessage();
    void nombrePages(int nombre);
private:
    string checksum(const string &chaine);
private:
    QSerialPort usb;
    string port = "<ID00>", fin="<E>";
};

#endif // PRINCIPAL_H
principal.cpp
#include "principal.h"
#include <sstream>

Principal::Principal(QWidget *parent) : QMainWindow(parent)
{
    setupUi(this);
    usb.setBaudRate(QSerialPort::Baud9600);
    usb.setPortName("/dev/ttyUSB0");
    if (usb.open(QIODevice::WriteOnly))
    {
      barreEtat->showMessage("USB connecté");
      nombrePages(1);
    }
    else  barreEtat->showMessage("Afficheur non connecté");
}

void Principal::nombrePages(int nombre)
{
  string protocole = "<TA>00000000009900000000A";
  char lettre = 'B';
  for (int i=1; i<nombre; i++) protocole += lettre++;
  ostringstream flux;
  flux << port << protocole << checksum(protocole) << "<E>";
  usb.write(flux.str().c_str());
}

void Principal::envoyerMessage()
{
  string protocole = "<L1><P";
  protocole += 'A'+page->value()-1;
  protocole += "><F";
  protocole += defile->isChecked() ? "E><MA><WC><FE><CE>" : "A><MB><WD><FE><CH>";
  string texte = message->text().toStdString();
  ostringstream trame;
  trame << port << protocole << texte << checksum(protocole+texte) << fin;
  usb.write(trame.str().c_str());
  barreEtat->showMessage(trame.str().c_str());
}

string Principal::checksum(const string &chaine)
{
  char calcul = 0;
  for (char octet : chaine) calcul^=octet;
  char bas = calcul & 0b00001111;
  char haut = (calcul & 0b11110000) >> 4;
  bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
  haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
  return {haut, bas};
}

Développement réseau entre le pcDuino et le PC classique

Pour cette dernière rubrique, nous allons de nouveau nous intéresser à l'informatique embarquée à l'aide de la carte pcDuino. L'idée est de piloter un programme interne à la carte avec, soit un navigateur Web, soit avec une application fenêtrée sur un poste classique. Dans ce cas de figure, nous devons réaliser du développement réseau en respectant le protocole WebSocket utilisation possible avec un simple navigateur.

Service d'affichage pour gérer la première page de l'afficheur

Dans ce premier développement réseau, je vous propose de réaliser un service qui permet d'afficher sur la première page de l'afficheur un simple message envoyé depuis n'importe quel poste connecté sur le réseau local ou depuis Intenet. Pour cela, nous utilisons le protocole WebSocket. Avant de démarrer dans ce projet, je vous invite à revoir l'étude sur les WebSockets.

serviceLCD.pro
QT += core websockets serialport
QT -= gui

TARGET = serviceLCD
CONFIG += console c++11
CONFIG -= app_bundle

TEMPLATE = app

SOURCES += main.cpp servicelcd.cpp
HEADERS += servicelcd.h

target.path = /home/ubuntu/Public
INSTALLS += target
main.cpp
#include <QCoreApplication>
#include "servicelcd.h"

int main(int argc, char *argv[])
{
  QCoreApplication a(argc, argv);
  ServiceLCD service;
  return a.exec();
}
serviceLCD.h
#ifndef SERVICELCD_H
#define SERVICELCD_H

#include <QObject>
#include <QWebSocketServer>
#include <QWebSocket>
#include <QSerialPort>
#include <string>
using namespace std;

class ServiceLCD : public QObject
{
  Q_OBJECT
public:
  explicit ServiceLCD(QObject *parent = 0);
private:
  string checksum(const string &trame);
  void affichePage(const string &message);
private slots:
  void nouvelleConnexion();
  void receptionMessage(const QString &message);
  void deconnexion();
private:
  QWebSocketServer service;
  QSerialPort usb;
};

#endif // SERVICELCD_H
serviceLCD.cpp
#include <iostream>
#include <sstream>
using namespace std;
#include "servicelcd.h"

ServiceLCD::ServiceLCD(QObject *parent) : QObject(parent), service("affichage", QWebSocketServer::NonSecureMode, this)
{
  usb.setBaudRate(QSerialPort::Baud9600);
  usb.setPortName("/dev/ttyUSB0");
  if (usb.open(QIODevice::WriteOnly))
  {
    cout << "Afficheur connecté" << endl;
    if (service.listen(QHostAddress::Any, 8080))
    {
      cout << "Lancement du service" << endl;
      connect(&service, SIGNAL(newConnection()), this, SLOT(nouvelleConnexion()));
    }
    else cout << "Le service ne peut pas démarrer" << endl;
  }
  else  cout << "Afficheur non connecté" << endl;
}

string ServiceLCD::checksum(const string &trame)
{
  char calcul = 0;
  for (char octet : trame) calcul^=octet;
  char bas = calcul & 0b00001111;
  char haut = (calcul & 0b11110000) >> 4;
  bas = bas < 10 ? bas+=0x30 :bas+=0x41-10;
  haut = haut < 10 ? haut+=0x30 : haut+=0x41-10;
  return {haut, bas};
}

void ServiceLCD::affichePage(const string &message)
{
  string commande = "<L1><PA><FE><MA><WC><FE><CE>";
  commande += message;
  ostringstream trame;
  trame << "<ID01>" << commande << checksum(commande) << "<E>";
  usb.write(trame.str().c_str());
  cout << "(" << message << ") vient d'être envoyé à l'afficheur" << endl;
}

void ServiceLCD::nouvelleConnexion()
{
    QWebSocket *client = service.nextPendingConnection();
    client->sendTextMessage("Bienvenue sur le service d'affichage");
    connect(client, SIGNAL(textMessageReceived(QString)), this, SLOT(receptionMessage(QString)));
    connect(client, SIGNAL(disconnected()), this, SLOT(deconnexion()));
}

void ServiceLCD::deconnexion()
{
    QWebSocket *client = (QWebSocket *) sender();
    client->deleteLater();
}

void ServiceLCD::receptionMessage(const QString &message)
{
    affichePage(message.toStdString());
}