|
|
|
|
Strumenti |
23-10-2012, 08:28 | #1 |
Senior Member
Iscritto dal: Sep 2003
Messaggi: 847
|
[Linux/C++] Scrittura Seriale mediante libreria termios
Ciao,
sto usando la libreria termios per scrivere dati tramite seriale su un modem. La scrittura avviene correttamente fino a quando non mi compare il seguente messaggio: write error 11 Resource temporarily unavailable Apro la porta in modalità non bloccante e la classe che uso è la seguente: Codice:
#include "cclassseriallib_modem.h" #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <string.h> #include <errno.h> cClassSerialLIB_modem::cClassSerialLIB_modem() { } bool cClassSerialLIB_modem::OpenPort(bool bloccante) { // make sure port is closed ClosePort(); fd = open("/dev/ttyUSB3", O_RDWR | O_NOCTTY | /* tells UNIX that this program doesn't want to be the "controlling terminal" for that port*/ O_NDELAY); /* tells UNIX that this program doesn't care what state the DCD signal line is in */ if (fd < 0) { printf("open error %d %s\n", errno, strerror(errno)); return false; } else { struct termios options; /* The FNDELAY option causes the read function to return 0 if no characters are available on the port. To restore normal (blocking) behavior, call fcntl() without the FNDELAY option: */ if(bloccante) { printf("bloccante\n"); fcntl(fd, F_SETFL, 0); } else { printf("NON bloccante"); fcntl(fd, F_SETFL, FNDELAY); } tcgetattr(fd, &options); //set port speed cfsetispeed(&options, B115200); cfsetospeed(&options, B115200); options.c_cflag |= (CLOCAL | CREAD); //set 8n1 options.c_cflag &= ~PARENB; /* Enable parity bit */ options.c_cflag &= ~CSTOPB; /* 2 stop bits (1 otherwise) */ options.c_cflag &= ~CSIZE; /* Mask the character size bits */ options.c_cflag |= CS8; /* Select 8 data bits */ /*options.c_cflag &= ~CRTSCTS; options.c_iflag &= ~IXON; //RIMUOVE X0N/XOFF control options.c_iflag &= ~IXOFF; options.c_iflag &= ~IGNCR; */ //set raw input options.c_lflag &= ~(ICANON | /* Enable canonical input (else raw) */ ECHO | /*Enable echoing of input characters */ ECHOE | /*Echo erase character as BS-SP-BS*/ ISIG); /*Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals*/ tcsetattr(fd, TCSANOW, &options); /*Make changes now without waiting for data to complete*/ } return true; } int cClassSerialLIB_modem::WritePort(QString psOutput) { int iOut; QByteArray ba = psOutput.toLocal8Bit(); if (fd < 1) { printf(" port is not open\n"); return -1; } // end if iOut = write(fd, ba.data(), strlen(ba.data())); if (iOut < 0) { printf("write error %d %s\n", errno, strerror(errno)); } else { printf("wrote %d chars: %s\n", iOut, ba.data()); } // end if return iOut; } int cClassSerialLIB_modem::ReadPort(QString * Response) { int iIn; char psResponse[254]; if (fd < 1) { printf(" port is not open\n"); return -1; } // end if iIn = read(fd, psResponse, 254); if (iIn < 0) { if (errno == EAGAIN) { return 0; // assume that command generated no response } else { printf("read error %d %s\n", errno, strerror(errno)); } // end if } else { psResponse[iIn<254?iIn:254] = '\0'; printf("read %d chars: %s\n", iIn, psResponse); } // end if *Response=QString::fromLocal8Bit(psResponse); return iIn; } void cClassSerialLIB_modem::ClosePort() { // you may want to restore the saved port attributes if (fd > 0) { close(fd); } // end if } Il problema è quando scrivo.. Ogni 50 ms mi arrivano i dati che dopo bypasso sulla seriale in questione. Sembra che ci sia un buffer che è piu lento a svuotarsi che a riempirsi come posso risolvere? grazie..
__________________
"VIVERE ARDENDO E NON SENTIRE IL MALE" |
23-10-2012, 13:08 | #2 |
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1816
|
Se apri uno stream in modalita' non bloccante e' naturale che ti appaia quell'errore di tanto in tanto.
Vuol semplicemente dire che stai scrivendo troppo velocemente e devi riprovare un po' dopo (per contro, se tu avessi aperto in modalita' bloccante la chiamata si sarebbe fermata in attesa dello svuotamento diqualche buffer). Soluzioni ? Se non e' cruciale che i dati arrivino in ritardo, apri la seriale in modalita' bloccante, oppure inserisci una attesa quando ricevi quell'errore (che in realta' non e' un vero e proprio errore). Se non e' cruciale spedire tutti i dati, ma spedire il piu' veloce possibile il piu' recente, puoi optare di scartare il dato se nono riesci a spedirlo (e' il caso ad esempio di quando vuoi spedire l'output di qualche sensore ). Se e' cruciale spedire tutti i dati e in tempo, allora non ti resta che cercare di far andare piu' veloce la seriale, il che vuol dire che intanto verifichi che viaggi alla velocita' che ti aspetti, e poi provare eventualmente con qualche altro mezzo.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
23-10-2012, 13:17 | #3 | |
Senior Member
Iscritto dal: Sep 2003
Messaggi: 847
|
Ciao grazie della risposta. Io sto usando una scheda hardware con linux embedded.. Su una seriale ricevo i dati da un dispositivo Bluetooth ed ho visto che li ricevo correttamente ogni 50ms.. Questi dati devono essere poi mandati ad un altra seriale ttyUSB3 che è connessa ad un modem che apre un socket su di un server.
Purtroppo i dati mi arrivano continuamente ogni 50ms! Se metto la modalità bloccante non mi appare più quell'errore ma di tanto in tanto perdo dei dati ad esempio: Quote:
__________________
"VIVERE ARDENDO E NON SENTIRE IL MALE" |
|
23-10-2012, 13:33 | #4 |
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1816
|
Si', perdi i dati perche' evidentemente la tua seriale non riesce a stare dietro alla periferica bluetooth.
Verifica se la quantita' di dati che leggi e' gestibile da una seriale. Hai configurato la seriale per 115kbit/sec ( cfsetispeed(&options, B115200); ), sicuro che ti bastano ? Sono meno di 15KB al secondo, inviando a 200Hz (50 ms tra una scrittura e l'altra) non puoi scrivere piu' di 75 byte alla volta (in realta' ancor meno). Mi sembra tu stia cercando di scrivere 254 byte al colpo, per cui... Verifica se la tua seriale supporta velocita' maggiori. Se cosi' non e' non ci sono alternative, devi "perdere" qualche messaggio e decidere come gestire la cosa
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
23-10-2012, 14:19 | #5 |
Senior Member
Iscritto dal: Sep 2003
Messaggi: 847
|
ottima spiegazione grazie!
potrei aumentare fino a 1152000 cosi dovrei inviare 720 byte alla volta.. ce la dovrei fare.. no? Ma come faccio a vedere poi se effettivamente vado a quella velocità?
__________________
"VIVERE ARDENDO E NON SENTIRE IL MALE" Ultima modifica di enaud : 23-10-2012 alle 14:29. |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 16:31.