Bonjour,
Je récupère un flux USB brute (sans aucun protocole) via un programme en C.
Le programme fonctionne correctement sans timeout.
Pour ajouter un timeout j'utilise la fonction "select()". Mais cela ne fonctionne pas, pourtant :
- La fonction "open()" fonctionne correctement et retourne 4
- Le timeout de select fonctionne correctement.
- Aucune erreur en retour de select (constamment un timeout)
- Malgré un flux USB entrant, "select()" ne détecte aucun caractère …
Je suis sous Ubuntu 16.04
Je vous envoie le programme.
J'ai déjà un peu d'expérience en C. Mais aucune sous linux, alors tout commentaire sera le bienvenue !
Merci !
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#define USB_RX_SIZE 0xFF
int main(int argc, char **argv)
{
/* --- INITIALISATION --- */
// ouverture du fichier
FILE* usbfile = fopen("/dev/ttyUSB0", "r+");
if(usbfile == NULL)
{
printf("fichier tty inexistant\n");
return 0;
}
// tableau de récupération des données
uint8_t usbRx[USB_RX_SIZE];
int i;
for(i = 0; i<USB_RX_SIZE; i++)
{
usbRx[i] = 0;
}
/* --- EMISSION --- */
for(i=0; i<strlen(argv[1]); i++)
{
fputc(argv[1][i], usbfile);
}
fputc('\r', usbfile);
fclose(usbfile);
// init de select() pour le TO
fd_set set;
struct timeval timeoutValue;
int rv_select;
int usbfile_select = open("/dev/ttyUSB0", O_RDWR);
FD_ZERO(&set);
FD_SET(usbfile_select, &set);
timeoutValue.tv_sec = 1;
timeoutValue.tv_usec = 0;
/* --- RECEPTION --- */
int idxRx = 0;
int timeout = 0;
do
{
rv_select = select(usbfile_select+1, &set, NULL, &set, &timeoutValue);
timeoutValue.tv_sec = 1;
timeoutValue.tv_usec = 0;
printf("%d\n", rv_select);
if(rv_select == -1)
{
printf("select error\n");
}
else if(rv_select == 0)
{
timeout = 1;
}
else
{
printf("data to read\n");
fread(&usbRx[idxRx], 1, 1, usbfile);
//read(usbfile_select, &usbRx[idxRx], 1);
idxRx++;
}
}while( (usbRx[idxRx-1] != '\n') && (idxRx < USB_RX_SIZE) && (timeout == 0) );
if(idxRx == USB_RX_SIZE)
{
printf("buffer full\n");
}
else if(timeout == 1)
{
printf("timeout expire\n");
}
else if(usbRx[idxRx-1] == '\n')
{
usbRx[idxRx] = '\0';
printf("%s\n", usbRx);
}
else
{
printf("error?\n");
}
return 0;
}
# double ouverture du fichier ?
Posté par flavien75 . Évalué à 0.
Ça m’étonne qu'on puisse ouvrir simultanément un même fichier avec fopen() et open().
Es-tu sûr que le open() a bien fonctionné et n'a pas renvoyé -1 ?
ça expliquerai pourquoi la suite se passe mal.
vu que usbfile_select+1 vaudrait 0, le select fonctionnerait en mode "tempo"
Après, si c'est bien ça, je n'ai pas d'idée sur comment faire le timeout sur un fichier ouvert avec fopen().
Les vrais naviguent en -42
[^] # Re: double ouverture du fichier ?
Posté par Pixerot . Évalué à 1.
C'est ce que je me suis dit. C'est pourquoi je fait un
fopen()
…
fclose()
…
open()
…
J'ai bien vérifié le retour des fonctions et aucune erreur …
# Port serie
Posté par -=[ silmaril ]=- (site web personnel) . Évalué à 3.
Hum, de ce que je vois tu n'est pas du tout en train de lire un "flux usb" mais un port serie, sur bus USB certes mais ce n'est rien d'autre qu'un port serie normal (enfin modulo que ton adapteur serie<=>usb soit de bonne facture).
Ne devrais tu pas configurer ton baud rate & compagnie avant tout du coup ?
Pour le select as tu essayé d'augmenter le timeout ça pourrait etre pas mal aussi
[^] # Re: Port serie
Posté par -=[ silmaril ]=- (site web personnel) . Évalué à 1.
Quelques bases sur la gestion des ports series
[^] # Re: Port serie
Posté par Pixerot . Évalué à 1.
Oui tu as bien raison c'est une com série via le port USB. Je me suis mal exprimé !
Ceci dit si j'utilise fread() pour récupérer les données caractères après caractères ça fonctionne, alors ce n'est pas un problème de configuration. Par contre si le flux série s'arrête prématurément fread() va bloquer le programme, alors que select() permet d'utiliser un timeout.
Je me demande si select() fonctionne sur un fichier de type ttyUSBx. Pourtant j'ai vu un exemple sur le net très proche de mon appli, c'était sur un fichier ttySx
Le timeout d'une seconde est correct, du moins lorsque j'exécute le programme il y a bien une seconde d'attente avant de m'indiquer l'erreur timeout.
Je regarderais tes liens ci-dessous ce soir … Merci !
[^] # Re: Port serie
Posté par -=[ silmaril ]=- (site web personnel) . Évalué à 1.
pas de raison, c'est un appel système géré par le kernel, cela va fonctionner quelque soit la source du flux.
Certes, mais est-ce que dans cet interval très court ton port série a vraiment eu le temps de bufferiser des données ?
# pourquoi select en particulier?
Posté par freem . Évalué à 2.
Une question, toute bête, mais pourquoi tu t'emmerdes avec
select()
?Ce n'est que m'on avis personnel, mais je trouve les codes qui utilisent select imbuvables, poll me semble tellement plus lisible, plus intuitif:
Au niveau avantages:
Les inconvénients… je n'en connais pas. Ah, si, la doc indique que c'est un peu plus récent (POSIX.1-2001, contre une apparition de select dans 4.4BSD) mais franchement, ça fait quand même plus de 15 ans, ça devrait le faire sur la plupart des systèmes.
Bon, tu fais ce que tu veux, mais ton bug est très probablement lié au fait que, justement, select ait une interface dégueulasse:
Tu utilises 2 fois la même structure, du coup, select, ben, il écrit 2 fois dedans…
# Usage du select
Posté par gato . Évalué à 1.
Bonjour,
select modifie les fd_set et les timeout, c'est pourquoi il faut les réinitialiser dans la boucle avant chaque appel.
Pour une meilleur portabilité préférez pselect ou son équivalent ppoll.
À noter : la résolution des timeouts est differente selon l'interface : poll en millisec, select en microsec, pselect et ppoll en nanosec.
[^] # Re: Usage du select
Posté par freem . Évalué à 4.
Dans le man:
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.