Lecture port com vc++, sans blocage ? - C - Programmation
Marsh Posté le 23-07-2012 à 16:37:44
il faut créer le port COM en mode OVERLAPPED , et ensuite faire un WaitForSingleObject sur le handle du port COM pour savoir s'il y a des données à lire ou non, et les lire le cas échéant. C'est un peu le même principe que le select en réseau.
Code :
|
Marsh Posté le 23-07-2012 à 17:44:22
Merci pour ta réponse rapide !
J'ai implémenté ta solution, effectivement, le programme attend bien le temps indiqué, puis laisse la main à l'interface.
Par contre, maintenant plus moyen de recevoir des données sur ce port, j'ai beau lui envoyer une trame, retwait vaut toujours "WAIT_TIMEOUT", à quoi est-ce du ?
J'ai créé une fonction renvoyant un DWORD (retwait), prenant en argument
- "unsigned char* buffer"
- "int portCOM" j'ai remplit 'buf' avec "\\\\.\\COM" + portCOM
- "int mybuffersize" qui correspond à la taille de la trame à recevoir
Le corps de la fonction correspond à ton code + remplissage de 'buf'
Marsh Posté le 24-07-2012 à 15:54:41
Petit up,
en fait j'ai implémenté la solution avec le port com overlapped, mon code est le suivant :
Code :
|
Le problème est que WaitForSingleObject(.....) renvoie toujours WAIT_TIMEOUT, même si j'envoie une trame sur le port désigné.
Je ne comprends pas vraiment pourquoi...
Marsh Posté le 24-07-2012 à 16:19:15
je regarderai en détail plus tard , juste pour info, j'ouvre le port com avec la chaine de caractère suivante : "COM1:" ou "COM2:" ou ...
Marsh Posté le 25-07-2012 à 11:29:17
Bon finalement j'ai contourné le problème.
Au lieu de configurer le port COM en OVRELAPPED, j'ai utilisé un timer.
A chaque évènement TICK du Timer, je lance une lecture sur le port COM, sauf que j'ai enlevé les boucles
- "while(nBytesMessageRecu < 2)"
- "while(nBytesMessageRecu + 3 < recept_COM[1] + 4)"
Ca fonctionne, avec une cadence de 10ms, le soft n'est pas bloqué, et les trames sont reçues.
Par contre, une fois sur deux environ, je ne reçoit pas la bonne trame, à quoi cela peut-il être du ? Peut être que à cause du timer, le prog commence à lire la trame "au milieu" de sa réception ?
Comment résoudre ce problème ? J'ai beau diminuer la cadence du timer, cela ne résout rien...
J'ai aussi une autre question qui me taraude, pour l'instant je déclare mes variables dans mes contrôles.
C'est à dire que à chaque TICK du timer (ou avant à chaque clic sur un bouton), je déclare mes variables (nBytesMessageRecu, recept_COM[]...).
Du coup ces dernières sont inaccessibles à l'extérieur de ce contrôle. Comment faire pour que mes variables soient accessibles depuis tous les contrôles ? J'ai bien essayé de les déclarer dans form_load, mais le problème est le même. Ou alors au début du fichier Form1.h, à cet endroit :
Code :
|
Mais j'ai des erreurs me disant que le type est managé et que cela n'est donc pas possible.
Ou les déclarer dans ce cas ? Ou alors comment y accéder depuis les autres contrôles ?
Merci d'avance
Marsh Posté le 25-07-2012 à 14:48:49
Pour tes problèmes de lecture, ca me semble normal si tu utilises la fonction LectureCom de ton message précédent. A chaque appel tu ouvres le port, vides les buffers puis le referme.
Si tu es parti pour faire du C#, il faut (faudrait) que tu te fasse une classe pour gérer le port série avec :
- une méthode pour ouvrir et configurer les port (à appeler dans le constructeur de ta form)
- une méthode pour fermer le port (à appeler dans le destructeur de ta form)
- une methode de lecture, soit non bloquante à appeler dans un timer, soit bloquante à appeler dans un thread (suivant les paramètres de SetCommTimeout)
et déclarer une instance de cette classe dans la partie 'protected' du code que tu a posté ci-dessus.
Marsh Posté le 25-07-2012 à 15:38:35
Pour le coup des variables accessibles uniquement dans le contrôle où elles sont déclarées, le problème est réglé.
J'ai crée un fichier .h dans lequel j'ai fait mes déclarations, et j'ai inclus ce fichier au début de mon form1.h
Après pour la lecture du port COM, je n'ai pas précisé, je n'ai en fait pas utilisé la fonction LectureCOM.
Enfin au final tu as raison, j'ouvre et ferme le port série à chaque fois.
Effectivement, à chaque évènement Tick, je fais ceci :
Code :
|
Si j'ai bien compris, ce que tu me conseille de faire, c'est :
- Ouvrir le port série au lancement de l'application
- Lire le port série dans un timer, ou avec un thread
- Fermer le port quand on quitte l'application
C'est bien ça ?
Le problème, c'est que je dois pouvoir modifier le port COM à lire quand l'application est lancée, du coup il faudrait ouvrir le port COM quand on modifie le n° du port ?
Et le fermer (si il a été ouvert) à ce moment aussi ?
Marsh Posté le 26-07-2012 à 12:56:59
petit up !
J'ai résolu le problème de réception COM, j'ai rajouté une condition sur le premier octet recu (si il vaut bien 0x01 on continue à lire, sinon on réessaie), et ça fonctionne !!
Du coup il ne me reste plus qu'un problème à régler dans mon projet, c'est à dire pouvoir envoyer la trame reçue (une fois convertie) via le port Ethernet.
Pour l'instant ça fonctionne (du moins en local, je n'ai pas testé entre deux PCs), mais le problème est le même que pour le port série.
L'envoi se fait sur le click d'un bouton, et tant que le client ne s'est pas connecté, le programme est bloqué.
Par contre cette fois je ne pense pas pouvoir contourner le problème avec un timer, vu que pour envoyer la trame j'utilise la fonction suivante :
csock = accept(..., ..., .......);
qui elle est bloquante.
Donc à moins de pouvoir utiliser une fonction non bloquante qui ferait à peu près la même chose, je vais devoir utiliser les threads ?
Mais je suis un peu perdu, je ne vois pas vraiment quelles fonctions utiliser, pthreat_create() et pthread_join() ???
Marsh Posté le 27-07-2012 à 08:21:11
Bonjour !
Effectivement, la fonction "accept" est bloquante, mais la fonction "select" permet de résoudre le problème, car elle permet de savoir si il y a un client en attente sur la "listening socket" (celle sur laquelle vous faites le accept).
Lors de l'appel, vous rajoutez le "file descriptor" de la socket dans le paramètre "readfs" et si un client est en attente, la socket est marquée comme ayant des données à lire, et vous pouvez lancer l'appel "accept" qui rendra la main tout de suite.
Marsh Posté le 01-08-2012 à 14:16:52
Merci pour ta réponse, ça m'a pas mal aidé quand j'en avais besoin.
Finalement, j'ai du utiliser les threads, et au final c'est pas si compliqué que ça, il faut faire gaffe et bien savoir ce que l'on fait mais ça va tout seul !
Marsh Posté le 23-07-2012 à 15:44:10
Bonjour,
dans le cadre d'un stage, je dois réaliser une application qui récupère une trame via un port COM, ensuite convertir ces données, puis les envoyer sur un port Ethernet.
J'ai tout d'abord réalisé cette appli avec visual studio 2010, mais avec la console, le code fonctionne.
Maintenant je dois réaliser une interface graphique, j'ai donc opté pour des windowsforms sur vc++.
Le code fonctionne toujours, je peux recevoir des données via le port COM, puis les convertir et les envoyer sur le port Ethernet.
Mon seul problème est que j'ai utilisé un bouton pour lancer la lecture dur port COM, et que une fois le bouton appuyé, l'appli est bloquée tant qu'une trame n'est pas reçue sur le port COM.
Pour l'instant, le code de mon bouton est le suivant :
Afin de résoudre ce problème, j'ai pensé à utiliser un timer, cette fonction se terminerait au bout de x secondes si elle n'a pas reçu de trame, mais je ne vois pas vraiment comment m'y prendre.
Ou alors utiliser des threads, mais là je vois encore moins, surtout qu'une fonction appellée dans un thread ne peut avoir qu'un argument ?
Si vous avez des idées, des pistes, je vous en remercie d'avance !
---------------
Mon topic de ventes matos informatique : http://forum.hardware.fr/hfr/Achat [...] 1897_1.htm