Go Down

Topic: Sending a data structure over serial (Read 21844 times) previous topic - next topic

icecool2

I'm looking to send a data structure over the serial port.  Is there a way to use Serial.print() for this or is there a better way to send it?

AWOL

There is no defined method for sending a structure in C/C++, except in shared memory architectures, when memcpy (or even simple assignment) may be used.
Some C++ objects may include serialisation member functions, but it is not obligatory.

Both ends of the link need to be aware of the structure and the data-types it is composed of.

Look out for gotchas like sizeof (int) and word order (little/big-endian) where sender and receiver are of different architectures.

icecool2

Hey AWOL,

The data structure is defined on both sides of the link.  I guess I can just do a memcpy of the structure onto a char array.  That should work right?

AWOL

#3
Jun 04, 2009, 04:48 pm Last Edit: Jun 04, 2009, 04:57 pm by AWOL Reason: 1
Quote
That should work right?


Sometimes.   >:(

There's another gotcha, and that's packing, though it probably won't happen here. Some processors require certain types like "long" to only be positioned on addresses divisible by four, or "short"s only on even addresses .
So, if you've got a structure like

typedef struct {
 char a;
 char b;
 long c;
} myStruct_t;

You might find on some processors that sizeof (myStruct_t) returns "6", and on others "8". In the latter case, invisible padding of two bytes is inserted into the structure after "b".
It is sometimes possible to persuade the compiler not to do this with a #pragma

If you're going to try "memcpy", just make sure that the size of the structures on the two machines match. (not a problem if both are Arduinos).

icecool2

Excellent point.  Didn't think about that.  One side is an Arduino, the other is a Gumstix.  I'll run a check to verify that they are the same size.

Thanks.

ArduinoBerlin

#5
Jun 04, 2009, 05:03 pm Last Edit: Jun 04, 2009, 05:04 pm by ArduinoBerlin Reason: 1
Hi, I would also suggest wrapping a union aroud those structs, so that you can send them to the external device bytewise:

Code: [Select]

typedef union
{
struct_t mystruct;
uint8_t my_struct_bytes[sizeof(struct_t)];
} my_struct_t_union;

icecool2

Here's a new one....

I figured out how to get the data structure to send.  I changed everything to be uint16_t on both sides.  I'm seeing two extra '0' come up in the data stream somewhere in the middle.  Ideas?

Code: [Select]
typedef struct {
 int messageCount;
 int time;
} __attribute__((__packed__))packet_header_t;

typedef struct {
 packet_header_t header;
 int16_t rotationRate;
 int16_t therm1;
 int16_t therm2;
 int16_t heading;
 //uint32_t pressure;
 int16_t airTemp;
 int16_t checksum;
} __attribute__((__packed__)) data_packet_t;


icecool2

Woops... figured it out.

Never mind.

AWOL

Code: [Select]
typedef struct {
 int messageCount;
 int time;
} __attribute__((__packed__))packet_header_t;


These aren't "int_16" s

Any clues how far in the padding comes?


icecool2

#10
Jun 05, 2009, 11:37 pm Last Edit: Jun 05, 2009, 11:39 pm by icecool2 Reason: 1
I was making my edits in the wrong spot.  Everything is int16_t.  I had an extra item in the structure.

I am noticing that there is a "2570" showing up after I send my message.  Still trying to track that down.  Ideas?

The println at the end is the only way I could get the data to actually be received on the other end.  Suggestions there?

Here's the code:
Code: [Select]
typedef struct {
 int8_t id;
 int16_t messageCount;
 int16_t time;
} __attribute__((__packed__))packet_header_t;

typedef struct {
 packet_header_t header;
 int16_t rotationRate;
 int16_t therm1;
 int16_t therm2;
 int16_t heading;
 //uint32_t pressure;
 int16_t airTemp;
 int16_t checksum;
} __attribute__((__packed__))data_packet_t;

data_packet_t dp;

void setup() {
 Serial.begin(115200);
 dp.header.id = 99;
 dp.header.messageCount = 0;
 dp.header.time = 1;
 dp.rotationRate = 2;
 dp.therm1 = 3;
 dp.therm2 = 4;
 dp.heading = 5;
 dp.airTemp = 6;
 dp.checksum = 7;
}

void loop() {
 unsigned short checkSum;

 unsigned long uBufSize = sizeof(data_packet_t);
 char pBuffer[uBufSize];

 memcpy(pBuffer, &dp, uBufSize);
 for(int i = 0; i<uBufSize;i++) {
   Serial.print(pBuffer[i]);
 }
 Serial.println();

}

ishinay

I really don't know if this is something related... (I never used packed):

http://grok2.tripod.com/structure_packing.html

Quote
Note that this doesn't seem to work right if you try to combine the typedef and the struct definition or if you combine variable declarations with the structure definition.

Go Up