Hallo Im Anhang ist der Quellcode meine Serial Port Cpp und h Datei. Ich versuche über einen Mikrocontroller Daten einzulesen. Dazu sende ich 2 Byte (A101) an den uController. Dieser sendet dann sofort 27 Byte zurück. Mit Hterm habe ich das bereits getestet. Das Funktioniert wunderbar und schnell. Mit dem Cpp Programme bekomme ich nur die Bytes nur eingelesen, wenn ich zuvor eine ganze Weile warte uslseep(count * 400000) steht in der readByte methode. Ist die Zeit kürzer werden immer wenigier Byte empfangen. Das kann aber nicht richtig sein. Die Daten müssen nach wenigen Millisekunden da sein. Jetzt sind das ja fast 4 bis 5 Sekunden die ich warten muss um alle Daten lesen zu können. In Hterm klappt das in unter 40ms. Kann mir da jemaden helfen? Danke!
:
Verschoben durch Moderator
Eine harte Zeit zu warten und nur dann einmal das Lesen probieren ist auch nicht der richtige Weg. Entweder nimmt man wie du select(), dann aber in einer Schleife bis etwas kommt (dann braucht man auch kein sleep vorher - select wartet doch selbst, solange nichts passiert. Oder man liest in einem eigenen Thread blockierend.
Jan Remmert schrieb: > Ist die Zeit kürzer werden immer wenigier Byte empfangen. Fehlen dann die ersten Bytes oder die letzten? Wenn die letzten fehlen, dann ist nicht der Linuxrechner zu langsam, sondern die Daten tröpfeln halt erst nach und nach ein. Seriell ist halt nicht so schnell, und wenn du zu früh liest, bekommst du natürlich nur die bis dahin übertragenen Daten zu sehen. In jedem Fall musst du natürlich sehen, ob du genug gelesen hast (auch wenn du wie von mir vorgeschlagen select() in einer schleife nimmst), und ggf. weiter lesen bis Zeilenende oder was auch immer das Ende deines Datensatzes signalisiert.
select wartet nicht bis alle bytes empfangen wurden, sondern nur bis etwas empfangen wurde. Dies ist bei einer seriellen Schnittstelle meistens nur ein Byte. Durch das Warten hast Du sichergestellt, dass alle Bytes die dich interessiert haben auch empfangen waren. Das Problem ist, dass du ein "framing" brauchst, mit dem deine Read-Methode erkennen kann, wann eine komplette Antwort empfangen wurde. Möglichkeiten: fixe Länge, Länge zuerst gesendet oder Schlusszeichen (z.B. CR). Dann musst Du nur in einer Schleife mit select empfangen bis die komplette Antwort zusammen ist. (und evtl zuviel empfangene Daten für später aufbewahren.) Nils
Nils schrieb: > Das Problem ist, dass du ein "framing" brauchst, mit dem deine > Read-Methode erkennen kann, wann eine komplette Antwort empfangen wurde. > Möglichkeiten: fixe Länge, Länge zuerst gesendet oder Schlusszeichen > (z.B. CR). Wirklich sinnvoll ist davon eigentlich nur das Schlusszeichen (das dann auch in den restlichen Daten nicht vorkommen sollte - zur Not per escaping entfernen). Andernfalls hat man keine Möglichkeit, sich zu synchronisieren. Wenn dann nur ein einziges Byte verlorengeht, kommt danach nur noch Datenmüll an.
Es sollte auch ohne select gehen, denn du wartest beim select ja eh nur
auf eine Filehandle. Da kannst du gleich read machen das warten auch
nur.
Dann kommt mir der code schon ein wenig merkwürdig vor.
> this->max_fileDiscriptor = this->fileDiscriptor+1;
1. Warum die ganzen Variabeln nicht lokal in der funktino machen, was
sollen sie denn in den Objekt?
2. max_fileDiscriptor sollte doch bestimmt eine anzahl sein, dan kann
man doch nicht das filehandler reinrechnen.
3. das this finde ich schrecklich, lass es weg und machen am Variabeln
namen kenntlich das es sich um eine membervariabel handelt.
Peter II schrieb: > 2. max_fileDiscriptor sollte doch bestimmt eine anzahl sein, dan kann > man doch nicht das filehandler reinrechnen. select(() braucht einen Wert, der um 1 höher ist als der max. vorkommende fd, also hier eins höher als der einzige fd. Es ist also keine Anzahl. Trotzdem fände ich ich es ohne Variable sinnvoller; man kann es tatsächlich einfach beim Aufruf berechnen lassen (den Rest macht der Optimierer :-).
Peter II schrieb: > Es sollte auch ohne select gehen, denn du wartest beim select ja eh nur > auf eine Filehandle. Da kannst du gleich read machen das warten auch > nur. Erstmal richtig; bei select() kann man aber sinnvollerweise noch ein Timeout mit angeben und so auf eine unterbrochene Verbindung sinnvoll reagieren. Ein blocking read() würde ewig warten.
Doch das passt so. Schau mal in die manpage zu select. http://linux.die.net/man/2/select Es geht um nfds: nfds is the highest-numbered file descriptor in any of the three sets, plus 1. Beste Grüße, Stefan
Klaus Wachtler schrieb: > Erstmal richtig; bei select() kann man aber sinnvollerweise noch ein > Timeout mit angeben und so auf eine unterbrochene Verbindung sinnvoll > reagieren. kann man etwa unter linux keine Timeout für das Filehandle(Comport) festlegen? Klaus Wachtler schrieb: > select(() braucht einen Wert, der um 1 höher ist als der max. > vorkommende fd, also hier eins höher als der einzige fd. > Es ist also keine Anzahl. ist ja unpraktisch, gut ich arbeite immer mit Poll dort muss die anzahl rein.
Peter II schrieb: > Klaus Wachtler schrieb: >> Erstmal richtig; bei select() kann man aber sinnvollerweise noch ein >> Timeout mit angeben und so auf eine unterbrochene Verbindung sinnvoll >> reagieren. > > kann man etwa unter linux keine Timeout für das Filehandle(Comport) > festlegen? nein, dafür nimmt man genau select() > > Klaus Wachtler schrieb: >> select(() braucht einen Wert, der um 1 höher ist als der max. >> vorkommende fd, also hier eins höher als der einzige fd. >> Es ist also keine Anzahl. > > ist ja unpraktisch, gut ich arbeite immer mit Poll dort muss die anzahl > rein. unpraktisch für den Aufrufer, aber effizienter, weil select() nicht soviel tun muß. Die fd_set sind (Bit-?) Vektoren, und durch die Angabe des maximalen Werts muß select() nicht den ganzen Vektor abgrasen, sondern kann bei dem Wert aufhören. Schließlich werden typischerweise nur die untersten der vielen möglichen Werte genutzt.
Danke für eure vielen Antworten Wenn die Zeit Kürzer ist, fehlen die letzten Daten. Dies liegt aber nicht an der Hardware oder dem mikrocontroller, da mit Hterm die Daten innerhalb von 40ms vollständig vorhanden sind. Die Zeit, die ich zu beginn warten muss beträgt wie gesagt fast 4 Sekunden. Das kann ja nicht sein. Die Framelänge übergebe ich der Funktion Ich lese im Polling. Ginge ein Byte verloren müsste die read funktion nur irgendwann ein timeout zurück geben. Wie würde denn jetzt eine Optimierte Read Methode mit select in while-chleife und max_filedescriptor ohne Variable aussehen? Die While-Schleife muss so lange durchlaufen werden bis count daten gelesen wurden oder nach einer Zeit von ca 2 sec abbrechen.
Jan Remmert schrieb: > bis count daten gelesen das ist wie bereits gesagt nicht sinnvoll, weil du dich nach einem kaputten Byte nicht wieder einkriegst. Ringe dich zu einem Zeilenvorschub durch, dann schreibe ich dir die select()-Variante :-)
Ich übertrage Messdaten als Rohdaten. Diese können jeden wert von 0 bis 255 annehmen. Daher kann nicht sichergestellt werden, dass ein Zeilenvorschub nur am Ende übertragen wird.
na, es soll nicht mein Problem sein, wenn etwas aus dem Tritt kommt. Dann halt so:
1 | ::std::vector<unsigned char> serialPort::readByte(int count) |
2 | {
|
3 | ::std::vector<unsigned char> receivedBytes; |
4 | |
5 | fd_set fd_set_input; |
6 | struct timeval timeout; |
7 | timeout.tv_sec = 2; |
8 | timeout.tv_usec = 0; |
9 | |
10 | while( receivedBytes.size()<count ) |
11 | {
|
12 | FD_ZERO( &fd_set_input ); |
13 | FD_SET( this->fileDiscriptor, &fd_set ); |
14 | |
15 | int ret_select = select( this->fileDiscriptor+1, &fd_set_input , NULL, NULL, &timeout ); |
16 | |
17 | if( ret_select<0 ) |
18 | {
|
19 | // select error: TODO handling...
|
20 | }
|
21 | else if( ret_select==0 ) |
22 | {
|
23 | // timeout expired: TODO handling...
|
24 | }
|
25 | else
|
26 | {
|
27 | // read:
|
28 | |
29 | char read_char; |
30 | if( read( this->fileDiscriptor, &read_char, 1 )==1 ) |
31 | {
|
32 | receivedBytes.push_back( read_char ); |
33 | }
|
34 | else
|
35 | {
|
36 | // error reading byte; TODO handling ...
|
37 | }
|
38 | }
|
39 | }
|
40 | |
41 | return receivedBytes; |
42 | }
|
(ungetestet, aus dem Stegreif geschrieben)
PS: Wenn man auf mehrere fd warten würde, müsste man nach select vor dem read noch prüfen, welcher überhaupt heiß ist. Weil wir aber nur einen fd eintragen, kann es auch nur einer nach select sein.
Danke sehr für die Mühe. Es gibt aber Probleme in der Zeile: FD_SET( this->fileDiscriptor, &fd_set ); mit dem &fd_set beim Compilieren;
Klaus Wachtler schrieb: > FD_ZERO( &fd_set_input ); > FD_SET( this->fileDiscriptor, &fd_set ); ich würde die dinger noch aus der while schleife rausziehen, macht wenig sinn jedes mal neu einzulegen. Eigentlich müsste man auch noch die Gesamtzeit berücksichtigen, wenn jedes byte nach 1,5s kommt, dann hängt das Programm zu lange. Es sollen ja alle bytes in 2s gelesen sien.
Ich glaube, das Problem ist ein anderes. Die Schnittstelle wird standardmäßig für die Verwendung als Terminal initialisiert, wartet also auf CR oder ein timeout. Anbei ein leicht gekürzter Beispielcode, der jedes empfangene Byte sofort zurückliefert:
1 | int openReceiver(int iSerLine, int iBaudrate) |
2 | {
|
3 | int iBaud; |
4 | |
5 | iBaud = getBaudRateIndex(iBaudrate); |
6 | if (iBaud == 0) |
7 | {
|
8 | iBaud = B4800; |
9 | }
|
10 | |
11 | /* open port */
|
12 | if ((iFD = openLine(iSerLine)) == -1) |
13 | {
|
14 | printf ("FATAL: serial GPS interface open error !\n"); |
15 | return RETURN_ERROR; |
16 | }
|
17 | |
18 | /* Configure port reading; block read(), until data arrive */
|
19 | fcntl(iFD, F_SETFL, 0); |
20 | |
21 | /* Get the current options for the port */
|
22 | tcgetattr(iFD, &oldoptions); |
23 | memcpy (&options, &oldoptions, sizeof (struct termios)); |
24 | |
25 | /* Set the baud rates to the defined value */
|
26 | cfsetispeed(&options, iBaud); |
27 | cfsetospeed(&options, iBaud); |
28 | |
29 | /* Enable the receiver and set local mode */
|
30 | options.c_cflag |= (CLOCAL | CREAD); |
31 | options.c_cflag &= ~PARENB; /* Mask the character size to 8 bits, no parity */ |
32 | options.c_cflag &= ~CSTOPB; |
33 | options.c_cflag &= ~CSIZE; |
34 | options.c_cflag |= CS8; /* Select 8 data bits */ |
35 | options.c_cflag &= ~CRTSCTS; /* Disable hardware flow control */ |
36 | /* options.c_cflag |= CRTSCTS; */ /* enable hardware flow control */ |
37 | |
38 | /* Enable data to be processed as raw input */
|
39 | options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); |
40 | options.c_iflag &= ~(ICRNL | INLCR | IXON | IXOFF); |
41 | options.c_oflag &= ~OPOST; |
42 | |
43 | options.c_cc[VTIME] = 0; /* no inter-character timer */ |
44 | options.c_cc[VMIN] = 1; /* number of characters expected */ |
45 | /* options.c_cc[VEOF] = 4; */
|
46 | |
47 | /* enable the new options for the port, return o.k. */
|
48 | tcsetattr(iFD, TCSANOW, &options); |
49 | fprintf (stderr, "receiver successful opened\n"); /* Debug */ |
50 | |
51 | return 0; |
52 | }
|
53 | |
54 | int closeReceiver(void) |
55 | {
|
56 | tcsetattr(iFD, TCSANOW, &oldoptions); /* Portrekonfiguration rueckgaengig*/ |
57 | tcflush(iFD, TCIFLUSH); |
58 | close(iFD); /* seriellen Port schliessen */ |
59 | return 0; |
60 | }
|
So funktioniert es zumindest bei mir.
Peter II schrieb: > Klaus Wachtler schrieb: > >> FD_ZERO( &fd_set_input ); >> FD_SET( this->fileDiscriptor, &fd_set ); > > ich würde die dinger noch aus der while schleife rausziehen, macht wenig > sinn jedes mal neu einzulegen. Nein, das geht schief (zumindest, wenn man mit mehreren fd arbeitet). Grund: select() ändert das Feld, indem nach dem Aufruf nur die fds noch gesetzt sind, von denen man lesen (bzw. im anderen Feld auf die man schreiben kann). In diesem Fall ist es egal, weil es ja nur einen Eintrag gibt und genau der nach select() auch wieder gesetzt sein wird (außer bei timeout, wo es keinen mehr interessiert). Ich hatte es es erst außerhalb der Schleife, dann aber nochmal schnell editiert, damit nicht jemand anderes das mal nimmt und mit mehreren fd dann auf die Klappe fällt. > > Eigentlich müsste man auch noch die Gesamtzeit berücksichtigen, wenn > jedes byte nach 1,5s kommt, dann hängt das Programm zu lange. Es sollen > ja alle bytes in 2s gelesen sien. Ja, wenn man es so will, kann immer die bisherige Zeit von der Gesamtzeit abziehen und nur den Rest übergeben. In aller Regel gehe ich aber davon aus, daß die 4 Byte zügig hereinpurzeln und nur am Anfang einmalig verzögert wird, oder es hängt komplett; insofern ist das wohl das kleinste Problem.
Bei mir hängt er jetzt in der Select schleife. es kommt kein Timeout. Das Beispiel von Frame ist zu stark verkürzt. Weiß da leider nicht was wie gemacht wurde. Noch einmal zur Übersicht was ich brauche. Vieleicht hat jemand einen ganz anderen Code: Beim öffnen die Baudrate und das Device als Sting übergeben. Meine Sende Methode funktioniert. (Es wird als ein Hexcode als String übergeben und es wird alles übermittelt) Eine Definierte Anzahl an Bytes möglichst schnell lesen und in einem unsigned char vector zurück geben. Kommen innerhalb von 2 Sekunden nicht genug Bytes einen timeout erzeugen und einen Leeren Vector zurück geben.
Peter II schrieb: > Klaus Wachtler schrieb: > >> FD_ZERO( &fd_set_input ); >> FD_SET( this->fileDiscriptor, &fd_set ); > > ich würde die dinger noch aus der while schleife rausziehen, macht wenig > sinn jedes mal neu einzulegen. Das darf nicht passieren! FD_ZERO legt nicht etwa eine Variable an, sondern löscht insbesonders auch die Flags für die Filedeskriptoren. Und das muss nach jedem select() neu passieren. Ich finde ja das select()-API total gruselig und würde immer die Verwendung von poll() stattdessen empfehlen, da sieht das dann etwa so aus:
1 | int main (int argc, char *argv[]) |
2 | { |
3 | int fd; |
4 | struct pollfd pfd[1]; |
5 | |
6 | fd = open ("/dev/ttyS0", O_RDWR); |
7 | if (fd < 0) { |
8 | perror ("open"); |
9 | return -1; |
10 | } |
11 | |
12 | pfd[0].fd = fd; |
13 | pfd[0].events = POLLIN; |
14 | |
15 | while (1) { |
16 | if (poll (pfd, 1, -1) > 0) { |
17 | if (pfd[0].revents & POLLIN) |
18 | ; /* read serial port input */ |
19 | } |
20 | } |
21 | |
22 | return 0; |
23 | } |
Viele Grüße, Simon
Jan Remmert schrieb: > Bei mir hängt er jetzt in der Select schleife. es kommt kein Timeout. Dann hast du wohl etwas falsch gemacht. Wenn man select() ein Timeout übergibt, gehe ich jede Wette ein, daß es auch berücksichtigt wird.
Simon Budig schrieb: > Ich finde ja das select()-API total gruselig und würde immer die > Verwendung von poll() stattdessen empfehlen select() war halt seinerzeit der erste Versuch, IO-Multiplexing überhaupt zu implementieren. Davor konnte man nur blockend arbeiten und musste zwei separate Prozesse für Senden und Empfangen nutzen (Threads gab's da auch noch keine). UUCP arbeitete noch auf diese Weise. poll() ist nun mittlerweile von Posix standardisiert, insofern spricht da alles dafür, das zu bevorzugen. > , da sieht das dann etwa so > aus: Aber nicht vergessen, das "canonical input processing" noch auszuschalten, sonst passiert bei binären Eingabedaten allerlei Unfug (\x13 wird zu \x10 umgemappt, \x15 löscht den Eingabepuffer etc. pp.): Beitrag "Re: Linux Serial Port zu langsam"
Simon Budig schrieb: > Ich finde ja das select()-API total gruselig naja, schön ist es nicht. Aber wenn man es verstanden hat auch wieder nicht besonders schwierig. Zudem halt sehr effizient.
Klaus Wachtler schrieb: > [select()-API] > Aber wenn man es verstanden hat auch wieder nicht besonders schwierig. > Zudem halt sehr effizient. Auch wenn wir uns hier am Rande eines Glaubenskrieges bewegen... :) select() ist in der libc AFAIK mittels poll() implementiert. Die Friemelei mit den Bitfeldern ist total unbequem und fehlerträchtig (siehe oben), besonders wenn man Filedeskriptoren simultan auf Lesbarkeit und Schreibbarkeit überwachen will etc. pp. Ein Array von Poll-Deskriptoren setzt man einmal außerhalb der poll()-Schleife auf und kann es dann immer wieder verwenden ohne es neu initialisieren zu müssen. Nur wenn sich an der Menge der Filedeskriptoren etwas ändert muss man das nochmal anfassen. Aber egal, jeder verwende das was er mag :) Viele Grüße, Simon
Klaus Wachtler schrieb: > Ja, wenn man es so will, kann immer die bisherige Zeit von der > Gesamtzeit abziehen und nur den Rest übergeben. Das ist übrigens auch noch eine select()-Falle: select() aktualisiert das timeout-Argument (Posix: "may"), so dass anschließend die Restzeit drinsteht. Wenn man das also vor einem erneuten select()-Aufruf nicht wieder den Originalwert reinschreibt, hat man automatisch das Verhalten was hier in diesem Fall gewünscht ist, im allgemeinen Fall aber häufig lästig ist. Viele Grüße, Simon
Simon Budig schrieb: > Das ist übrigens auch noch eine select()-Falle: select() aktualisiert > das timeout-Argument (Posix: "may"), so dass anschließend die Restzeit > drinsteht. Übrigens nur unter Linux. (Daher auch das "may".) BSD (wo select() herkommt) hat das nie getan, und entsprechend auch alle anderen Clones davon nicht.
Jörg Wunsch schrieb: > Übrigens nur unter Linux. (Daher auch das "may".) BSD (wo select() > herkommt) hat das nie getan, und entsprechend auch alle anderen Clones > davon nicht. ich habe mir auch gerade mal die windows doku durchgelesen, da ist der parameter sogar const und wird auch nicht aktualisiert. (Das Linux immer alles anders machen muss...)
Ich bekomme das alles nicht hin. Verstehe von dem was ihr hier diskutiert auch nur noch die Hälfte. Es wäre super, wenn mir jemand eine .cpp und .h Datei mit Funktionierendem Code uploaden kann. Ihr scheint euch ja gut auszukennen. Die startReading methode brauche ich nicht. Die anderen Motoden sollten von der Schnittstelle her so bleiben wie sie sind. Die ReadByte methode soll eine bestimmte Anzahl Bytes (count) lesen und als unsigned char vector zurück geben. Wenn nach 2 Sekunden nicht alle Daten gelesen werden konnten soll ein leerer vector zurück gegeben werden. Wäre echt schön wenn mir jemand das macht. Vielen Dank.
Jörg Wunsch schrieb: > Simon Budig schrieb: >> Das ist übrigens auch noch eine select()-Falle: select() aktualisiert >> das timeout-Argument (Posix: "may"), so dass anschließend die Restzeit >> drinsteht. > > Übrigens nur unter Linux. (Daher auch das "may".) BSD (wo select() > herkommt) hat das nie getan, und entsprechend auch alle anderen Clones > davon nicht. Leider, denn eigentlich ist das recht praktisch. Typisches Problem ist, daß select wie jeder Systemcall beim Eintreten eines Signals vorzeitig zurückkehrt (mit errno=EAGAIN). Wenn man zuverlässig mit einem bestimmten Timeout warten will, ist es angenehm, wenn select einem gleich die noch zu wartende Zeit einträgt, die man dann so zum nächsten Aufruf weiterverwenden kann. Ohne dieses Feature muß man sich vorher mit gettimeofday den Startzeitpunkt merken, nach Rückkehr von select prüfen, ob die gewünschte Zeit schon abgelaufen ist, Restzeit ausrechnen und die an den nächsten select-Aufruf übergeben, und das finde ich nicht sonderlich elegant.
Rolf Magnus schrieb: > daß select wie jeder Systemcall beim Eintreten eines Signals vorzeitig > zurückkehrt (mit errno=EAGAIN) Sorry, meinte natürlich EINTR.
Rolf Magnus schrieb: > Ohne dieses Feature muß man sich vorher mit > gettimeofday den Startzeitpunkt merken, nach Rückkehr von select prüfen, > ob die gewünschte Zeit schon abgelaufen ist, Restzeit ausrechnen und die > an den nächsten select-Aufruf übergeben, und das finde ich nicht > sonderlich elegant. Wobei die Linux-Implementierung letztlich nicht viel anderes tun wird als genau dies. Dafür, dass sie das nun nicht-portabel macht, sich der Aufrufer also ohnehin nicht drauf verlassen kann und den ganzen Krams nochmal selbst implementieren muss, damit er portabel ist, war der Aufwand dann für die Katz'. Letztlich hat poll() das alles überholt (und dabei keinerlei eigene Vorkehrungen für die Restzeit mitgebracht).
So ich habe endlich eine Klasse geschrieben, die dass macht was ich möchte und gut Funktioniert. Zumindest in der der Testumgebung: der uController hat bei Epmfang von A1 27 bytes hochgezählt und gesendet. Die 27 Bytes habe ich alle Empfangen. Das Programm hängt sich auch nicht auf, wenn nichts empfangen wird. Allerdings dauert es dann ziemlich lange, da für jedes Byte ein eigener timeout abläuft. Seltsamer weise klappt es noch nicht mit dem richtigen Programm im uRechner. Dem werde ich aber morgen auf den Grund gehen.
Ich muss mich leider nocheinmal melden. Meine neu geschriebene Klasse funktioniert auch nicht richtig. Es werden manchmal leere Bytes eingelesen, und dadurch verschieben sich sie anderen.
Jan Remmert schrieb: > Es werden manchmal leere Bytes eingelesen, und dadurch verschieben sich > sie anderen. es gibt keine leeren bytes - was meinst du damit?
ist ja klar [c] unsigned char ComPort::readByte() { unsigned char buffer[1]; int n; n = read(this->fileDiscriptor,&buffer,1); if (n>0) { return buffer[0]; } else { return NULL; } } [\c] wie willst du die beiden zustände unterscheiden (NULL oder return buffer[0])?
OK Sry ich hatte noch was geändert bzw nutze diese Funktion
1 | ::std::vector<unsigned char> ComPort::readBytes(int count) |
2 | {
|
3 | int n; |
4 | unsigned char buffer[1]; |
5 | ::std::vector<unsigned char> vbuffer; |
6 | for(int i = 0; i < count; i++) |
7 | {
|
8 | n = read(this->fileDiscriptor,&buffer,1); |
9 | if (n>0) |
10 | {
|
11 | vbuffer.push_back(buffer[0]); |
12 | }
|
13 | }
|
14 | return vbuffer; |
15 | }
|
ja, und? Wenn read() scheitert (z.B. weil etwas zu früh gelesen wird), dann fehlen dir ein paar Bytes im Feld. Und warum? Weil du nicht mit select() (oder wie auch immer) darauf wartest, daß die Bytes auch gelesen werden können. Dann hast du aus voller Überzeuigung immer noch keine Synchronisation, worauf sich alles weitere verschiebt. Das wolltest du doch so haben, oder? :-)
Die Bytes die ich lesen möchte kommen ja direkt hinternander. Wenn es nicht zu Störungen kommt müssen auch alle gelesen werden mit dieser Funktion. Sonst wird sie irgendwann abbrechen und der zurück gegebene Vektor ist zu kurz. Dann werden die Daten verworfen. Dies darf hin und wieder vorkommen. Das Programm soll aus einem Mikrokontroller zyklisch, so schnell es geht Messwerte von Batterien und Temepraturfühlern auslesen. Um neue Messwerte zu empfangen wird A0,01 an den uRechner gesendet. Darauf hin sendet dieser sofart 27 Byte Daten. Byte 3 und 4 beinhalten sogar eine Prüfsumme, um die Richtigkeit der Daten sicherzustellen. Unter Windows geschiet das einige male in der Sekunde. Dann macht es auch nichts wenn hin und wieder Daten verworfen werden. Unter Linux klappt das noch nicht.
Jan Remmert schrieb: > Die Bytes die ich lesen möchte kommen ja direkt hinternander. Wenn es > nicht zu Störungen kommt müssen auch alle gelesen werden mit dieser > Funktion. Sonst wird sie irgendwann abbrechen und der zurück gegebene > Vektor ist zu kurz. Dann werden die Daten verworfen. Dies darf hin und > wieder vorkommen. Du schreibst leider nirgends, wie Du readBytes() denn nun verwendest. Deine Funktion liest im Normalfall weniger als (count) Bytes ein, da Du den seriellen Port nonblocking öffnest, d.h. das read() wird regelmäßig nichts lesen, da dein Programm die Schleife schneller durchlaufen wird, als der Port Daten liefern kann. Wenn Die aufrufende Funktion also nicht vorsichtig ist und checkt, ob genügend Daten zurückgeliefert wurden, können da auch schonmal Nullbytes drinstehen. Zudem wird - da Du Dich ja weigerst select() oder poll() zu verwenden - das Programm Busy-Waiting machen, d.h. der Prozess verbraucht jede Menge Rechenzeit um nichts zu tun. Entweder du verwendest select() und poll(), oder Du machst ein blocking read. In letzterem Fall blockiert dann das Programm aber solange bis tatsächlich ein Zeichen kommt. Viele Grüße, Simon
Also weniger Zeichen als er soll liest er eigendlich nicht ein. Das Programm soll auch blocken, da ich erst dann weiter machen will wenn alle Daten da sind.
Jan Remmert schrieb: > Das Programm soll auch blocken, da ich erst dann weiter machen will wenn > alle Daten da sind. Dann mach auf jeden Fall das O_NDELAY-Flag aus dem open() weg. Viele Grüße, Simon
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.