Précédent   Forum du club des développeurs et IT Pro > Général Développement > Programmation système > Windows
Windows Forum d'entraide sur la programmation Windows. Tutoriel API Windows
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 13/10/2012, 11h43   #1
vdary
Invité régulier
 
Homme
Lycéen
Inscription : septembre 2012
Messages : 10
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Lycéen
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : septembre 2012
Messages : 10
Points : 5
Points : 5
Par défaut Port série overlapped: problème de récupération des données

système: windows 7
IDE: code::block

Bonjour,

Je sollicite encore une fois de l'aide sur ce site car j'ai rencontré un problème pour programmer un événement sur un port série sous windows.

Mon but est d'abord de créer un "time out" sur la fonction de lecture du port série ( ReadFile() ) pour qu'elle ne bloque pas indéfiniment le programme, ça j'ai pu le faire avec la fonction SetCommTimeout(). Ce "time out" une fois configuré, on peut invoquer la fonction ReadFile() qui se stoppe au bout du temps configuré précédemment, mais le problème c'est que si on reçoit des données à la moitié du "time out" il faut attendre la totalité du temps pour pouvoir traiter les données.

Donc, dans un deuxième temps, j'ai voulu instauré un événement avec un "time out" qui, lui, stoppe quand des données sont présentes sur le port série (ou plutôt dans les buffers internes du port série...enfin là je suis pas sur)
Ça aussi j'ai réussit à le réaliser, mais mon problème vient du fait que je n'arrive pas à récupérer les données après que l'événement se soit déclenché.

En fait mon programme réagit très bien, j'ai raccordé deux pc, sur l'un j'ai créer un générateur de trame qui envoi une chaîne de caractère passé en argument et sur l'autre il y a mon programme avec un événement qui attend des données en réception. Quant je déclenche le générateur de trame, mon événement détecte les données, puis il invoque la fonction ReadFile() qui au passage génère une erreur ( ERROR_IO_PENDING -> Overlapped I/O operation is in progress), puis j'affiche mon buffer de réception et là rien :p .

(ps: je vous rassure mes port COM sur chaque pc sont configurés exactement pareil)

Je pense que l'erreur générée y est pour quelque chose, et encore je ne croie pas (là aussi je ne suis pas sur).

Voici mon code :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define READ_TIMEOUT      9000

int main()
{

  HANDLE fd = NULL;   // descripteur de fichier du port com
  struct _DCB info;   // struture de configuration du port com
  unsigned char buffer_r[101];    // buffer de donnees de reception
  DWORD bit_rw;	// variable du nombre d'octet ecrit sur le port com
  char port[]="COM4\0";  // identifiant du port com sur le système

// ouverture du port com

	fd = CreateFile(	                port,
						GENERIC_READ | GENERIC_WRITE,
						0,
						NULL,
						OPEN_EXISTING,
						FILE_FLAG_OVERLAPPED,
						NULL );

	if(fd == INVALID_HANDLE_VALUE)
	{
		printf("\n :: Erreur d'ouverture du port %s ::\n", port);
		exit(0);
	}
	else printf("\n :: Ouverture du port %s ::\n", port);


// recuperation de la configue du port com

	memset(&info, '\0', sizeof(struct _DCB));

	//	recupere la configue du port com
	if ( GetCommState(fd, &info) == 0)
	{
		printf(" :: Impossible de recuperer la configuration du port %s ::\n", port);
		exit(0);
	}
	else printf(" :: Configuration actuelle du port %s ::\n", port);


// configuration du port com pour une utilisation classique  8N1 (8 data bits, N no parity, 1 stop bit)

	info.ByteSize = 8;
	info.BaudRate = CBR_9600;
	info.Parity   = NOPARITY;
	info.StopBits = ONESTOPBIT;
	
	info.fBinary = 1;
	info.fParity = 0;
	info.fNull = 0;

	info.fOutxCtsFlow = 1;
	info.fOutxCtsFlow = 1;
	
	info.fDtrControl = DTR_CONTROL_ENABLE;
	info.fRtsControl = RTS_CONTROL_ENABLE;
	
	//	configure le port com	
	if( SetCommState(fd, &info) == 0)
	{
		printf("\n :: Impossible de configurer le port %s ::\n", port);
		exit(0);
	}
	else printf("\n :: Changement de la configuration du port %s ::\n", port);


// création de l'événement

	OVERLAPPED com_ev  = {0};  
	DWORD mask;
	DWORD iHandle;

	com_ev.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); // crée l'événement

	SetEvent( com_ev.hEvent ); // enregistre l'événement
	
	SetCommMask( fd, EV_RXCHAR ); // spécifie le type d'événement (ici EV_RXCHAR indique que l'on attend une donnée sur la broche RX de reception du port série)

	WaitCommEvent( fd, &mask, &com_ev ); // enregistre le type d'événement souhaité

	
	iHandle = WaitForSingleObject(com_ev.hEvent, READ_TIMEOUT); // attend que l'événement souhaité se produise, avec une valeur de time out de 9s

	if( iHandle == WAIT_OBJECT_0 ) // si l'événement c'est réalisé avec succée alors on récupére les données
	{
		if( ReadFile(fd, &buffer_r, (sizeof(buffer_r)-1), &bit_rw, &com_ev) == 0 ) // lit les données sur le port série
		{
			printf("ERROR: %ld\n\n", GetLastError() );
		}
		
		printf(" buffer de reception: \n\n %s\n\n\n", buffer_r );  // affiche le buffer de reception des données
		
	}
Voilà, je pense qu'il y a quelque chose que je n'ai pas compris, peut-être que mon code n'est pas bon, la fonction ReadFile() n'est peut être pas à la bonne place.
J'ai aussi pensé que je devais mal configurer ma structure _DCB qui à son tour paramètre le port série (c'est probable).
J'ai testé tout un tas de chose dont voici les liens et rien ne marche ou du moins je suis pas doué. En tout cas j'ai trouvé aucun exemple propre qui fonctionne :

http://cpp.developpez.com/faq/vc/?page [...] ithSerialPort (je me suis inspiré de celui-ci)
http://msdn.microsoft.com/en-us/librar [...] serial_topic4

Merci d'avance pour toute réponse ou lien qui pourrait me mettre sur la voie.
vdary est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/10/2012, 09h48   #2
Médinoc
Expert Confirmé Sénior
 
Avatar de Médinoc
 
Homme
Développeur informatique
Inscription : septembre 2005
Messages : 22 396
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 29
Localisation : France

Informations professionnelles :
Activité : Développeur informatique
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : septembre 2005
Messages : 22 396
Points : 32 049
Points : 32 049
Envoyer un message via MSN à Médinoc
Overlapped, c'est pour les lectures/écritures asynchrones.
En gros, tu dois démarrer la lecture avec ReadFile(), puis attendre sur ton événement, puis tu peux utiliser ton buffer.
__________________
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone.
-- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Médinoc est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/10/2012, 20h15   #3
vdary
Invité régulier
 
Homme
Lycéen
Inscription : septembre 2012
Messages : 10
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Lycéen
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : septembre 2012
Messages : 10
Points : 5
Points : 5
Merci pour le conseille et effectivement j'arrive bien à lire les données maintenant mais j'ai un nouveau problème pour la récupération des données.

Je n'arrive pas à récupérer toute les données en déclarant un événement sur l'arrivé d'un caractère sur le port série et parfois elles sont manquantes.
Par contre j'arrive à récupérer l'ensemble des donnée si je place un événement sur l'arrivé d'un caractères de contrôle que je paramètre auparavant; mais avec une contrainte qui est de savoir le nombre totale d'octets qui va arrivé et que ce caractère de contrôle ce trouve à la fin de la trame.

D'autre part le nombre d'octet lue par ReadFile() est faussé, il est inférieur au nombre vraiment lue.

Donc je suis contraint d'une part d'avoir des trame avec un caractère de contrôle à la fin et d'autre part de savoir la taille de celle-ci. Le problème ]est que mon dispositif avec le quel je communique génère des trames avec un caractère de contrôle qui ce trouve au début de la trame et qui sont de taille variable.

voicie mon code:

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define READ_TIMEOUT      9000


int main()
{

	HANDLE fd = NULL;   // descripteur de fichier du port com
	struct _DCB info;   // struture de configuration du port com
	struct _COMMTIMEOUTS time;
	unsigned char buffer_r[101];    // buffer de donnees de reception
	DWORD bit_rw = 0;	// variable du nombre d'octet ecrit sur le port com
	char port[]="COM4\0";  // identifiant du port com sur le système
	int size;


	memset( buffer_r, '\0', sizeof(buffer_r) );

// ouverture du port com

	fd = CreateFile(	port,
						GENERIC_READ | GENERIC_WRITE,
						0,
						NULL,
						OPEN_EXISTING,
						FILE_FLAG_OVERLAPPED,
						NULL );

	if(fd == INVALID_HANDLE_VALUE)
	{
		printf("\n :: Erreur d'ouverture du port %s ::\n", port);
		exit(0);
	}
	else printf("\n :: Ouverture du port %s ::\n", port);





// recuperation de la configue du port com

	memset(&info, '\0', sizeof(struct _DCB));

	//	recupere la configue du port com
	if ( GetCommState(fd, &info) == 0)
	{
		printf(" :: Impossible de recuperer la configuration du port %s ::\n", port);
		exit(0);
	}
	else printf(" :: Configuration actuelle du port %s ::\n", port);

// configuration du port com pour une utilisation classique  8N1 (8 data bits, N no parity, 1 stop bit)

	info.ByteSize = 8;
	info.BaudRate = CBR_9600;
	info.Parity   = NOPARITY;
	info.StopBits = ONESTOPBIT;

	info.EofChar = 'o';
	info.EvtChar = 'o';
	
	/*	configure le port com	*/
	if( SetCommState(fd, &info) == 0)
	{
		printf("\n :: Impossible de configurer le port %s ::\n", port);
		exit(0);
	}
	else printf("\n :: Changement de la configuration du port %s ::\n", port);

OVERLAPPED com_ev = {0};
	DWORD mask;
	DWORD iHandle;
	char buffer_2  = {0};
	
	
	
	com_ev.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

	
	SetEvent( com_ev.hEvent );
	
	SetCommMask( fd, EV_RXFLAG );

	WaitCommEvent( fd, &mask, &com_ev );

	// vous pouvez voir ici que je met ici la taille des données à recevoir
        // soit neuf caractère
	ReadFile(fd, &buffer_r, /*(sizeof(buffer_r)-1)*/ 9 , &bit_rw, &com_ev);

	
	iHandle = WaitForSingleObject(com_ev.hEvent, READ_TIMEOUT);
	

	GetOverlappedResult( com_ev.hEvent, &com_ev, &bit_rw, FALSE);		
	
	if(bit_rw)
	{
	
		printf(" buffer de reception %ld bytes: \n\n %s\n\n\n", bit_rw, buffer_r);
	}
	
	ResetEvent( com_ev.hEvent );
	
}
Voici la trame que je génére:
Code :
1
2
3
4
5
Abcdefgho
        |
        |
         caractère de contrôle
le retour écran de mon programme:

Code :
1
2
3
4
5
buffer de réception 4 bytes: Abcdefgho
                    |
                    | 
                  nombres d'octet lue faussé
Comment récupérer toute des données de taille variable et avec le bon nombre d'octet lue, je pense que j'ai vraiment loupé quelque chose.

Merci d'avance pour votre aide, là vraiment je bloque.
vdary est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/10/2012, 12h36   #4
vdary
Invité régulier
 
Homme
Lycéen
Inscription : septembre 2012
Messages : 10
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Lycéen
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : septembre 2012
Messages : 10
Points : 5
Points : 5
J'ai trouvé ce matin une méthode pour récupérer une trame entière sans le caractère de contrôle, en utilisant un événement sur un "break" sur le port série:

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define READ_TIMEOUT      9000


int main()
{

	HANDLE fd = NULL;   // descripteur de fichier du port com
	struct _DCB info = {0};   // struture de configuration du port com
	unsigned char buffer_r[101];    // buffer de donnees de reception
	DWORD bit_rw = 0;	// variable du nombre d'octet ecrit sur le port com
	char port[]="COM4\0";  // identifiant du port com sur le système
	int size;


	memset( buffer_r, '\0', sizeof(buffer_r) );

// ouverture du port com

	fd = CreateFile(	port,
						GENERIC_READ | GENERIC_WRITE,
						0,
						NULL,
						OPEN_EXISTING,
						FILE_FLAG_OVERLAPPED,
						//FILE_ATTRIBUTE_SYSTEM,
						NULL );

	if(fd == INVALID_HANDLE_VALUE)
	{
		printf("\n :: Erreur d'ouverture du port %s ::\n", port);
		exit(0);
	}
	else printf("\n :: Ouverture du port %s ::\n", port);

// recuperation de la configue du port com

	memset(&info, '\0', sizeof(struct _DCB));

	//	recupere la configue du port com
	if ( GetCommState(fd, &info) == 0)
	{
		printf(" :: Impossible de recuperer la configuration du port %s ::\n", port);
		exit(0);
	}
	else printf(" :: Configuration actuelle du port %s ::\n", port);

// configuration du port com pour une utilisation classique  8N1 (8 data bits, N no parity, 1 stop bit)

	info.ByteSize = 8;
	info.BaudRate = CBR_9600;
	info.Parity   = NOPARITY;
	info.StopBits = ONESTOPBIT;

	
	/*	configure le port com	*/
	if( SetCommState(fd, &info) == 0)
	{
		printf("\n :: Impossible de configurer le port %s ::\n", port);
		exit(0);
	}
	else printf("\n :: Changement de la configuration du port %s ::\n", port)


	OVERLAPPED com_ev = {0};

	DWORD mask = EV_BREAK;
	
	DWORD iHandle;
	char buffer_2  = {0};
	
	
	
	com_ev.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
	
	SetEvent( com_ev.hEvent );
	
	SetCommMask( fd, EV_BREAK );	
	
	WaitCommEvent( fd, &mask, &com_ev );
	
	
	ReadFile(fd, &buffer_r, /*(sizeof(buffer_r)-1)*/9, &bit_rw, &com_ev);

	
	SetupComm( fd, 101, 101 );
	
	
	iHandle = WaitForSingleObject(com_ev.hEvent, READ_TIMEOUT);
	

	GetOverlappedResult( com_ev.hEvent, &com_ev, &bit_rw, FALSE);		
	
	if(bit_rw)
	{
		printf(" buffer de reception %ld bytes: \n\n %s\n\n\n", bit_rw, buffer_r);
	}
	
	ResetEvent( com_ev.hEvent );



}

Voilà mais je bloque toujours pur recevoir des données de taille variable donc si vous avez des idées à me proposé je suis preneur.

Merci d'avance pour votre aide.

Amicalement et librement
vdary est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 07h06.


 
 
 
 
Partenaires

Hébergement Web