Search code examples
carduinobuffermemcpyuint8t

Store multiple variables to buffer with memcpy


I'm very new to Arduino and I can't find any way to do the following. I have a typedef struct which fills up multiple values:

void loop() {
accel.process();
AccelerationReading accelData;
accelData.xAxis = accel.xAxis;
accelData.yAxis = accel.yAxis;
accelData.zAxis = accel.zAxis;
//Irrelevant code after this
}

After the struct is filled I memcpy it in to the buffer:

uint8_t buffer[6];
memcpy((void*)buffer, (void*)&accelData, 6);

Now this works fine but I also need to read values from two analog ports and those two values also need to be added in the memcpy. The code that fills the two variables:

//New variables
int shortflexposition;
int longflexposition;
//Filling up the variables.
shortflexposition = analogRead(shortflexpin);
longflexposition = analogRead(longflexpin);

The accelData contains 6 bytes of raw values and now I want to add shortflexposition and longflexposition after these bytes. The values in the variables shortflexposition and longflexposition are always between 0 and 1023. How exactly should I add those other variables in the memcpy? I've tried for example:

uint8_t buffer[8];
memcpy((void*)buffer, (void*)&accelData + shortflexposition, 8);

But this seems to rather add values to eachother than adding them to the next bytes or something. So, how do I add new variables on the next byte positions with memcpy?

Thanks! Yenthe

Update: This is an attempt at the code from Lundin..

typedef union
{
  struct s
  {
    AccelerationReading accelData;
    uint16_t shortflexposition;
    uint16_t longflexposition;
  };
 uint8_t raw_data [sizeof(struct s)];
 } my_data;

void setup() {
// Bean Serial is at a fixed baud rate. Changing the value in Serial.begin() has no effect.
Serial.begin();   
accel.init();
}

void loop() {
  accel.process();
  AccelerationReading accelData;
  my_data data;
  data.accelData.xAxis = accel.xAxis;
  data.accelData.yAxis = accel.yAxis;
  data.accelData.zAxis = accel.zAxis;

  //Get flex readings
  int shortflexposition;
  int longflexposition;

  //Read the position of the flex sensor (0 to 1023?)
  data.shortflexposition = analogRead(shortflexpin);
  data.longflexposition = analogRead(longflexpin);
  my_data some_other_data = data;

  uint8_t buffer[6];
  memcpy((void*)buffer, (void*)&accelData, 6);
  Bean.setScratchData(1,buffer,6);
  Bean.sleep(1000);
}

But gives the following errors:

GetReader.ino: In function 'void loop()':
GetReader.ino:54:8: error: 'union loop()::my_data' has no member named 'accelData'
GetReader.ino:55:8: error: 'union loop()::my_data' has no member named 'accelData'
GetReader.ino:56:8: error: 'union loop()::my_data' has no member named 'accelData'
GetReader.ino:63:8: error: 'union loop()::my_data' has no member named 'shortflexposition'
GetReader.ino:64:8: error: 'union loop()::my_data' has no member named 'longflexposition'

Solution

  • First of all, it doesn't make any sense to increase the buffer size with 2 bytes if you want to add two 16 bit numbers == 4 bytes. I would suggest you do something like this:

    typedef union
    {
      struct s
      {
        AccelerationReading accelData;
        uint16_t shortflexposition;
        uint16_t longflexposition;
      };
      uint8_t raw_data [sizeof(struct s)];
    } my_data;
    
    
    // use whatever compile-time assert you have available to check for padding:
    static_assert(sizeof(my_data) == sizeof(AccelerationReading) + 2*sizeof(uint16_t), 
                  "Unwanted padding detected.");
    
    
    my_data data;
    data.accelData.xAxis = x;
    data.accelData.yAxis = y;
    data.accelData.ZAxis = z;
    data.shortflexposition = something;
    data.longflexposition  = something;
    
    my_data some_other_data = data; // equivalent of memcpy
    

    If you need to access the data byte by byte, you simply use data.raw_data[i] instead.


    If you are using an old compiler, you will have to change the code to:

    typedef union
    {
      struct s
      {
        AccelerationReading accelData;
        uint16_t shortflexposition;
        uint16_t longflexposition;
      } my_compiler_is_old;
      uint8_t raw_data [sizeof(struct s)];
    } my_data;
    
    data.my_compiler_is_old.accelData.xAxis = x;
    data.my_compiler_is_old.accelData.yAxis = y;
    ...