Here is how to send struct data between ESP8266 and Arduino via nRF24L01

Hi.

I'm new to the forum. I have been lurking here for a few weeks, and I find it a great source of knowledge. Many thanks to all who contributed to it over the years!

I decided my first post will not be a question, but rather a solution to a problem that doesn't have a good answer here yet (or at least I was not able to find it).
When transmitting data between ATMega328P device and ESP8266 via NRF24L01+ module, the packet length is only 32 characters maximum. So instead of using and parsing regular text, it makes more sense to create your own data structure, and use that for communication. Saves lots of bytes. However, the problem is that you can't directly send a data structure (which is essentially a block of RAM) between two different CPUs. The data will most likely not match the memory allocation of the machine on the other side.

In order to do that correctly, you need to encode, send, and then decode your structure. Since I wasn't able to find good examples of that anywhere in these forums, I decided to share my code. I'm only including the relevant parts of the code - you need to write all the rest to make it work, but that should be straightforward for anybody who ever used NRF24L01+ modules to send and receive character strings.

Here is the code for transmitting device:

struct packet 
{ 
   uint8_t device_id;
   uint16_t packet_id;
   uint8_t sensor_id;
   uint16_t value;
}; 
struct packet Packet;


size_t EncodePacket(unsigned char *dst, const struct packet *object)
{
    size_t i = 0;

    memcpy(&dst[i], &object->device_id, sizeof object->device_id);
    i += sizeof object->device_id;

    memcpy(&dst[i], &object->packet_id, sizeof object->packet_id);
    i += sizeof object->packet_id;

    memcpy(&dst[i], &object->sensor_id, sizeof object->sensor_id);
    i += sizeof object->sensor_id;

    memcpy(&dst[i], &object->value, sizeof object->value);
    i += sizeof object->value;

    return i;
}



// You might now also shorten the maximum payload size to make packets shorter (do this on all devices)
   radio.setPayloadSize(6);


// If you want to even further shorten your packets, you can use 3-bytes addresses, instead of default 5:
  radio.setAddressWidth(3);
  uint8_t address[4] = "100";


void loop() {

    Packet.device_id = 2;
    Packet.packet_id = 250;
    Packet.sensor_id = 5;
    Packet.value = 689;

    char data_to_send[6];
    EncodePacket(data_to_send, &Packet);
    radio.write(&data_to_send, sizeof(data_to_send));

}

Here is the code for receiving device:

struct packet 
{ 
   uint8_t device_id;
   uint16_t packet_id;
   uint8_t sensor_id;
   uint16_t value;
}; 
struct packet Packet;


int DecodePacket(struct packet *object, char *ptr)
{

    memcpy(&object->device_id, ptr, sizeof object->device_id);
    ptr += sizeof object->device_id;

    memcpy(&object->packet_id, ptr, sizeof object->packet_id);
    ptr += sizeof object->packet_id;

    memcpy(&object->sensor_id, ptr, sizeof object->sensor_id);
    ptr += sizeof object->sensor_id;

    memcpy(&object->value, ptr, sizeof object->value);

    return 1;
}


// You might now also shorten the maximum payload size to make packets shorter (do this on all devices)
   radio.setPayloadSize(6);


// If you want to even further shorten your packets, you can use 3-bytes addresses, instead of default 5:
  radio.setAddressWidth(3);
  uint8_t address[4] = "100";


void loop() {

     char data_received[6];
     radio.read(&data_received, sizeof(data_received));
     DecodePacket(&Packet, data_received);

}

Hope this will be helpful to somebody. If you think there are any errors, or you have an idea on how this can be improved, please let me know.

Cheers.

cadence22:
If you think there are any errors,

You don't care about struct member alignment / packing (which is different on the platforms),

cadence22:
or you have an idea on how this can be improved, please let me know.

The reception and 'decoding' involves an extra copy which is absolutely superfluous,
just read the packet directly into the Packet buffer.

void loop() {
  if (radio.available()) {
     radio.read(&Packet, sizeof(Packet));
  }
}