La lecture série de Linux génère une erreur

J’essaie de lire à partir de mon port série en utilisant le code C suivant. Je peux écrire avec succès sur un ordinateur en écoute (oui!), Mais la lecture renvoie une erreur (code 11 – ressource temporairement indisponible). J’ai également remarqué que mes journaux de messages / dmesg ne contiennent aucune information concernant les erreurs, etc. Donc c’est bien.

//A bunch of INCLUDES exist here....the the code int fd=0; int status=0; int running=1; char buffer[100]; char message[7]; void main(){ fd = 1; fd=open("/dev/ttyM0",O_RDWR | O_NOCTTY); if(fd == -1) { perror("open_port: Unable to open /dev/ttys0"); } else { while(running<20) { sprintf(message,"Test%d\r",running); status=write(fd,message,6); if(status<0) { printf("Error Writing. Status=%d\n %s\n",errno, strerror(errno)); } status=read(fd,buffer,8); //This throws an error(11). My connected device is writing "Testing/r" if(status<0) { printf("Error Reading. Status=%d \n%s\n",errno, strerror(errno)); //close(fd); running=running+1; } else { printf("%s\n\r",buffer); } sleep(2); } close(fd); } } //END MAIN 

Ce sont mes parameters de série pour mon port. J’essaie de lire / écrire à 9600 8 bits, pas de parité, 1 bit d’arrêt. Je pense que mes parameters sont corrects.

 sudo stty -a -F /dev/ttyM0 speed 9600 baud; rows 0; columns 0; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ; eol2 = ; swtch = ; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -issortingp -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke 

Toute aide serait très appréciée. Je vous remercie!

Avec O_NDELAY parti, le programme rest en attente de saisie

On dirait que termios est configuré pour une entrée canonique (basé sur icanon dans la sortie stty ). En mode canonique (c’est-à-dire cuit), les caractères reçus du port série sont traités avant d’être mis à la disposition du programme utilisateur à l’aide de read () .

Par la page de manuel Linux:

En mode canonique:

  • L’entrée est disponible ligne par ligne. Une ligne d’entrée est disponible lorsqu’un des délimiteurs de ligne est saisi (NL, EOL, EOL2; ou EOF en début de ligne). Sauf dans le cas de EOF, le délimiteur de ligne est inclus dans le tampon renvoyé par read (2).

Icrnl est également défini dans votre termios , ce qui signifie qu’un retour à la ligne est converti en nouvelle ligne en entrée (sauf si igncr est défini, ce qui n’est pas le cas car il comporte un tiret précédent). Eol et eol2 ne sont pas définis (qui sont les valeurs par défaut).

Ainsi, pour votre configuration, une fin de ligne est définie comme une nouvelle ligne ou un retour à la ligne (ou cntl-D au début de la ligne). Vérifiez que votre périphérique distant envoie effectivement un caractère de contrôle CR ou LF pour mettre fin à la ligne. Votre commentaire dans le code indique que ce n’est pas le cas (c’est-à-dire que “/ r” n’est pas un retour à la ligne).


Pour utiliser correctement le texte renvoyé par read () en tant que chaîne, définissez la demande sur une taille inférieure à la taille de la mémoire tampon allouée (afin de permettre l’ajout d’un terminateur nul). Ensuite, après un retour correct, utilisez le nombre d’octets renvoyés comme index pour stocker le terminateur de chaîne.

  status = read(fd, buffer, sizeof(buffer) - 1); if (status < 0) { /* handle error condition */ } else { buffer[status] = '\0'; printf("%s\n\r", buffer); } 

Vous utilisez l’option O_NDELAY dans votre appel open . Cela rend le descripteur de fichier non bloquant . Cela signifie que si vous effectuez une read et qu’aucune donnée n’est disponible, l’appel de read renverra EAGAIN qui correspond à l’erreur que vous voyez.

Pour le moment, vous pouvez supprimer le O_NDELAY de l’ open . À l’avenir, vous devriez probablement le rendre non bloquant à nouveau et utiliser select ou poll pour déterminer quand vous pourrez lire.

Vous avez un buffer overflow ici:

 sprintf(message,"Test%d\r",running); 

puisque le message est déclaré comme:

 char message[6]; 

message doit avoir une taille minimale de 7 caractères s’il doit contenir une chaîne de 6 caractères, en raison de la nécessité d’un terminateur '\0' .

Il peut également y avoir d’autres problèmes, mais vous devez résoudre ce problème et voir si cela fait une différence.