I use the Arduino compatible chipKIT WF32 board. I want to transfer structure data between my board and a Linux PC. Can I do it like the following?
struct data d;
char *tx = (char*)d;
Serial.print(tx);
Even if the above code works, the data type size in Arduino and on Linux will vary. Is there a way to serialize the data, like Protocol Buffers on Arduino?
-
1Casting to a char* will make Serial.print expect a null terminated string. So the amount of data transferred will depend on the next zero byte in memory(arbitrary).user2973– user29732015年04月07日 15:49:01 +00:00Commented Apr 7, 2015 at 15:49
2 Answers 2
The following solution isn't strictly portable, but it should work as long as both ends are little-endian (most platforms).
You can use the GCC attribute packed
to tell the compiler not to pad the fields like this:
struct __attribute__ ((packed)) my_struct {
char c;
int32_t n;
};
Then you can send your struct like this:
Serial.write((uint8_t*) a_my_struct_ptr, sizeof(my_struct));
On the receiving end you just copy the received data to a similarly packed struct. If you would rather use Python over C/C++ you can use the struct
module to unserialize the data.
I just googled your product and the MIPS processor is bi-endian, but I will assume that it is configured for little-endian by default. You can try and see if int
s keep their value after transmit. Also remember to use explicit size types such as int16_t, uint64_t, etc.
-
This may get messy - is an
int
32 bits on the chipkit reflecting its processor's actual word width, or is it 16 bits for compatibility with ATmega-insipired Arduinos? It probably makes sense to use explicit width types on both ends.Chris Stratton– Chris Stratton2015年04月08日 12:41:10 +00:00Commented Apr 8, 2015 at 12:41 -
Yes you are right I forgot to consider that, I've updated the answer to use fixed size types.user2973– user29732015年04月08日 20:32:45 +00:00Commented Apr 8, 2015 at 20:32
-
Is the sizeof struct really equal to the size of structure in memory? I think memory padding would pad empty bytes between variable. Correct me if I am wrong. Thanks.user48782– user487822018年08月13日 18:17:28 +00:00Commented Aug 13, 2018 at 18:17
-
@lionlai The
__attribute__ ((packed))
makes sure no padding is applied. If padding was used, you would get into trouble trying to send data from eg. an 8 bit platform to a 32 bit one. However,sizeof
does represent the size of the structure in memory including padding. Try this on eg. x86printf("%d\n", sizeof(struct {uint8_t a; uint32_t b;}));
It should print 8 (remember to include stdint.h).user2973– user29732018年08月15日 07:56:22 +00:00Commented Aug 15, 2018 at 7:56
I usually send structures from arduino via serial port to PC (削除) and use the memcpy function to do it. (削除ここまで)
Let's say you have the struct data d (as pointed by the comments the memcpy as unnecessary. Use cast or union):
struct data state;
len = sizeof(state);
Serial.write((uint8_t *)&state,len);
It is useful to create a starting and ending character to delimit your important data and make sure you receive all data and good information. Let me give you one of my recent work example:
...
void send_state(){
len = sizeof(state);
Serial.write('S');
Serial.write((uint8_t *)&state, len);
Serial.write('E');
return;
}
...
In this example the struct state is preceded with "S" (start) and succeeded with "E". Then in python, for example, you can get the data using the unpack function. In my case:
...
# wait for data from arduino
myByte = port.read(1)
if myByte == 'S':
data = port.read(39)
myByte = port.read(1)
if myByte == 'E':
# is a valid message struct
new_values = unpack('<c6BH14B4f', data)
...
See if arduino sends data in little endian. The one I have used to send it.
-
What do you hope to achieve by re-buffering the data especially on the transmit side? It is already in memory, so if you have a reason for making a copy of it, that should be stated.Chris Stratton– Chris Stratton2017年04月22日 17:52:29 +00:00Commented Apr 22, 2017 at 17:52
-
Thanks for pointing out. Indeed it is not necessary (and even stupid). I do not really remember any particular reason for that, but looking at it after all this time, I would guess it was some newbie mistake due to compile error related to the Serial.write expecting uint8_t and I (stupidly) made that work around. The simple cast should be enough or more safely, as I've been learning here, using unions right?brtiberio– brtiberio2017年04月27日 17:43:25 +00:00Commented Apr 27, 2017 at 17:43