Programmation Windows : port série

Transcription

Programmation Windows : port série
C++ : Utilisation du port série
On se propose de construire une application, utilisant
le port série, qui permet de recevoir ou d’envoyer des
messages sous forme de texte.
L’intérêt de cette présentation est de détailler la mise
en uvre des classes de l’API Windows.
Nous allons créer une application basée sur une boîte
de dialogue dont l’interface est présentée ci-contre.
Pour cela nous allons avec Visual C++ V6 créer un
nouveau projet appelé SerialApp avec les options
adéquates.
Ci-dessous une vue d’ensemble des classes de
l’application SerialApp.
La classe SerialCtl constitue le driver du port série pour notre application, elle fournie des méthodes d’accès au
périphérique matériel.
Création de l’interface.
La première tâche, une fois le projet créé, consiste à créer l’interface du programme comme le montre la copie
d’écran ci-dessus.
Il faut fixer, pour chacun des contrôles de notre application, les propriétés. En cliquant avec le bouton droit
sur un contrôle, il est possible de modifier ses propriétés !
La classe CSerielAppDlg.
Ensuite, éditer les propriétés de chaque élément, et fixer les valeurs qui suivent :
Elément
Propriété : ID
Zone « edit » Status
IDC_Wstatus
Zone « edit » Reception
IDC_Wreceive
Zone « edit » Emission
IDC_Wsend
Zone « liste » Vitesse
IDC_Lbaudrate
Drop down, vertical scroll
Zone « liste » Num. Port
IDC_Lportname
Drop down, vertical scroll
Bouton « Ouvrir Port »
IDC_Bopen
Ouvrir port
Bouton « Fermer Port »
IDC_Bclose
Fermer Port
Bouton « Envoyer »
IDC_Bsend
Envoyer
Bouton « Quitter »
IDC_Bexit
Quitter
#njc Lycée « la Briquerie »
Propriété : Caption
Propriétés : autres
Programmation C++ : port série
& page 1/9
On peut avant de continuer observer les différentes objet de la classe CSerielAppDlg qui caractérise cette
interface :
Création des variables de la classe CSerielAppDlg
Les fichiers sont ceux élaborés au démarrage du projet. Maintenant, il faut :
associer des variables aux différents champs que l’utilisateur peut fixer,
associer du code aux boutons pour les rendre opérationnels.
Cela se fait avec le ClassWizard : View -> ClassWizard ou ctrl + w.
Lancer le ClassWizard, et aller à l’onglet Member Variables. En double-cliquant sur chaque variable, entrer les
valeurs comme elles apparaissent su l’écran suivant :
Les variables ainsi définies peuvent être utilisées librement dans notre programme, elles apparaissent dans la
classe CSerialAppDlg
Création des fonctions associées aux contrôles
Ensuite, il faut associer des fonctions aux boutons. Pour cela, passer à l’onglet Message Maps du ClassWizard.
Cet onglet permet de :
§
sélectionner un objet dans le cadre Object IDs,
§
sélectionner ensuite un message parmi ceux
potentiellement générés par cet objet (fenêtre
Messages),
§
associer à ce message une fonction qui sera
membre de la classe affichée en haut.
Pour les identificateurs IDC_Bx, ce sont les boutons, on
associer respectivement les fonctions proposées. Par
défaut, ces fonctions sont de type void et ne reçoivent
aucun paramètre, ce qui convient :
Dans le gestionnaire de projet, la classe SerialAppDlg.cpp a été modifiée avec de nouvelles méthodes et de
nouvelles données :
#njc Lycée « la Briquerie »
Programmation C++ : port série
& page 2/9
Nous pouvons ajouter d’autres variables à notre classe, par exemple, en écrivant dans le fichier d’entête :
On peut également initialiser des variables :
On peut alors placer le code correspondant mais, dans notre cas, il faut maintenant se soucier de l’application
proprement dite c'est-à-dire la gestion de la liaison série.
Driver du port série.
L’utilisation du port série peut se faire selon différentes techniques :
En utilisant des ActiveX
En utilisant directement les entrées/sorties
En utilisant la notion de fichier.
Nous allons examiner la dernière technique, celle utilisant la notion de fichier sur la plateforme Win32.
#njc Lycée « la Briquerie »
Programmation C++ : port série
& page 3/9
Dans les systèmes Windows le port série peut être traité comme un fichier, c’est pourquoi on peut ouvrir un
port série par création d’un fichier. C’est cette méthode que l’on va utiliser.
Nous allons ajouter une nouvelle classe générique à notre projet : la classe CSerialCtl dont on voit le fichier de
définition qui est, à part le squelette, pratiquement vide. Cette classe nous permettra de contrôler la liaison série.
Nous allons tout d’abord définir les éléments de cette classe en complétant le fichier CSerialCtl.h comme ceci :
Il faut maintenant définir le code correspondant dans le fichier Controlserie.cpp. de la classe dérivé de la classe
CserialCtl.
On définit ci-dessous les paramètres par défaut lors de la construction et la destruction de l’instance de la
classe.
#njc Lycée « la Briquerie »
Programmation C++ : port série
& page 4/9
On récupère l’état du port grâce à la méthode getStatusPort.
On définit ci-dessous la méthode write_scc pour l’écriture vers le port série. On utilise les opérations classiques
de la fonction WriteFile.
On définit ci-dessous la méthode read_scc pour la lecture depuis le port série.
On définit ci-dessous la méthode close_port pour la fermeture du port série.
La méthode permet de fermer le port s’il est ouvert en fermant le « handle ». En cas de succès la fonction la
fonction retourne TRUE.
Pour ouvrir le port, on utilise la méthode openPort ci-dessous. La première étape dans l’ouverture du port, s’il
est fermé, consiste à fixer les paramètres du port en créant un « handle ou gestionnaire» pour le fichier
concernant le port. Le gestionnaire nous permet d’accéder au port ; on utilise la fonction CreateFile.
La première action consiste à créer un « handle » :
#njc Lycée « la Briquerie »
Programmation C++ : port série
& page 5/9
On vérifie ensuite l’ouverture en relisant les paramètres du handle et la configuration du port.
La fonction GetCommState est utilisée pour lire la configuration du port afin de remplir la structure de type
DCB (Device Control Block).
On met à jour la configuration à partir des données au format DCB et on vérifie la bonne exécution en relisant
les paramètres.
La fonction SetCommState permet la configuration du périphérique avec les spécifications de la structure
DCB. La fonction réinitialise le périphérique matériel avec les paramètres du DCB mais ne purge pas les
buffers d’émission et de réception.
Le fonctionnement du port série, lors de son utilisation, s’accompagne, pour éviter les blocages, d’un certain
nombre de « temps de butée » ou timeout que l’on définit ci-dessous en position les données de la structure
COMMTIMEOUTS en utilisant la fonction SetCommTimeouts.
ReadIntervalTimeout
Spécifie, en millisecondes, la durée maximale entre l’arrivée de 2 caractères sur la ligne de réception. Pendant
l’opération ReadFile, si l’intervalle de temps dépasse cette valeur aucune donnée n’est mémorisée. Une valeur
de 0 indique que ce timeout n’est pas utilisé.
La valeur de MAXDWORD combinée avec des 0 pour les données ReadTotalTimeoutConstant et
ReadTotalTimeoutMultiplier, précise que le retour après une opération de lecture est immédiate avec les
caractères reçus même si aucun caractère n’est reçu.
ReadTotalTimeoutMultiplier
Spécifie le multiplieur, en millisecondes, utilisé pour calculer le timeout total pour une opération de lecture.
Pour chaque opération, cette valeur est multipliée par le nombre d’octets à lire.
ReadTotalTimeoutConstant
Spécifie la constante, en millisecondes, utilise pour calculer le timeout total pour une opération de lecture. Pour
chaque opération, cette valeur est ajoutée au produit de ReadTotalTimeoutMultiplier et du nombre d’octets
à lire.
Une valeur nulle pour ReadTotalTimeoutMultiplier et ReadTotalTimeoutConstant indique que le timeout
total n’est pas utilisé pour les opérations de lecture.
WriteTotalTimeoutMultiplier
Spécifie le multiplieur, en millisecondes, utilisé pour calculer le timeout total pour une opération d’écriture.
Pour chaque opération, cette valeur est multipliée par le nombre d’octets à écrire.
#njc Lycée « la Briquerie »
Programmation C++ : port série
& page 6/9
WriteTotalTimeoutConstant
Spécifie la constante, en millisecondes, utilise pour calculer le timeout total pour une opération d’écriture. Pour
chaque opération, cette valeur est ajoutée au produit de WriteTotalTimeoutMultiplier et du nombre
d’octets à écrire.
Une valeur nulle pour WriteTotalTimeoutMultiplier et WriteTotalTimeoutConstant indique que le
timeout total n’est pas utilisé pour les opérations d’écriture.
Note : après positionnement sans erreur, par l’utilisateur, du timeout, le port série est ouvert.
La classe serialCtl produit des méthodes qui seront appelées par les autres classes de notre application c’est
pourquoi elle ne présente pas de liaison dans le diagramme des classes de la page 1.
Gestion de la liaison par un thread
Pour que l’application puisse gérer la liaison série, on doit disposer d’une tâche qui gère le port série (en faisant
appel au driver SerialCtl).
Nous allons ajouter une nouvelle classe générique à notre projet : la classe SerialThread dont on voit le fichier
de définition qui est, à part le squelette, pratiquement vide.
Nous allons tout d’abord définir les éléments de cette classe en complétant le fichier SerialThread.h comme
ceci :
Pour que cette classe puisse faire appel au driver SerialCtrl, on définit la classe SCC dans ce même fichier
SerialThread.h.
Il faut maintenant définir le code correspondant dans le fichier serialthread.cpp.
On définit ci-dessous les paramètres par défaut lors de la construction et la destruction de l’instance de la
classe.
#njc Lycée « la Briquerie »
Programmation C++ : port série
& page 7/9
Voyons maintenant la méthode « run » qui représente les actions de gestion par la tâche du port série. Cette
méthode utilise les méthodes du driver SerialCtl mais aussi les données concernant la classe SerialAppDlg
interface de dialogue.
Quand la tâche est active, on effectue une boucle
sans fin.
On entre dans la première boucle si le processus
est actif.
On teste si le port est ouvert et si cela n’est pas le
cas, on l’ouvre.
On affiche le statut du port si :
L’ouverture est correcte
L’ouverture est incorrecte
Si le port est activé, on lit le message si il y en a
un de disponible.
On l’affiche dans la fenêtre correspondante
On désactive le processus.
S’il faut envoyer un message, on effectue la
transmission.
S’il faut fermer le port on le fait !
Voila nous disposons des outils nécessaires à la gestion de la liaison série mais revenons à notre interface
graphique pour laquelle il nous faut gérer l’action des différents boutons.
#njc Lycée « la Briquerie »
Programmation C++ : port série
& page 8/9
L’interface graphique : le retour !
La méthode OnBclose permet la fermeture du port
série en positionnant les indicateurs utilisés dans le
« thread » précédent puis va griser ou non les
autres boutons si nécessaire.
La méthode OnBexit permet de quitter
l’application en arretant le « thread » précédent.
On « détruit la fenêtre de dialogue.
La méthode OnBopen permet l’ouverture du port
série en positionnant les indicateurs utilisés dans le
« thread » précédent. On met à jour les données de
configuration. On lance le « thread » et ensuite on
va griser ou non les autres boutons si nécessaire.
La méthode OnBsend permet l’envoie des données
en positionnant l’indicateur utilisés dans le
« thread » précédent. On met à jour les données de
configuration.
La méthode UpdateConfig permet la mise à jour
du paramètre vitesse du port série.
#njc Lycée « la Briquerie »
Programmation C++ : port série
& page 9/9