Forum: Compiler & IDEs read() u. port settings


von Ralph F. (feu)


Lesenswert?

Hallo ich brauche nochmal einen tip.
soweit ich bisher gelernt habe gibt die Funktion read() bei non_blocking 
0 zurück wenn ein eof gekommen ist, int > 0 wenn's was zu lesen gab, der 
string aber noch nicht zu ende ist und int < 0 + EAGAIN == errno wenn 
noch nichts angekommen ist. Das seltsame ist, bei mir gibt sie 0 zurück 
obwohl noch gar kein eof gekommen sein kann, da der String noch nicht 
fertig gelesen wurde.

statt dessen

root:~> ./uart

,12,-gesendete_bytes
AT#SELINT=2

,6,-empfangene_bytes
n==0

,AT#SEL,-empfangener_string

und

AT#SELINT=2
OK

sollte gelesen werden
----------------------------------------------------------------
....
  fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);
  fcntl(fd, F_SETFL, FNDELAY);
....
----------------------------------------------------------------
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))
  {
    bytes_read=0;
    while(1)
        {
        n = read(fd,rx_buffer + bytes_read + 1, rx_buffer_size - 
bytes_read);
        if (n >0)
        {
          bytes_read = bytes_read + n;
          printf( "\n,%d,-empfangene_bytes\n", n );
        }
        if (n==0)
        {
          puts("n==0");
          break;
        }
        if ((n<0)&&(EAGAIN != errno))
          {
           perror("read error\n");
           break;
          }
        }
      printf( "\n,%s,-empfangener_string\n", rx_buffer );
return bytes_read;
}


Hat jemand eine Idee?

vielen Dank im Voraus

von Karl H. (kbuchegg)


Lesenswert?

Ralph Feuchter schrieb:

>   fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);
>   fcntl(fd, F_SETFL, FNDELAY);

mit dem fcntl setzt du aber fd wieder zurück auf blocking.

von Ralph F. (feu)


Lesenswert?

Stimmt, ich habe aber VMIN und VTIME auf 0. müsste das nicht trotzdem 
read() zu non_blocking Verhalten zwingen? Ich probiere es aber noch mal 
ohne fcntl(fd, F_SETFL, FNDELAY) aus und melde mich wieder.
Vielen Dank

ralph

von Rolf Magnus (Gast)


Lesenswert?

Ralph Feuchter schrieb:
> Hallo ich brauche nochmal einen tip.
> soweit ich bisher gelernt habe gibt die Funktion read() bei non_blocking
> 0 zurück wenn ein eof gekommen ist,

Das ist unabhängig davon ob er blocking oder non-blocking ist.

> int > 0 wenn's was zu lesen gab, der string aber noch nicht zu ende ist

Was verstehst du hier unter "der string"? read() gibt 0 zurück, wenn das 
Ende des Files erreicht wurde, es also auch in Zukunft nichts mehr zu 
lesen geben wird, oder wenn man ihm als Anzahl zu lesender Bytes 0 
übergibt.
Die Funktion arbeitet einfach mit Bytes und weiß überhaupt nichts von 
Strings.

Ralph Feuchter schrieb:
> Stimmt, ich habe aber VMIN und VTIME auf 0. müsste das nicht trotzdem
> read() zu non_blocking Verhalten zwingen? Ich probiere es aber noch mal
> ohne fcntl(fd, F_SETFL, FNDELAY) aus und melde mich wieder.

Die richtige Methode für fcntl wäre, die Flags erst auszulesen 
(F_GETFL), dann mit den gewünschten zusätzlichen Flags zu verODERn und 
dann das Ergebnis zu setzen.

von Ralph F. (feu)


Lesenswert?

also ganz kurz was ich machen will:
ich schicke an ein modem ein AT befehl und das modem antwortet dann in 
der Regel mit dem echo des Befehls + LF + OK.
Mit select() warte ich jetzt wann auf dem file descriptor was passiert. 
sobald das modem antwortet wird read() in einer while Schleife solange 
aufgerufen bis die komplette Antwort ausgelesen wurde.
Allerdings was bei mir passiert ist, dass read() beim ersten Durchlauf 
den Teil aus dem Buffer liest der angekommen ist und die anzahl der 
gelesenen Bytes zurück gibt. Bis her ist alles ok. Nun im zweiten 
Durchlauf ist wahrscheinlich noch kein byte des Rests angekommen. jetzt 
sollte read() -1 zurück geben und EAGAIN = errno setzen. Aber was 
machts, es gibt 0 zurück als ob eof angekommen wäre und die Schleife 
bricht ab.
offensichtlich sind die Settings für fd falsch, aber welche??

von Rolf Magnus (Gast)


Lesenswert?

Ralph Feuchter schrieb:
> also ganz kurz was ich machen will:
> ich schicke an ein modem ein AT befehl und das modem antwortet dann in
> der Regel mit dem echo des Befehls + LF + OK.
> Mit select() warte ich jetzt wann auf dem file descriptor was passiert.
> sobald das modem antwortet wird read() in einer while Schleife solange
> aufgerufen bis die komplette Antwort ausgelesen wurde.

Woran erkennst du denn, daß die Antwort komplett ist?

> Allerdings was bei mir passiert ist, dass read() beim ersten Durchlauf
> den Teil aus dem Buffer liest der angekommen ist und die anzahl der
> gelesenen Bytes zurück gibt. Bis her ist alles ok. Nun im zweiten
> Durchlauf ist wahrscheinlich noch kein byte des Rests angekommen. jetzt
> sollte read() -1 zurück geben und EAGAIN = errno setzen. Aber was
> machts, es gibt 0 zurück als ob eof angekommen wäre und die Schleife
> bricht ab.

Ist dein Puffer vielleicht voll? Wie gesagt, wenn du an read() als 
Anzahl der zu lesenden Bytes 0 übergibst, gibt es auch 0 wieder zurück. 
Das tust du, wenn du am Ende deines Puffers angekommen bist, denn dann 
ist  rx_buffer_size - bytes_read==0.

> offensichtlich sind die Settings für fd falsch, aber welche??

Ich wüßte keine Settings, die dazu führen, daß read() einfach so 0 
zurückgibt.

von Ralph F. (feu)


Lesenswert?

vielen dank für die Antwort.
die Antwort besteht immer aus dem Echo und einem "OK".
Der buffer hat für 20 bytes Platz und die Antwort ist maximal 15 bytes 
lang. Wenn ich mit dem read() Aufruf lange genug warte, liegt die 
Antwort auch komplett im buffer.
Das Problem tritt auf wenn ich zu zeitig lese. Dann ist im besten Fall 
das erste Fragment der Antwort im tty-buffer. Lese ich ein zweites mal, 
sollte eignetlich, wenn noch nichts da ist, -1 returned werden. Aber es 
gibt 0 zurück. übrigens auch wenn ich einige ms später lese, wenn der 
rest längst angekommen sein sollte. Dann wäre die 0 zwar richtig aber 
read() hätte was gelesen haben müssen, was es nicht tut.

also das der buffer voll ist, ist ziehmlich ausgeschlossen.

ralph

von Karl H. (kbuchegg)


Lesenswert?

Bitte auch nicht ausser acht lassen, dass hier von einem seriellen Port 
gelesen werden soll.

D.h. die 'File-Nomenklatur' EOF (End of File) ist da nur bedingt 
anwendbar. read() liefert einfach nur die Anzahl der Zeichen, die 
gelesen werden konnten. Bei einer seriellen Schnittstelle kann das auch 
schon mal 0 sein, ganz einfach deswegen, weil in der Zwischenzeit kein 
Zeichen eingetrudelt ist. Bei einem File gibt es aber nur den einen 
Fall, dass 0 zurückgeliefert werden kann: nämlich wenn das Ende des 
Files erreicht ist.

Aber: Die ganze EOF Systematik ist auf Dinge wie Netzwerk und/oder 
externe Schnittstellen nicht wirklich anwendbar, weil kein Programm und 
auch kein I/O System in die Zukunft schauen kann. Wenn momentan keine 
weitere Daten abholbereit vorhanden sind, dann sind eben momentan keine 
weiteren Daten vorhanden. Was nicht heißt, dass das 10 Millisekunden 
später nicht schon wieder ganz anders sein kann.

Hier ist also ein Returnwert von 0 zu lesen als: Im Moment hab ich 
nichts, was ich dir geben könnte.


Deine ganze Sichtweise
> Das seltsame ist, bei mir gibt sie 0 zurück obwohl noch gar kein eof
> gekommen sein kann, da der String noch nicht fertig gelesen wurde.
macht mich stutzig. Kein einziges dieser Konzepte ist auf das Lesen 
mittels read() auf einem mit einer Seriellen verbundenen 
Stream-Descriptor anwendbar. Weder EOF macht in diesem Kontext Sinn, 
noch weiß read() irgendwas von irgendwelchen Strings. read() liefert 
einfach nur gelesene Bytes (deren Anzahl auch schon mal 0 sein kann) und 
ansonsten obliegt es dir aus den Bytes was zu machen.

von Rolf Magnus (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Bitte auch nicht ausser acht lassen, dass hier von einem seriellen Port
> gelesen werden soll.
>
> D.h. die 'File-Nomenklatur' EOF (End of File) ist da nur bedingt
> anwendbar. read() liefert einfach nur die Anzahl der Zeichen, die
> gelesen werden konnten. Bei einer seriellen Schnittstelle kann das auch
> schon mal 0 sein, ganz einfach deswegen, weil in der Zwischenzeit kein
> Zeichen eingetrudelt ist.

Nein, eigentlich nicht. Wenn der Port blockierend geöffnet wird, wartet 
read() einfach, bis was da ist. Bei non-blocking, gibt die Funktion -1 
zurück und setzt errno auf EAGAIN, wenn gerade nichts da ist. Das sollte 
auch unabhängig davon sein, ob das nun ein File, ein Socket, ein Device 
oder sonstwas ist.

von Ralph F. (feu)


Lesenswert?

Vielen Dank für Eure ausfürlichen Erklährungen. Karl Heinz seine 
Erklährung ist einleuchtend, wenn nichts zu lesen ist würde read() 0 
zurückgeben. Rolf seine Sache deckt sich eher mit dem was ich bis her 
gehört habe und würde mir auch mehr nützen. Zumal ich jetzt das ganze 
auf einem richtigen Linuxrechner ausprobiert habe und da kommt bei 
nonblocking -1 und EAGAIN wenn noch nichts angekommen ist. beim 
Blackfin-uClinux kommt 0 statt -1 an der Stelle. Habe es auch ans 
Blackfin forum geschrieben. werde mich wieder melden wenn ich etwas von 
dort höre.
Aber nochmal:
Wenn read()  in jedem falle 0 zurück gibt wenn nichts zu lesen ist, wie 
kann man denn dann eine längere Zeichenkette, deren Länge nicht bekannt 
ist vollständig empfangen, ohne unnötig lange zu warten bis nun alles 
angekommen sein müsste?
ralph

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus schrieb:
> Karl Heinz Buchegger schrieb:
>> Bitte auch nicht ausser acht lassen, dass hier von einem seriellen Port
>> gelesen werden soll.
>>
>> D.h. die 'File-Nomenklatur' EOF (End of File) ist da nur bedingt
>> anwendbar. read() liefert einfach nur die Anzahl der Zeichen, die
>> gelesen werden konnten. Bei einer seriellen Schnittstelle kann das auch
>> schon mal 0 sein, ganz einfach deswegen, weil in der Zwischenzeit kein
>> Zeichen eingetrudelt ist.
>
> Nein, eigentlich nicht.

Hast recht.
Da haben mich heut nachmittag irgendwie ein paar Links verwirrt, die das 
anders zu beschreiben schienen. Ich find die aber jetzt nicht mehr (bin 
auf einem anderen Rechner)

von Karl H. (kbuchegg)


Lesenswert?

Ralph Feuchter schrieb:
> Vielen Dank für Eure ausfürlichen Erklährungen. Karl Heinz seine
> Erklährung ist einleuchtend,

aber laut Doku der read() Funktion falsch.

Was natürlich nicht heißt, dass sich deine read Funktion nicht genau so 
verhält, wenn von einee Seriellen die Rede ist.
Aber mitlerweile tendiere ich auch (wieder) dazu, das dann als Fehler 
der Implementierung von read anzusehen.

von Karl H. (kbuchegg)


Lesenswert?

Ralph Feuchter schrieb:

> Wenn read()  in jedem falle 0 zurück gibt wenn nichts zu lesen ist, wie
> kann man denn dann eine längere Zeichenkette, deren Länge nicht bekannt
> ist

gar nicht.
Irgendetwas musst du vom String wissen.
Entweder wieviele Zeichen da daher kommen oder du musst eine 
Übereinkunft mit dem Sender haben, welches Zeichen er als letztes an 
jeden String drann hängt. Üblich ist zb ein \n oder ein ;. \n deswegen 
weil man dann an die andere Leitung ein Terminal hängt und wenn der 
Benutzer auf 'Return' haut, dann ist das das Zeichen für den Sender, 
dass der String (die 'Zeile') jetzt komplett ist.

Aber zaubern oder hellsehen kann weder der Sender, der Empfänger, die 
Runtime Library noch read().


Da du anscheinend am anderen Ende ein AT-Modem hängen hast: Jede Antwort 
vom Modem wird mit einem \n abgeschlossen. Das ist dein Zeichen, dass 
das Modem eine Zeile (eiunen String) komplett rausgeblasen hat.

von feucom (Gast)


Lesenswert?

Hallo ich bin wieder da.
jetzt funktioniert alles wie erwartet. read()gibt -1 und errno == 
eagaine zurück und liest auch das kommando bis zum CR aus dem buffer. 
was es nun war kann ich leider nicht sagen, der Rat vom BF-forum war, 
eine andere uClinux version zu testen.
hier der link zum tread: http://ez.analog.com/message/61525
eigenartig ist nur, das meine version nach dem Neucompilieren auch 
funktionierte. nicht recht zufriedenstellend, .. wenn man nicht weiss 
woran es nun gelegen hat. finde ich es noch raus, schreibe ich es noch.

bis dahin und vielen Dank für Eure unterstützung


ralph

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.