+ Répondre à la discussion
Affichage des résultats 1 à 4 sur 4
  1. #1
    Invité régulier
    Homme Profil pro
    Lycéen
    Inscrit en
    septembre 2012
    Messages
    11
    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 : 11
    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.

  2. #2
    Expert Confirmé Sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    septembre 2005
    Messages
    24 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France

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

    Informations forums :
    Inscription : septembre 2005
    Messages : 24 287
    Points : 34 576
    Points
    34 576

    Par défaut

    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.

  3. #3
    Invité régulier
    Homme Profil pro
    Lycéen
    Inscrit en
    septembre 2012
    Messages
    11
    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 : 11
    Points : 5
    Points
    5

    Par défaut

    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.

  4. #4
    Invité régulier
    Homme Profil pro
    Lycéen
    Inscrit en
    septembre 2012
    Messages
    11
    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 : 11
    Points : 5
    Points
    5

    Par défaut

    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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •