Split of an 60 bytes array back into float, long, float... whatever

Hi!

I successfully transferred some data from one Arduino to another. No I receive all data in an 60 byte array and I am not sure how to handle it...

What I send:

struct callback {
	float Value1 = 1;
	float Value2 = 2;
	long Value3  = 3;
	long Value4 = 4;
	uint8_t Value5 = 5;
	float Value6 = 6;
	float Value7 = 7;
	float Value8 = 8;
} returnData;

(!rf69_manager.sendtoWait((byte*)&returnData, sizeof(returnData), from))

here I receive the code:

 if (rf69_manager.recvfromAckTimeout(buf, &len, 10, &from))

the &len is the maximum length I can transfer, 60 bytes total... enough for my stuff! But how can bring them back into my old values... do I have to split them all off and write them manually back?

thanks!

Hi

'No i receive' klingt nun Mal nicht wirklich Englisch - Du bist hier im deutschen Zweig des Forum - hier darf Deutsch geschrieben werden.
Aufgrund Deines Fauxpas gehe ich davon aus: Englisch ist nicht Deine Haupt-Sprache :wink:

Dein len gibt Dir, sehr wahrscheinlich, NUR die Lände/die Anzahl der übertragenen Bytes zurück - würde zumindest für den Namen 'len' sprechen.

Wenn Du diese Struktur auf beiden Seiten hast (wovon auszugehen ist) - warum schreibst Du nicht einen Datensatz in diese Struktur?
Entweder in der IDE, oder hier im Forum gab's ein Beispiel, wie man - zumindest via I²C - beliebige 'Klumpen an Daten' zum anderen Arduino bringt.

MfG

Kommt auf die Empfangs-Methode der Library an. Falls du nur eine Methode hast um einzelne Bytes zu empfangen, einfach die Adresse einer Struktur-Variable auf einen Zeiger auf Byte casten. Dann kannst du die Struktur wie ein Array ansprechen

Ich habe keine Ahnung warum ich auf englisch geschrieben habe... vermutlich weil ich schon stundenlang herumstöbere und an einem englischen laptop arbeite. Sorry, aber zum Glück habt ihr mich verstanden :slight_smile:

Ja, die Struktur befindet sich auf beiden Seiten. Aber ich bekomme von rf69_manager.recvfromAckTimeout() lediglich einen langen Array von bytes zurück. Anscheinend kann ihr nicht einfach wie beim NRF24 die Struktur als ganzes übertragen und abgreifen.

   /// Send the message (with retries) and waits for an ack. Returns true if an acknowledgement is received.
   /// Synchronous: any message other than the desired ACK received while waiting is discarded.
   /// Blocks until an ACK is received or all retries are exhausted (ie up to retries*timeout milliseconds).
   /// If the destination address is the broadcast address RH_BROADCAST_ADDRESS (255), the message will 
   /// be sent as a broadcast, but receiving nodes do not acknowledge, and sendtoWait() returns true immediately
   /// without waiting for any acknowledgements.
   /// \param[in] address The address to send the message to.
   /// \param[in] buf Pointer to the binary message to send
   /// \param[in] len Number of octets to send
   /// \return true if the message was transmitted and an acknowledgement was received.
   bool sendtoWait(uint8_t* buf, uint8_t len, uint8_t address);

oder habe ich das hier missverstanden?

ich habe es inzwischen gelöst... das muss doch aber auch smarter gehen oder? Die komplette Struktur im ganzen abgreifen ware natürlich am schönsten.

     byte bufValue01[3];
     bufValue01[0] = buf[0]; 
     bufValue01[1] = buf[1]; 
     bufValue01[2] = buf[2]; 
     bufValue01[3] = buf[3]; 

     returnData. Value01 = *((float*)bufValue01);

Wobei ich den Teil hier nicht verstehe... ((float)bufValue01). leidlich irgendwo gefunden.

Schau dir Zeiger an. Schau dir Typumwandlungen/Casts an

Wieso machst du den Empfang hier nicht analog zum Senden?

if (rf69_manager.recvfromAckTimeout(buf, &len, 10, &from))

Nur weil der Paramter ein byte* musst du da nicht ein Byte-Array übergeben. Man nimmt die Adresse eines structs und castet diese auf byte*
Sowie hier:

(!rf69_manager.sendtoWait((byte*)&returnData, sizeof(returnData), from))

Ansonsten gibt es für sowas noch Unions

   byte bufValue01[3];
     bufValue01[0] = buf[0];
     bufValue01[1] = buf[1];
     bufValue01[2] = buf[2];
     bufValue01[3] = buf[3];

Achtung böser böser Fehler:
Du definierst ein 3 Element großes Array schreibst aber 4 Elemente. So überschreibst Du die nächste Variable im Speicher. Das ergibt unvorhersagbare Fehlerbilder die zum Verrücktwerden sind, wenn Du verstehen willst was der Grund des Fehlers ist.

Grüße Uwe

Serenifly:
Schau dir Zeiger an. Schau dir Typumwandlungen/Casts an

Wieso machst du den Empfang hier nicht analog zum Senden?

if (rf69_manager.recvfromAckTimeout(buf, &len, 10, &from))

Nur weil der Paramter ein byte* musst du da nicht ein Byte-Array übergeben. Man nimmt die Adresse eines structs und castet diese auf byte*
Sowie hier:

(!rf69_manager.sendtoWait((byte*)&returnData, sizeof(returnData), from))

Ansonsten gibt es für sowas noch Unions

Genau das mache ich ja... ich sende das ganze als "struct", finde aber keinen Weg das ganze auch als struct abzurufen. Oder mache ich da nur etwas falsch?

Ich hätte eigentlich erwartete, ich kann es so empfangen:

if (rf69_manager.recvfromAckTimeout((byte*)&returnData, sizeof(returnData), 10, &from)) {

aber dann bekomme ich folgenden Fehler:

/Users/XX/Documents/GitHub/FeatherM0-Esk8-Remote/transmitter/transmitter.ino: In function 'void transmitToReceiver()':
transmitter:376: error: invalid conversion from 'unsigned int' to 'uint8_t* {aka unsigned char*}' [-fpermissive]
       if (rf69_manager.recvfromAckTimeout((byte*)&returnData, sizeof(returnData), 10, &from)) {
                                                                     ^
In file included from /Users/XX/Documents/GitHub/FeatherM0-Esk8-Remote/transmitter/transmitter.ino:13:0:
/Users/XX/Documents/Arduino/libraries/RadioHead/RHReliableDatagram.h:155:10: error:   initializing argument 2 of 'bool RHReliableDatagram::recvfromAckTimeout(uint8_t*, uint8_t*, uint16_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*)' [-fpermissive]
     bool recvfromAckTimeout(uint8_t* buf, uint8_t* len,  uint16_t timeout, uint8_t* from = NULL, uint8_t* to = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
          ^
exit status 1
invalid conversion from 'unsigned int' to 'uint8_t* {aka unsigned char*}' [-fpermissive]

uwefed:

   byte bufValue01[3];

bufValue01[0] = buf[0];
    bufValue01[1] = buf[1];
    bufValue01[2] = buf[2];
    bufValue01[3] = buf[3];




Achtung böser böser Fehler:
Du definierst ein 3 Element großes Array schreibst aber 4 Elemente. So überschreibst Du die nächste Variable im Speicher. Das ergibt unvorhersagbare Fehlerbilder die zum Verrücktwerden sind, wenn Du verstehen willst was der Grund des Fehlers ist.

Grüße Uwe

Danke fuer den Hinweis!! Habe da was durcheinander gebracht!

Also ein bisschen Nachdenken musst du schon selber und dir mal die Parameter der Methoden anschauen

Und auch die Fehlermeldung durchlesen. Die sagt genau was falsch ist:

invalid conversion from 'unsigned int' to 'uint8_t*
...
initializing argument 2

Wie kommst du von dem:

if (rf69_manager.recvfromAckTimeout(buf, &len, 10, &from))

zu dem:

if (rf69_manager.recvfromAckTimeout((byte*)&returnData, sizeof(returnData), 10, &from))

Wenn die Signatur so aussieht:

 bool recvfromAckTimeout(uint8_t* buf, uint8_t* len,  uint16_t timeout, uint8_t* from)

Das mit &len hat schon gepasst. Die Methode gibt da wahrscheinlich die Länge der empfangenen Daten zurück. Deshalb der Zeiger auf eine Variable statt sizeof() als konstanten Wert

Ich habe mir kurz etwas mehr mit dem Thema beschäftigt wie du schon gesagt hast. Ich denke es hat wunder gewirkt.

      if (rf69_manager.recvfromAckTimeout((uint8_t*)&returnData, &len, 10, &from)) {

sollte die Lösung sein.

Ich muss ein byte zurückgeben. EINES. Um genauer zu sein, die Adresse des ersten bytes von wo auch immer die Daten hingehen sollen. Da die Struktur auf beiden Seiten gleich ist, kann ich ganz einfach die Adresse des ersten bytes von returnData angeben mit &returnData. Inklusive dem Zeiger darauf *, ist es eine saubere Lösung und alle Daten aus der Übertragung werden jetzt byte fuer byte auf den Speicherort returnData geschrieben.

Allerdings muss ich dann noch aufpassen bei &len.

Im moment steht den folg da:

uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
uint8_t from;

Da mein gesendeter String nie länger ist als die meine Struckur (sind ja auf beiden Seiten gleich) müsste alles gut gehen. Trotzdem ist es nichtkorrekt oder? Theoretisch könnte ich hier die lange der Struktur angeben... also:

uint8_t len = sizeof(returnData);

Richtig oder totaler mist?

Vielen dank schonmal fuer den Anstoß und die Hilfe.

Hi

Das Problem könnte sein, wenn Du 'irgendwas Anderes' empfängst, was länger als Deine Struktur ist, aber eben in einem Rutsch vom RH_RF69 eingelesen werden kann, wird Der Das auch tun - und Du überschreibst Dir irgendwelche Daten, Die hinter Deinem Empfangs-Puffer stehen.
Sonst, wenn Du sicher bist, NIE mehr Daten zu bekommen, als in Deinen Puffer rein gehören - sollte Das klappen.
Wäre mir aber zu unsicher - eine kompromittierte Übertragung, und Da kommt 'was auch immer' zusammen - kannst Du den RH_RF69 Buffer ebenfalls verkleinern? Dort dürften dann ja ebenfalls nie mehr Zeichen anfallen, als Du empfangen willst.

Um welche Differenz sprechen wir hier?

MfG

StefanMe:
uint8_t len = sizeof(buf);

buf benötigst Du nicht, stattdessen nutzt Du returnData. Daher macht

uint8_t len = sizeof(returnData);

Sinn.

   if (*len > msgLen)
 *len = msgLen;
    memcpy(buf, a->data, *len);

len hat zwei Bedeutungen:

  • Du gibst an, wie groß der reservierte Speicheplatz ist. Mehr Bytes werden nicht empfangen. Vor recvfromAckTimeout muß len immer auf den richtigen Wert gesetzt werden.
  • Die Anzahl der tatsächlich übertragenen Bytes steht nach der Übertragung in len. Das könnte man überprüfen.

Diese Methode bietet noch mehr Parameter: uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags

postmaster-ino:
Das Problem könnte sein, wenn Du ‘irgendwas Anderes’ empfängst, was länger als Deine Struktur ist, aber eben in einem Rutsch vom RH_RF69 eingelesen werden kann, wird Der Das auch tun - und Du überschreibst Dir irgendwelche Daten, Die hinter Deinem Empfangs-Puffer stehen.

Nein, die Anzahl ist auf len begrenzt. Siehe RHMesh.cpp.