Forum: PC-Programmierung Linux C Read von ttys0


von Lars (Gast)


Lesenswert?

Moin,

ich habe ein Gerät das 30Sec lang ASCII Zeichen sendet und diese will 
ich empfangen und bearbeiten.

Als System ist ein Debian vorhanden mit gcc.

Ich habe schon versucht so was zu lesen:

res = read(fd,(char *)buf,sizeof(buf));

aber irgendwie kommen da nur ca.9 Zeilen an....Ist das die große des 
Hardware Buffers? Wie zeichnet mann denn alles auf in C?


Ich wäre für einen Tip dankbar

Lars

von g457 (Gast)


Lesenswert?

> Ich habe schon versucht so was zu lesen:
>
> res = read(fd,(char *)buf,sizeof(buf));

Na nur damit wirst Du nicht weit kommen :-) Zeig mal den ganzen 
Quellcode. Falls Du das nicht möchtest lies wenigstens die Manpage.

von Georg aus Wien (Gast)


Lesenswert?

Machs doch mit Python!

Ist auf jedem Debian vorinstalliert.

http://pyserial.sourceforge.net/shortintro.html

von Rolf Magnus (Gast)


Lesenswert?

Lars schrieb:
> Ich habe schon versucht so was zu lesen:
>
> res = read(fd,(char *)buf,sizeof(buf));
>
> aber irgendwie kommen da nur ca.9 Zeilen an....Ist das die große des
> Hardware Buffers?

Wie groß ist denn dein Buffer?

> Wie zeichnet mann denn alles auf in C?

read() in einer Schleife aufrufen.

von Lars (Gast)


Lesenswert?

Moin,


ich habe den Buffer schon auf > 10000 gestellt aber es kommen immer 
gleich wenig Zeichen.

Ich habe noch nicht viel Code...ich geben den Buffer danch einfach per 
Prinf aus.

Wenn ich eine while Schleife wie bekomme ich denn alle Daten in eine 
Variable?

Ich will ja alle gesammelten Daten zusammen auswerten.



Lars

von mar IO (Gast)


Lesenswert?

Lars schrieb:
> aber irgendwie kommen da nur ca.9 Zeilen an....Ist das die große des
> Hardware Buffers? Wie zeichnet mann denn alles auf in C?

Wenn Du folgendes durchliest, sollten alle deine Fragen vorerst gelöst 
sein (geht ab "Programmierung mit C" los):

http://www.netzmafia.de/skripten/hardware/Seriell/index.html

von Rolf Magnus (Gast)


Lesenswert?

Lars schrieb:
> ich habe den Buffer schon auf > 10000 gestellt aber es kommen immer
> gleich wenig Zeichen.

Dann ist wohl der interne Puffer voll.

> Wenn ich eine while Schleife wie bekomme ich denn alle Daten in eine
> Variable?

Du merkst dir einfach, wieviele Zeichen schon gelesen wurden und 
übergibst read() halt als Startposition die entsprechende Stelle in 
deinem Puffer statt dessen Anfang.
Du mußt auch noch definieren, was "alle Daten" sind. Mit anderen Worten: 
Du brauchst eine Möglichkeit, das Ende zu erkennen. Hast du dir dazu 
schon Gedanken gemacht?

von g457 (Gast)


Lesenswert?

> ich habe den Buffer schon auf > 10000 gestellt aber es kommen immer
> gleich wenig Zeichen.

Sachichdoch - Manpage lesen wäre zweckmäßig.

> Wenn ich eine while Schleife wie bekomme ich denn alle Daten in eine
> Variable?

Mitzählen. Das war jetzt einfach :-)

von Lars (Gast)


Lesenswert?

Buffersize ist 1
1
  char buf[BUFFSIZE];
2
  int res=0;
3
  int i=0;
4
  char spei[10000];    
5
6
7
  do{
8
  
9
    res = read(fd,(char *)buf,sizeof(buf));
10
    
11
    strncpy(spei, buf, i);  
12
  
13
    i++;
14
    
15
  }while(i < 2);
16
  
17
18
  printf("read:%s\n",spei);
19
20
21
  return;

Warum kann ich den dem While kein Strcopy machen? Da hängt das Programm

von Karl H. (kbuchegg)


Lesenswert?

Lars schrieb:

> Warum kann ich den dem While kein Strcopy machen? Da hängt das Programm

Ja, hast du denn überhaupt Strings?


Ich seh schon.
WIr sind wieder mal an dem Punkt an dem man sagen muss: Es hilft alles 
nichts. Wer Programm in der realen Welt schreiben will muss erst mal die 
Grundlagen lernen! Das geht nun mal nicht so, wie sich manche das 
vorstellen: vormittags den Entschluss gefasst Programmierer zu werden, 
und nachmittags die Killerapplikation geschrieben, die einen reich 
macht.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Lars schrieb:
>
>> Warum kann ich den dem While kein Strcopy machen? Da hängt das Programm
>
> Ja, hast du denn überhaupt Strings?

Und ehe du dich in einen Wirbel reinredest.
Nein, du hast erst mal keine Strings.
read befüllt dir den buffer mit den Zeichen die gerade da sind bzw. in 
den buffer passen. Nicht mehr und nicht weniger. Von Strings kann zu 
diesem Zeitpunkt noch überhaupt keine Rede sein.

von Lars (Gast)


Lesenswert?

Mh okay verseh ich nun nicht so ganz....

Was ist den in dem Buffer? Deklariert sind ja Char Sind doch 
Zeichenketten....


Ist nicht ein Char ein String?

von Rolf M. (rmagnus)


Lesenswert?


von Jörg B. (jbernau)


Lesenswert?

Lars schrieb:
> Ist nicht ein Char ein String?

Nein das ist ein Array of Bytes, In C sind Strins mit \0 terminert. Dann 
sind es Strings und können mit den Funktionen aus der string.h behandelt 
werden. Sonst ist das nur irgendwelcher Datenkram...

Gegenvorschlag:

char *spei; // Wir machen einen Pointer daraus
spei = (char)malloc(10000) // Speicher reservieren;
char *mark;

mark = spei; // alten Pointer merken

do{

    res = read(fd,(char *)buf,sizeof(buf));
if (spei < mark + 10000) { // Sicher stellen, dass nocht über den 
allocierten Speicher geschrieben wird
    memcpy(spei, buf, res); // anzahl der gelesenen Zeichen umschaufeln
    spei += rc // pointer hochzählen
  }
  }while( res > 0);

// hoffen, dass es sich um strings handelt, sonst als letztes Zeichen \0 
anfügen


  printf("read:%s\n",mark); // nicht wundern, wir nehmen hier den Anfang 
des spei Pointers, da wir den ja oben laufend verschoben haben


// Speicher wieder frei geben
free(spei);
free(mark);


So, das ist nicht getestet, sollte aber gehen..

Grpßle aus dem Ländle von Jörg

von Jean (Gast)


Lesenswert?

Jörg Bernau schrieb:
> So, das ist nicht getestet, sollte aber gehen..

Wenn die kleinen Elflein kommen und die Speicherlecks entfernen. Ja dann 
funzt es xD

-->siehe malloc
->res = read(fd,(char *)buf,sizeof(buf)); ^^
wohle eher res = read(fd, buf, sizeof(buf) / sizeof(buf[0]);
-->memcpy(spei, buf, res); // anzahl der gelesenen Zeichen umschaufeln
    spei += rc // pointer hochzählen
SoSo ^^
--> Speicher wieder frei geben
char *spei; // Wir machen einen Pointer daraus
spei = (char)malloc(10000) // Speicher reservieren ^^ Witzig
char *mark;
...
mark = spei; // alten Pointer merken
free(spei);
free(mark);
:) jaja speicher von einem nicht reservierten Speicherbereich freigeben 
xD

Sry, musste sein.
:)

von Jean (Gast)


Lesenswert?

Jörg Bernau schrieb:
> Grpßle aus dem Ländle von Jörg

:)
Wunderland ^^
Sry, bin gerade schlecht drauf ^^

von Rolf M. (rmagnus)


Lesenswert?

Jörg Bernau schrieb:
> spei = (char)malloc(10000) // Speicher reservieren;

Wozu denn malloc, wenn die Größe eh als Konstante vorgegeben ist? Mal 
abgesehen von dem überflüssigen und hier auch noch falchen Cast.

von Lars (Gast)


Lesenswert?

Ok danke für die Tips.

Aber ein Problem habe ich immer noch.....

Wenn ich z.b das hier:
1
  char string[] = "Die schoenen Dinge im Leben sind umsonst.";
2
  int laenge = strlen(string);
3
  printf("Laenge: %d Zeichen\n", laenge);

In meinen Code einfüge bleibt da das Programm stehn :-(

Ich habe auch das diese Includes drin:
/* lesen.c */
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>

von Mehmet K. (mkmk)


Lesenswert?

(Zwar nicht die Antwort auf Deine Frage)
Dem Compiler ist die Laenge des Strings bereits bekannt, weshalb ich 
anstelle von strlen() sizeof() benutzen würde.

von Rolf M. (rmagnus)


Lesenswert?

In dem Codeschnipsel ist kein Fehler, also muß er irgendwo anders 
liegen. Sinnvoll ist es deshalb, ein minimales, aber vollständiges 
Programm zu posten, das den Fehler noch enthält.
Folgendes Programm funktioniert bei mir jedenfalls einwandfrei:
1
/* lesen.c */
2
#include <termios.h>
3
#include <fcntl.h>
4
#include <sys/ioctl.h>
5
#include <stdio.h>
6
#include <sys/types.h>
7
#include <sys/stat.h>
8
#include <string.h>
9
#include <stdlib.h>
10
11
int main(void)
12
{
13
    char string[] = "Die schoenen Dinge im Leben sind umsonst.";
14
    int laenge = strlen(string);
15
    printf("Laenge: %d Zeichen\n", laenge);
16
    return 0;
17
}

Es gibt aus:
1
Laenge: 41 Zeichen

Mehmet Kendi schrieb:
> Dem Compiler ist die Laenge des Strings bereits bekannt, weshalb ich
> anstelle von strlen() sizeof() benutzen würde.

Der Compiler (zumindest gcc) ist so intelligent, in so einem Fall auch 
bei strlen() die Länge schon zur Compilezeit zu ermitteln.

von Lars (Gast)


Lesenswert?

Wenn ich string[100] schreibe gehts.

Wie kompilierst du mit gcc?

von Rush (Gast)


Lesenswert?

Lass es Lars, hier wirst Du nicht wirklich eine "vernünftige" Antwort 
erhalten.
BTW: Nimm Dir mal das Buch von K&R und lerne erst einmal, denn Dir 
fehlen noch viele Grundlagen. Erst wenn Dir klar ist, was Du eigentlich 
machst (Pointer und so Sachen), dann wirst Du auch ein einges, positives 
Ergebnis bekommen.

Ein guter Compiler zum üben unter Windoof ist:
http://www.cs.virginia.edu/~lcc-win32/

Der ist sehr gut zu bedienen und die gesamte Doku ist dabei.
Und er ist für Lau!

von Rolf M. (rmagnus)


Lesenswert?

Lars schrieb:
> Wenn ich string[100] schreibe gehts.

Und wenn du den exakten Code von mir nimmst, geht es nicht? In dem 
Fall stimmt irgendwas mit deinem Compiler nicht, oder er ist extrem 
veraltet. Oder hast du's nur in deinem Programm probiert? Dann gilt 
immer noch:

Rolf Magnus schrieb:
> Sinnvoll ist es deshalb, ein minimales, aber vollständiges
> Programm zu posten, das den Fehler noch enthält.

> Wie kompilierst du mit gcc?

gcc datei.c -o datei

von Lars (Gast)


Lesenswert?

Jap und habe mit gdb rausgefunden das das Programm am READ hängt warum 
auch immer.....

Ich habe ein aktuelle Debian aufgesetzt...

von Rolf M. (rmagnus)


Lesenswert?

In dem Code kommt doch gar kein read() vor und auch nichts, von dem aus 
es aufgerufen würde.

von mar IO (Gast)


Lesenswert?

Welche Werte haben c_cc[VMIN] und c_cc[VTIME] bzw. die serielle 
Schnittstelle?

von Lars (Gast)


Lesenswert?

Die habe ich gar nicht konfiguriert.

So sieht es bei mir aus:

  struct termios port_settings;      // structure to store the port 
settings in

  cfsetispeed(&port_settings, B300);    // set baud rates
  cfsetospeed(&port_settings, B300);

  port_settings.c_cflag |= PARENB;    // setze 7E1
  port_settings.c_cflag &= ~PARODD;
  port_settings.c_cflag &= ~CSTOPB;
  port_settings.c_cflag &= ~CSIZE;
  port_settings.c_cflag |= CS7;
  port_settings.c_lflag = ICANON;
  tcsetattr(fd, TCSANOW, &port_settings);    // apply the settings to 
the port
  return(fd);

von Simon B. (nomis)


Angehängte Dateien:

Lesenswert?

Lars schrieb:
> res = read(fd,(char *)buf,sizeof(buf));
>
> aber irgendwie kommen da nur ca.9 Zeilen an....Ist das die große des
> Hardware Buffers? Wie zeichnet mann denn alles auf in C?

Der Linux-Kernel macht bei einem read()-Syscall keine Garantien, dass 
der Buffer gefüllt wird, es wird das rausgereicht, was gerade da ist. 
Nur wenn nix da ist wird blockiert (ok, man kann die Datei auch 
nonblocking öffnen, dann kommt "nix" zurück).

Wenn man darauf angewiesen ist, dann macht man das mit den 
"highlevel"-Funktionen der libc (fread etc.).

Ich habe mal ein winz-Programm angehängt, welches auf eine serielle 
Schnittstelle zugreift und die empfangenen Daten auf stdout als Hexdump 
ausgibt. Als Bonus wird da auch gezeigt, wie man mit poll() auf das 
Vorhandensein von Daten warten kann - hier nutze ich das dafür, dass 
nach einer kleinen Pause ein Zeilenumbruch ausgegeben wird, also 
typischerweise nach einem Telegramm.

Ich hoffe das hilft weiter.

Viele Grüße,
         Simon

von Karsten F. (Firma: von Dänemark) (bingo600)


Lesenswert?

@Simon
Nice trick with the polling.

@Lars
I have used this code on an Arduino , and it seems to be ok. For reading 
serial responses from an Arduino.
Beitrag "PortableSerialLib - Portable Serial Port Library"

Maybe it should be extended with the poll Simon shows.

I haven't tried it on windows , but used it in hope of a "dual platform" 
support.

regards
Karsten - Denmark

von mar IO (Gast)


Lesenswert?

1
...
2
if (pfd[0].revents & POLLIN) {
3
    ret = read (serial_fd, buffer, 255);
4
    if (ret < 0 && errno != EAGAIN) {
5
        ...
6
...

@Simon

Muss man ret hier wirklich auf /EAGAIN/prüfen? - Mit der vorigen 
Abfrage sollte doch sichergestellt sein, dass Daten vorhanden sind, oder 
nicht (immer)?

von Simon B. (nomis)


Lesenswert?

mar IO schrieb:
> Muss man ret hier wirklich auf /EAGAIN/prüfen? - Mit der vorigen
> Abfrage sollte doch sichergestellt sein, dass Daten vorhanden sind, oder
> nicht (immer)?

Ja, im Prinzip hast Du recht, es sollten Daten verfügbar sein.

Hier ist das ein bischen defensiv programmiert und schützt einen vor 
irgendwelchen komischen Situationen mit z.B. kaputten Treibern. Ich weiß 
jetzt gerade nicht, ob ich diese Situation schonmal konkret hatte, aber 
ich weiß: Wenn read() EAGAIN zurückgibt, dann will ich es nochmal 
probieren, insofern teste ich lieber drauf.

Viele Grüße,
         Simon

von Rolf M. (rmagnus)


Lesenswert?

mar IO schrieb:
> Muss man ret hier wirklich auf /EAGAIN/prüfen? - Mit der vorigen
> Abfrage sollte doch sichergestellt sein, dass Daten vorhanden sind, oder
> nicht (immer)?

In der Man-Page steht:
1
BUGS  See the discussion of spurious readiness notifications under the
2
      BUGS  section of select(2).

Und bei select steht dann:
1
BUGS:
2
       Under Linux, select() may report a socket file  descriptor
3
       as  "ready  for  reading", while nevertheless a subsequent
4
       read blocks.  This could for example happen when data  has
5
       arrived  but  upon  examination  has wrong checksum and is
6
       discarded.  There may be other circumstances  in  which  a
7
       file  descriptor is spuriously reported as ready.  Thus it
8
       may be safer to use O_NONBLOCK on sockets that should  not
9
       block.

O_NONBLOCK hat er ja wohl schon, aber dann muß man auch auf EAGAIN 
prüfen, um das von einem echten Fehler unterscheiden zu können.

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.