1

i'm trying to send data from a C++ program over serial communication to an Arduino. I formed a struct for sending the data as an object:

typedef struct
{
   double width;
   double height;
   bool passBoard;
} MachineParameters;

I'm using this Serial library: http://wjwwood.github.com/serial/ for sending the data like this:

    MachineParameters mp;
    mp.width = 100;
    mp.height = 200;
    mp.passBoard = true;

    ser.write((const uint8_t *)&mp, sizeof(mp));

The library makes it possible to send the data as uint8_t, std::vector or std::string.

The Arduino does receive data, but i don't know how to parse the data into the struct. I'm using the same struct as in the cpp code.

// In Arduio

MachineParameters mp;
int byte_size = 24;

loop() {
   if(Serial.available() >= 24) {
     Serial.readBytes((char*) &mp , 24);
   } 
}

// Goal: Read received mp data just like
// mp.width or mp.height

After hours of trying, i still cannot figure it out, how to send this struct to the arduino successfully. Is there another way of sending this data to the arduino? It worked sending the data as string, but that did not seem right.

I am pretty new to programming with C++, so please excuse any obvious questions...

Thank you for helping!


UPDATE: Working solution below

After a view more tries and thanks to your tips, i figured it out. Here is the code, which worked for me. I found out that my problem was the wrong byte size, used for parsing the buffer. The size of the struct in C++ is 12, whereas on the arduino it's 9. Using the original size (12) for parsing the buffer on the Arduino, the struct was parsed correctly.

/* --- C++ CODE --- */
typedef struct
{
   double width;
   double height;
   bool passBoard;
} MachineParameters;
// sizeof(MachineParameters) returns 12.


MachineParameters mp;
mp.width = 11.1;
mp.passBoard = false;
mp.height = 22.2;

ser.write((uint8_t *)&mp, sizeof(mp));
/* --- END OF C++ --- */



/* --- Arduino Code --- */
#define   BYTE_SIZE   12
char messageBuffer[BYTE_SIZE];

typedef struct
{
   double width;
   double height;
   bool passBoard;
} MachineParameters;

MachineParameters mp;

void setup() {
  Serial.begin(9600);
}

void loop() {

  if (Serial.available() >= BYTE_SIZE) {
    Serial.readBytes(messageBuffer , BYTE_SIZE);
    memcpy(&mp, &messageBuffer, BYTE_SIZE);

    // mp.width returns 11.1
    // Success :)
  }
}
/* --- END OF ARDUINO --- */
mafo
  • 11
  • 1
  • 3
  • 1
    Please show us how you're trying to send the data, not just a description thereof. We can't tell you what's wrong if we don't know what you're doing. – Cubic Jan 11 '18 at 17:20
  • Are you sending the structure verbatim or each field independently? Are you sending in binary or text? – Thomas Matthews Jan 11 '18 at 18:05
  • Sorry, when i wrote the question, i was quite in a hurry. I edited the question now, hoping you can understand my problem now. – mafo Jan 11 '18 at 19:11
  • 1
    How do you know that the Arduino receives the data? And what happens when you try to deserialize the data (tat is, parse it back into the struct) on the same machine that you use to serialize it, without involving the Arduino? And have you tried sending simpler data to the Arduino by this method? – Beta Jan 11 '18 at 21:18
  • Yeah, I'd like to see a better description of why you think the code doesn't work and what you did to debug. What is Serial.available() returning after you send the data from your computer? If you read in all the available bytes and just look at the raw values of those bytes, what are they? Your Arduino program has no output so how do you know it's not working? What is `sizeof(MachineParameters)` on both systems? You might need to make the struct be packed so thare is no padding added by either compiler. – David Grayson Jan 12 '18 at 00:48
  • I know the arduino receives data, because it works with simple data, like an int or a string. `sizeof(MachineParameters) ` is different on both systems. C++ returns as size `24`, whereas on arduino it's `9`. – mafo Jan 12 '18 at 11:36
  • Btw, type double is the same size as float in the Arduino. And if you want integral values for width, height there is no need for double(float) at all. – KIIV Jan 12 '18 at 13:57
  • The parameters `100`and `200` were just a bad example. Width as well as height should be definately doubles/floats. – mafo Jan 12 '18 at 14:01

1 Answers1

0

on the arduino you receive the data in a buffer as raw bytes

now you have to parse this, you can do this using memcpy to copy the data in the struct

however for doing this the data has to be aligned meaning that you have to know exactly where it begins. so you should send a synchronization byte ( start / stop bytes ) to be able to fix where the data begins

then you can use the code in parsing buffer data into struct :

struct abc {
    char a;
    char b;
    char c;
    char d[2];
};

int main() {

    char arr[5] = { 'a', 'b', 'c', 'd', 'e' };
    struct abc sa;
    memcpy(&sa, arr, 5);


    return 0;
}

here arr is incoming buffer, and with memcpy all the contents are copied appropriately.

ser.write((const uint8_t *)&mp, sizeof(mp)); is correct

you can create an identical structure mp_arduino on the arduino and copy the content of the receive buffer into this structure with

memcpy ( &mp_arduino, receive_buffer+n, sizeof(mp_arduino) ); where n indicates the position / byte in receive_buffer where your data begins and receive_buffer is defined as uint8_t receive_buffer[] ( or uint8_t* receive_buffer is the same... )

( http://www.cplusplus.com/reference/cstring/memcpy/ )

this is how a struct is stored in memory : How is a struct stored in memory?

on both systems a float should be 32 bit https://www.arduino.cc/reference/en/language/variables/data-types/float/

ralf htp
  • 9,149
  • 4
  • 22
  • 34
  • So do you think that sending the data with `ser.write((const uint8_t *)&mp, sizeof(mp));` is correct? – mafo Jan 12 '18 at 14:01