Hallo Gemeinde,
ich steige gerade von µC / C auf das BeagleBone Black in C++ um und bin
mittlerweile ein bisschen verweifelt. Ich hoffe sehr, hier ein paar
Ideen und Vorschläge zu bekommen.
Ich ich habe eine Funktion
1
intdecodeData(char*buffer,intreceived_bytes)
die bekommt zeitlich versetzt die zuvor über einen Bus empfangenen
Hex-Werte übergeben. Diese muss ich "nichtflüchtig" erstmal
zwischenspeichern (ich denke da an "static") und sobald mehr als 14
Bytes (= 14 Hex-Werte) übergeben wurden, muss ich innerhalb dieser 14
Werte nach einem Hex-Muster "0x0201C1" suchen. Hier beginnt nämlich ein
wichtiges Paket.
So, ich könnte das natürlich alles mit einem Array machen und hier mit
diversen Schleifen usw. arbeiten und suchen lassen. Aber gibt's da in
C++ nicht eine elegantere Lösung?? Ich hab jetzt schon viel mit strings
und vectoren versucht, aber immer bleibe ich irgendwo hängen... Oder
gibt's da echt keine gute Lösung außer den "alten" C-Arrays??
Tausend Dank!
Michaela
Das Problem ist hier wohl, dass du die letzten 14 Zeichen speichern
willst und das auch noch der Reihenfolge nach. Wenn du vector oder
strings benutzt hast du das Problem das du vorne ein Zeichen wegnehmen
musst und hinten eins dranhängen. Gerade das vorne wegnehmen sind
operationen die von beiden Typen nicht effizient umzusetzen sind. Du
suchst wohl so etwas wie einen Ringbuffer. Da gibts in C++ direkt nichts
aber die boost Library hat sowas:
http://www.boost.org/doc/libs/1_55_0/doc/html/circular_buffer.html
Boost ist natürlich ziemlich komplexes C++ und eventuell ungeeignet für
Mikrocontroller. Habe ich selbst noch nicht ausprobiert. Ich würde fast
bei einem C Array bleiben und das ganze "von Hand" machen.
sebi707 schrieb:> Das Problem ist hier wohl, dass du die letzten 14 Zeichen speichern> willst und das auch noch der Reihenfolge nach. Wenn du vector oder> strings benutzt hast du das Problem das du vorne ein Zeichen wegnehmen> musst und hinten eins dranhängen. Gerade das vorne wegnehmen sind> operationen die von beiden Typen nicht effizient umzusetzen sind.> Da gibts in C++ direkt nichts
Es gibt std::deque.
sebi707 schrieb:> Gerade das vorne wegnehmen sind> operationen die von beiden Typen nicht effizient umzusetzen sind.
Dafür gibts entweder std::list (Doppelt verkettete Liste). Hat aber
(eben durch die Doppel-Verkettung) einen großen Overhead, also für
"char" nicht so sinnvoll.
Dann gibts noch "std::deque", eine "double ended queue", die ist exakt
für sowas da. Effizient auch für 1-byte-Datentypen, push&pop auf beiden
Enden in (armortisierter) konstanter Zeit.
Kopiert aber oft ihren Inhalt um, d.H. nichts für Datentypen mit teurem
Copy-Construktor...
Hallo zusammen,
und Danke erstmal!
std::deque und boost
sagen mir erstmal leider gar nichts. Auch nach kurzer Suche und dem
Überfliegen einiger Internetseiten hat sich daran nichts geändert.
Scheint für mich wohl ohne char array doch zu kompliziert zu sein...
Dann wollte ich doch zu viel und bleibe somit wohl besser bei einem C
array. Wenigstens habe ich es (auch mit netter Hilfe) versucht.
Danke euch trotzdem sehr für die schnelle, freundliche und kompetente
Hilfe!
Michaela
CPlusPlus schrieb:> Kopiert aber oft ihren Inhalt um, d.H. nichts für Datentypen mit teurem> Copy-Construktor...
Nicht mehr seit C++11 und Move Semantics, man muss nur an den richtigen
Stellen std::move einstreuen.
Dr. Sommer schrieb:> Warum nicht schlicht std::string und std::string::find?std::string> buffer;> int decodeData(char *rec, int received_bytes) {> buffer += std::string (rec, received_bytes);> if (buffer.size () >= 14) {> auto pos = buffer.find ("\x02\x01\xC1", 3);> if (pos != std::string::npos) {> std::cout << "Gefunden an Stelle " << pos << "\n";> }> }> }
Mensch super! Danke Dr. Sommer! Funktioniert wunderbar. So muss ich doch
keine Schleifen programmieren.
Ich war schon relativ weit mit den Strings, aber auf:
1
buffer.find("\x02\x01\xC1",3)
bin und wäre ich nie gekommen.
Nochmals Danke auch an die anderen! Sst einfach klasse, wie einem hier
geholfen wird.
LG Michaela
Dr. Sommer schrieb:> Tip: Nachgucken kann man das unter> http://en.cppreference.com/w/cpp/string/basic_string
Danke. Die Funktion "find" hatte ich schon gefunden. Aber dass man die
hex-Werte mit "\x02\x01\xC1" maskiert, darauf wäre ich nie gekommen.
Vielleicht darf ich hier gerade noch eine Frage stellen, wo ich glaube
ich irgendwie voll auf dem Schlauch stehe.
Dieser von mir empfangene String besteht ja aus 14 Byte, die drei
Startbits
'0x02' '0x01' '0xC1'
konnte ich jetzt durch eure Hilfe komfortabel erkennen.
Byte vier und fünf repräsentieren zusammen eine Zweierkomplement-Zahl,
also z.B.: 0xFFF8 (Bin 1111111111111000) = -8
Die zwei Bytes habe ich mit
1
Zahl=BufferLocal.substr(4,2);
extrahiert und habe jetzt vergeblich versucht, den String "Zahl" in
einen signed int zu verwandeln...
U.A. habe ich es mit stringstream versucht, aber das geht ja davon aus,
dass die zwei Bytes z.B. die Buchstaben 'FA' darstellen und gibt mir
dann 250 aus. Beim googlen kommt natürlich immer genau dieser Fall....
Nochmals Danke!
Michaela
Ich denke du merkst schön langsam selbst, dass eine Bytefolge nun mal
kein String ist. Es ist daher nicht wirklich klug, mit Strings an
derartige Dinge heranzugehen. Strings sind in erster Linie für Texte
gedacht und nicht um damit beliebige Bytes zu bearbeiten. Ein paar
Operationen mögen ja funktionieren, aber std::string ist nun mal auf
Texte geprägt.
Du kannstz natürlich immer noch die Bytes 'per Hand' zusammensetzen
Summe = Byte1 * 256 + Byte2;
man braucht nicht wirklich für alles Spezialfunktionen.
Michaela schrieb:> extrahiert und habe jetzt vergeblich versucht, den String "Zahl" in> einen signed int zu verwandeln...
Das Problem ist dass das signed Zahlenformat nicht standardisiert ist.
Eine einfache Möglichkeit die mit dem GCC und x86 (ARM vermutlich auch)
funktioniert ist:
Ziemlich hässlich, was kürzeres ist mir grad nicht eingefallen...
Funktioniert dafür auch mit deinem Big Endian signed format.
Karl Heinz schrieb:> Ich denke du merkst schön langsam selbst, dass eine Bytefolge nun mal> kein String ist. Es ist daher nicht wirklich klug, mit Strings an> derartige Dinge heranzugehen. Strings sind in erster Linie für Texte> gedacht und nicht um damit beliebige Bytes zu bearbeiten.
Warum nicht?! Ein C++-string ist wie ein vector<char> mit Extras, warum
sollte man ihn nicht dafür verwenden? Es handelt sich schließlich nicht
um C-Strings, die keine 0-Bytes mögen...
Karl Heinz schrieb:> Summe = Byte1 * 256 + Byte2;
Hallo Karl Heinz,
ja natürlich, das geht auch. Ich kann auch die einzelnen Bytes des
Strings mir so holen, aber dann wird daraus trotzdem noch kein signed:
1
intSumme=Byte1*256+Byte2;
1
intSumme=(Byte1<<8)+Byte2;
1
intSumme=(Byte1<<8)|Byte2;
immer bekomme ich aus den zwei Bytes '0xFF' und '0xFA' die Zahl 65530
und nicht die negative Zahl -6...
Karl Heinz schrieb:> Du kannstz natürlich immer noch die Bytes 'per Hand' zusammensetzen>> Summe = Byte1 * 256 + Byte2;
Das klappt leider nicht mit den signed Typen...
Dr. Sommer schrieb:> int16_t out = static_cast<int16_t> ( (static_cast<uint16_t>> (static_cast<uint8_t> (Zahl[0])) << 8) | static_cast<uint16_t>> (static_cast<uint8_t> (Zahl[1])));
Ja, so klappt es!! Von solchen Lösungen bin ich mit meinem Wissen echt
noch weit entfernt ...
Mich hat die fehlende String-Funktion bei C immer irgendwie gefehlt, es
bleiben ja dann nur die Char-Arrays. Deshalb wollte ich jetzt beim
Umstieg so viel wie möglich von den "mächtigen Strings" profitieren.
Oder es zumindest mal damit versuchen.
Heute hat's mich leider wieder den ganzen Abend gekostet...
Um so mehr nochmal ein herzliches Danke!
Und guten Nacht...
Michaela
Michaela schrieb:> Ja, so klappt es!! Von solchen Lösungen bin ich mit meinem Wissen echt> noch weit entfernt ...
Die Integer-Konversions-Geschichten sind in C/C++ ziemlich delikat, da
sie unter allen (un)möglichen Plattformen funktionieren sollen, mit
13-Bit-'chars', 1-Complement-Integern etc. ... Daher gibt es auch keine
eingebauten fertigen allgemeinen Konvertierungsfunktionen. Durch ein
paar alte aus C geerbte ungünstige Regeln wird das dann noch
verkompliziert.
Hallo zusammen,
ich trau mich ja schon fast nicht mehr zu schreiben, aber vielleicht
könnte sich jemand mal meinen finalen Code anschauen. Das Programm hängt
sich leider unter bestimmten Umständen immer auf:
einfüge, bzw. die Zeilen zum Abspeichern der Datei. Dann läuft das
Programm einmal durch und bleibt dann hängen.
Auch wenn ich diese Zeilen drin lasse, aber dafür die oberen Zeilen
(Zuordnung der Werte aus dem Datenfeld) weglasse, funktionert der
Code...
Habe ich da irgendwelche Fehler drin, die in der Summe zu einem Absturz
führen?
Mein Remote-Debuggen auf dem BeagelBoard läuft noch nicht, sonst hätte
mir das vielleicht geholfen.
Zum wiederholten mal DANKE!
Michaela
Michaela schrieb:> int processWeather(string &Daten) {
Veränderst du "Daten" in der Funktion? Nein. Also wenn schon "const
std::string& Daten".
> unsigned int typ = Daten[0];> unsigned int adresse = Daten[1];> int16_t temp = static_cast<int16_t> ( (static_cast<uint16_t>> (static_cast<uint8_t> (Daten[2])) << 8) | static_cast<uint16_t>> (static_cast<uint8_t> (Daten[3])));> float feuchte = static_cast<float>(Daten[4]*256 + Daten[5])/10;> float wind = static_cast<float>(Daten[6]*256 + Daten[7])/10;> unsigned int wippen = Daten[8]*256 + Daten[9];> unsigned int regen = Daten[10];
Ja, äh, erläutere doch mal das Datenformat, es ist jetzt nicht so leicht
zu erraten ob das tut was es sollte!
> strftime(timestamp, 22, "%d.%m.%Y - %H:%M:%S", localtime(&now));
localtime ist nicht thread-safe, verwendest du mehrere Threads?
> einfüge, bzw. die Zeilen zum Abspeichern der Datei. Dann läuft das> Programm einmal durch und bleibt dann hängen.
Ja wo denn genau?
> Habe ich da irgendwelche Fehler drin, die in der Summe zu einem Absturz> führen?
Schwierig zu sagen bei der Konvertiererei.
> Mein Remote-Debuggen auf dem BeagelBoard läuft noch nicht, sonst hätte> mir das vielleicht geholfen.
Dann debugge halt lokal durch installation und Aufruf von "gdb" auf der
Kommandozeile, vllt auch valgrind. Dann kannst du sehen wo es stehen
bleibt/abstürzt. Kompilieren mit "-g" nicht vergessen.
Dr. Sommer schrieb:> Dann debugge halt lokal durch installation und Aufruf von "gdb" auf der> Kommandozeile, vllt auch valgrind. Dann kannst du sehen wo es stehen> bleibt/abstürzt. Kompilieren mit "-g" nicht vergessen.
Danke für den Kommandozeilen-Tipp. Nach ein bisschen Einarbeitung konnte
ich mit dem Debugger arbeiten und auch den Fehler finden. Hatte an einer
ganz anderen Stelle im Programm noch einen Timer laufen, der bei
längerer Abarbeitungszeit in anderen Funktionen einen Überlauf hatte.
Die Zeit wurde immer gerade dadurch erreicht, wenn die obige Funktion
mit weiteren Befehlen "verlängert" wurde.
Saudoofer Fehler...