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