2010-07-12 9 views
7

J'ai donc ce code de test pour envoyer « BONJOUR » sur un port USB série:write() C ne pas envoyer des données jusqu'à la fermeture (fd) est appelé

int fd; 
struct termios tty; 

if((fd = open("/dev/ttyUSB0", O_WRONLY|O_NONBLOCK|O_NOCTTY)) == -1){ 
err(1, "Cannot open write on /dev/ttyUSB0"); 
} 

tcgetattr(fd, &tty); 
tty.c_iflag = 0; 
tty.c_oflag = 0; 
tty.c_lflag = 0; 
tty.c_cflag = 0; 
tty.c_cc[VMIN] = 0; 
tty.c_cc[VTIME] = 0; 
cfsetospeed(&tty, B19200); 
cfsetispeed(&tty, B19200); 
tty.c_cflag |= CREAD|CRTSCTS|HUPCL|CS8; 
tcsetattr(fd, TCSANOW, &tty); 

printf("Write: %i\n", write(fd, "HELLO", 5)); 

sleep(5); 

if(close(fd) != 0){ 
warn("Could not close write fd"); 
} 

Le programme exécute bien et « BONJOUR "est envoyé mais il y a un problème. "HELLO" ne semble pas être envoyé lorsque la fonction write() est appelée, mais plutôt lorsque le descripteur de fichier est fermé. J'ai ajouté la ligne sleep (5) ci-dessus pour tester cette théorie et bien sûr, "HELLO" est envoyé ~ 5 secondes après l'exécution du programme. Comment puis-je obtenir "HELLO" à envoyer immédiatement après la commande write() au lieu de close()?

+0

Avez-vous vérifié la ' tcsetattr' renvoie la valeur? – jweyrich

+0

tcsetattr renvoie 0 – Ryan

+0

Vous dites "HELLO" ** semble ** à envoyer lorsque la fonction write() est appelée Comment est-ce que vous établissez exactement? Etes-vous sûr qu'il n'est pas envoyé immédiatement? et l'appareil ne traite tout simplement pas t? –

Répondre

5

De la page de manuel de write():

Un retour réussi d'écriture() ne fait aucune garantie que les données ont été commises sur le disque. En fait, sur certaines implémentations buggées, il ne garantit même pas que de l'espace a été réservé avec succès pour les données. La seule façon d'être sûr est d'appeler fsync (2) une fois que vous avez fini d'écrire toutes vos données.

Vous devez appeler fsync() sur votre descripteur de fichier pour vous assurer que les données sont effectivement validées.

+0

Ajout de "fsync (fd);" juste après que la ligne write (fd) renvoie -1: "Argument invalide". – Ryan

+0

Que dit 'errno'? –

+7

Sans lien. Le problème est que le périphérique terminal est en mode ligne-buffered. –

0

le tampon n'est pas purgé. fflush.

+1

fflush a besoin d'un fichier *, ici OP a un descripteur de fichier (et voudrait probablement ne pas utiliser stdio) –

+0

'fdopen' peut être utilisé; Si cela résout le problème OP et il n'a aucune raison de ne pas utiliser le gestionnaire de fichiers au lieu du descripteur de fichier. – ShinTakezou

0

Veuillez consulter this question. BAsiquement, vous devez vider le fichier pour que l'E/S ait lieu quand vous le voulez.

0

Essayez de faire un

fflush(NULL); 

après la write(). Peut-être qu'il y a un tampon interne qui n'est pas vidé.

+1

à résoudre le problème pour 2 raisons: 1) fflush se soucie-t-il des fichiers ouverts avec open?peut-être qu'un fdopen est requis; 2) les notes de la page man: fflush() vide uniquement les tampons d'espace utilisateur fournis par la bibliothèque C. Pour s'assurer que les données sont stockées physiquement sur le disque, les tampons du noyau doivent être vidés aussi, par exemple, avec sync (2) ou fsync (2) – ShinTakezou

2

Les ports de sortie sont souvent mis en mémoire tampon, de sorte qu'il existe un écart plus ou moins important entre l'écriture dans un flux de sortie et le contenu qui est réellement envoyé sur le disque, la ligne ou autre. C'est généralement pour l'efficacité.

Voir fflush (3) pour forcer le tampon à être validé en sortie.

Vous pouvez également ouvrir le descripteur de sortie d'une manière qui le rend non-bufferisé, mais en utilisant fflush pour dire 'c'est fini, j'ai terminé', c'est probablement mieux.

+0

Ooops, oui, fflush (3) est pour 'FILE *', et comme d'autres ont souligné, fsync (2) est probablement ce que vous voulez si vous avez besoin d'utiliser des FD. –

+0

En fait, regardez fcntl (2) sur votre plate-forme. Sur certaines plateformes, cela vous permettra de désactiver la mise en mémoire tampon pour la sortie, mais ce n'est pas portable. Si vous voulez abandonner complètement la portabilité, alors les ioctls pour votre appareil vous aideront probablement, mais cela devient désespéré. –

+0

fd -> fdopen -> fh; fh -> fileno -> fd ... le problème n'est pas d'avoir "FILE *" ou fd (si la conformité est pour POSIX et pas strictement C89/C99) – ShinTakezou

0

Modifier cette ligne:

tty.c_cc[VMIN] = 0; 

à ceci:

tty.c_cc[VMIN] = 1; 
+0

Juste essayé cela et cela n'a pas aidé – Ryan

7

Le dispositif est un dispositif de TTY, donc fsync ne va pas aider, peut-être pas fflush non plus.

Par défaut, le périphérique fonctionne en mode canonique, ce qui signifie que les données sont regroupées en unités de lignes. Vous trouverez probablement que l'ajout d'une paire cr/lf à vos données entraînera son envoi.

Vous devez vous assurer que le mode canonique est désactivé. En outre, la réponse de R sera utile.

http://en.wikibooks.org/wiki/Serial_Programming/termios

+0

Pouvez-vous s'il vous plaît poster votre configuration appropriée ici? –

2

d'abord, aucune idée pourquoi vous devez d'abord définir tous les champs de termios à 0, puis plus tard, sans aucune modification de ce 0 précède, décider de mettre les drapeaux rs232 habituels sur le cflag. (plutôt que de le faire sans l'OR directement, où vous le mettez maintenant à 0, ci-dessus). Ce qui vous plairait - au lieu de mettre tous ces drapeaux - est juste cfmakeraw() les champs de termios.

également, sync(); sans aucun paramètre (PAS fsync!;) semble envoyer toutes les sorties en attente à TOUS les fichiers de texte, pas seulement les périphériques de bloc. aussi sockets tcp et rs232 ..

et aussi open() a une option O_SYNC (O_SYNC et O_ASYNC ont des noms confus mais n'ont rien à voir avec le protocole de ligne série étant cadencé ou non, celui commente immédiatement write() ' s et l'autre produit un signal de piégeage lorsque l'entrée devient disponible (rs232 base un peu comme IRQ sur dos;)

réglage O_SYNC en plein air() pourrait déjà résoudre votre problème

également « en lisant les données. à l'autre extrémité '... il y a ces choses appelées' leds 'et' résistances 'que vous pouvez simplement connecter à TXD et VOIR les données;) il y a aussi des choses appelées' rs232 breakout box 'ou une portée qui peut le rendre -directement visible-;) beaucoup plus facile que "deviner" quel côté ne se comporte pas correctement.

AVERTISSEMENT: N'A PAS TESTÉ LE CODE. il compile. mais j'ai tous mes câbles ttyUSB0 dans un autre bâtiment. mais je pense que votre problème principal est O_SYNC de toute façon. définir tous les cries termios à 0 est à peu près la même chose que cfmakeraw() ... aussi pourquoi définir CREAD si vous allez l'ouvrir en écriture seule? (pourquoi l'écrire seulement plutôt que readwrite de toute façon?) et aussi avec write seulement vous ne devrez pas avoir peur de devenir un tty de contrôle (O_NOCTTY;) donc dans le cas d'écriture seulement, ce n'est pas vraiment nécessaire non plus .. .

juste remarqué le% i (même pour% d BTW) formatter déclenche également un décalage de type d'avertissement la valeur de retour de ssize_t d'écriture() si casted que pour (int)

#include<termios.h> 
#include<stdio.h> 
#include<unistd.h> 
#include<fcntl.h> 

void main(){ 
int fd; 
struct termios tty; 
fd=-1; 
while(fd<0){fd=open("/dev/ttyUSB0",O_WRONLY|O_NONBLOCK|O_NOCTTY|O_SYNC);sleep(1);}; 
cfmakeraw(&tty); 
tty.c_cflag=CREAD|CRTSCTS|HUPCL|CS8; 
cfsetospeed(&tty,B19200); 
cfsetispeed(&tty,B19200); 
tcsetattr(fd,TCSANOW,&tty); 
printf("Write: %i\n",(int)write(fd,"HELLO",5)); 
sync();//if all else fails, also try without, O_SYNC should already fix that. 
close(fd); 
};