Forum: Compiler & IDEs read() and delay


von Ralph F. (feu)


Lesenswert?

Hallo,
ich bin dabei die uart1 Schnittstelle auf einem BF537-stamp uClinux 
Plattform zu configurieren. Angeschlossen ist ein GSM modem, was über 
AT-Befehle gesteuert wird.
Wird ein AT-Befehl gesendet antwortet das modem normalerweise mit OK. 
read() wird gleich nach send() aufgerufen und sollte warten bis was 
kommt. So viel ich weiss gibt read() null zurück wenn nach ablauf eines 
timers nichts angekommen ist. Nun ist dieses Interval aber zu kurz. wenn 
mir jemand sagen kann wie ich den timer verändern kann, wäre prima. also 
ich meine nicht tty_config.c_cc[VTIME] und select() wollte ich erstmal 
nicht nehmen.
hat jemand eine idee?
vielen Dank im voraus

ralph

von Tom M. (tomm) Benutzerseite


Lesenswert?

Ralph Feuchter schrieb:
> So viel ich weiss gibt read() null zurück wenn nach ablauf eines
> timers nichts angekommen ist.

Du solltest dir Gewissheit verschaffen, indem du das manual der 
verwendeten Implementierung (GNU libc?) konsultierst.

Arbeitest mit der GNU library und setzt den Timer mit timerfd_create() 
auf?

von Andreas B. (andreas_b77)


Lesenswert?

Ein Rückgabewert 0 von read() im Unix-Stil heißt "end of file". Das 
heißt, auf diesem file descriptor kann man auch in Zukunft nur "end of 
file" lesen.

Und wieso send()? Das ist für Sockets, aber hier geht es doch um eine 
serielle Schnittstelle, richtig?

von feu (Gast)


Lesenswert?

klar doch, ich meine natürlich write() sorry!!!

so viel ich bisher weiss gibt read() die Anzahl der empfangen bytes 
zurück, wenn welche zum Abholen im tty bereitliegen. Ist nichts da bevor 
der timer abgelaufen ist, kommt NULL raus und wenn was schief ging <0. 
Die Frage war wie der Timer heist und wie ich ihn verändern kann. Der 
tip mit timer_fd scheint kein schlechter Weg zu sein, nur weiss ich 
nicht ob uClinux das auch unterstützt. muss es erst ausprobieren und 
meld mich wieder.
vielen dank jedenfalls!!

von feu (Gast)


Lesenswert?

danke für den tip. hoffe uClinux unterstützt das auch. ich meld mich 
wieder. ralph

von Andreas B. (andreas_b77)


Lesenswert?

feu schrieb:
> so viel ich bisher weiss gibt read() die Anzahl der empfangen bytes
> zurück, wenn welche zum Abholen im tty bereitliegen. Ist nichts da bevor
> der timer abgelaufen ist, kommt NULL raus und wenn was schief ging <0.

Falsch. 0 (nicht NULL) heißt "end of file" und sonst nichts. Wenn der 
Deskriptor mit der Option O_NONBLOCK geöffnet ist und bei read() nichts 
zum Lesen vorliegt, gibt es sofort -1 zurück mit errno gesetzt auf 
EAGAIN. Ohne O_NONBLOCK wartet es bis etwas da ist, potentiell endlos, 
außer es wird durch ein externes Signal unterbrochen. Da gibt es keinen 
Timer.

Hat überhaupt das write() ohne Fehler funktioniert und alle Zeichen 
gesendet? Es klingt mir irgendwie so, als ob die Fehlererkennung fehlt, 
also erstmal alle open/write/read Aufrufe auf Fehler abfragen und in dem 
Falle den Fehlercode in errno ausgeben (Tip: mit perror() kann man 
automatisch einen beschreibenden Text zum Fehler in errno ausgeben 
lassen).

von Ralph F. (feu)


Lesenswert?

vielen Dank Andreas. habe alles noch mal neu aufgesetzt und jetzt geht 
es.schwer zu sagen woran es nun gelegen hat.  am Ende wars ein 
Interpretationsfehler von mir.
Wie du sagst, es gibt tatsächlich keinen timer. Aber was könnte mann 
dann machen um zu vermeiden, dass wenn das modem nicht mehr reagiert die 
read() funktion nach gegebener Zeit abgebrochen wird? bin ich da mit 
timerfd_settimer() richtig, oder gibts da was anderes.
danke im voraus
ralph

von Klaus W. (mfgkw)


Lesenswert?

select()

von Ralph F. (feu)


Lesenswert?

select() ist sicher keine schlechte Sache. Ich werde es mal ausprobieren 
und melde mich wieder. Derweilen würde ich trotzdem gerne wissen was es 
mit den fFunktionen timerfd_settimer() , ~creat() und ~gettimer() 
aufsich hat und wozu/wie man sie verwendet.also wenn jemand eine Idee 
hat oder gar profi drin ist...
vielen dank


ralph

von Andreas B. (andreas_b77)


Lesenswert?

select() (oder poll(), ein anderes Interface zur selben Funktionalität) 
ist genau die Lösung dafür und noch mehr. Wenn select() sagt, dass auf 
einem Deskriptor etwas zu lesen ist, dann wird das erste read() darauf 
nie blockieren. Dazu kann man mit select() auf mehrere Deskriptoren 
warten und eben einen Timeout spezifizieren.

timerfd_* sind Intervall-Timer, die ein Ablaufen statt über Signale über 
Dateideskriptoren mitteilen. Damit kann man Timer ohne Signale 
implementieren (Signale sind ja wie Interrupts und entsprechend 
aufwendig) und über select() in den normalen Ablauf integrieren. 
Ansonsten haben die nichts mit Datenübertragung zu tun.

von Ralph F. (feu)


Lesenswert?

ganz prima sache mit dem select(). es läuft wie am Schnürchen. 
vielleicht hilfts mal jemandem, .. unten ist die Funktion angehangen.

und zu dem timerfd, wenn ich dich richtig verstanden habe müsste ich 
read() auf nonblocking setzen und in eine Schleife einbauen, wobei die 
Abbruchbedingung der timerfd oder eof wäre, ..?

also ersmal vielen Dank Andreas und auch an alle Anderen

ralph


int receive(int fd, char * rx_buffer,int sec, int usec)
{
  int n,bytes_read;
  fd_set rdfs;

  struct timeval timeout;
  timeout.tv_sec =  sec;
  timeout.tv_usec = usec;

  FD_ZERO(&rdfs);
  FD_SET (fd,&rdfs);

  n = select(fd + 1, &rdfs, NULL, NULL, &timeout);

  if(n < 0)
  {
   perror("select failed\n");
  }
  else if (n == 0)
  {
   puts("Timeout!");
  }
  else
  {
   if (FD_ISSET(fd, &rdfs))
   {
        while ((n=read(fd,rx_buffer + bytes_read, rx_buffer_size - 
bytes_read))>0)
        {
          bytes_read += n;
        }
   }
  }

return n;
}

von Andreas B. (andreas_b77)


Lesenswert?

Ralph Feuchter schrieb:
> und zu dem timerfd, wenn ich dich richtig verstanden habe müsste ich
> read() auf nonblocking setzen und in eine Schleife einbauen, wobei die
> Abbruchbedingung der timerfd oder eof wäre, ..?

Naja, in der man-page zu timerfd_create() steht eigentlich alles 
inklusive einem ausführlichen Beispiel.


Ralph Feuchter schrieb:
> if (FD_ISSET(fd, &rdfs))
>    {
>         while ((n=read(fd,rx_buffer + bytes_read, rx_buffer_size -
> bytes_read))>0)
>         {
>           bytes_read += n;
>         }
>    }

select() garantiert nicht, dass beliebig viel gelesen werden kann. Also 
funktioniert das nur, wenn fd das Flag O_NONBLOCK besitzt. Aber auch in 
diesem Fall fehlt hier die Behandlung für EOF und andere Fehler als 
EAGAIN.

von Ralph F. (feu)


Lesenswert?

nIch bin bisher davon ausgegangen, dass read() von selbst aufhört 
zulesen wenn eof kommt, was es in meinem Fall anscheinend auch macht. es 
eof findet ja auch
wie in (http://gd.tuwien.ac.at/languages/c/programming-bbrown/c_075.htm) 
beschrieben

...The read() function attempts to read nbytes from the file associated 
with handle, and places the characters read into buffer. If the file is 
opened using O_TEXT, it removes carriage returns and detects the end of 
the file....

vielleicht hae ich auch zufàllig die richtigen Einstellungen beim öffnen 
des ports gewählt.

und was timerfd_~() angeht, um die man-page zu lesen und zu verstehen 
muss man natürlich wissen was man damit machen kann, was in meinem Fall 
bis her nicht so richtig zutraf. aber trotzdem weiss ich die Tips zu 
schätzen.
ralph

von Ralph F. (feu)


Angehängte Dateien:

Lesenswert?

Hallo,
ich muss noch mal drauf zurückkommen. ganz funktioniert es immer noch 
nicht.
wenn ich die read() man page richtig gelesen habe, dürfte, read() nur 0 
zurückgeben wenn beim letzten auslesen mit EFO abgeschlossen wurde. nun 
gibt das read() bei mir aber nun 0 zurück obwohl kein eof gekommen sein 
kann.

habe Andreas's tips versucht einzubauen, mit -1 und EAGAIN geht es jetzt 
aber das eof wird nicht richtig gelesen. hat jemand eine Idee?
vielen Dank im voraus

der code ist im Anhang

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.