struct-memcpy-UDP data comms not working

I’ve read through the forums and Stackoverflow to understand how to send a struct over UDP on two Arduinos and attempted a lot of solutions. Then I used a packet sender to communicate to each one and could receive the data. But not on either Arduinos.

As I thought I had got a handle on >>Udp.write((byte *) &myStruct, sizeof(myStruct)), my bubble has burst all together :confused:

Please see my code below and educate me on whether I’ve the correct logical and semantic implementations.

Transmit code

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>


IPAddress localip(192, 100, 2, 224);      // local IP  
unsigned int localPort = 2100;            // local port to listen on

IPAddress remoteIP(192,100,2,239);
unsigned int remotePort = 59810;

int status = WL_IDLE_STATUS;

char ssid[] = "32";     //  your network SSID (name)
char pass[] = "1A6";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)


struct data sendata = {2};
struct data receive ={0};

char packetBuffer[sizeof(receive)]; //buffer to hold incoming packet
char  ReplyBuffer[sizeof(sendata)];       

WiFiUDP Udp;



void setup() {
  //Initialize serial and wait for port to open:

  WiFi.setPins(8,7,4);
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  Udp.begin(localPort);
}

void loop() {

int packetSize = Udp.parsePacket();
  
  // if there's data available, read a packet   

  Serial.print(packetSize); Serial.println(": received ");
  
  if (packetSize)  
  {    
    // read the packet into packetBufffer
    Udp.read(packetBuffer, sizeof(packetBuffer));
    memcpy(&receive, packetBuffer, sizeof(packetBuffer));
    Serial.println("Contents:");
    Serial.println(sizeof(packetBuffer));
    delay(100);
  }

   memcpy(ReplyBuffer, &sendata,sizeof(sendata));
  
   Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
   Udp.write(ReplyBuffer);
   Udp.endPacket();

   Serial.print("sent data size: "); Serial.println(sizeof(ReplyBuffer));

  delay(1000);
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

…and here is the receiving code

struct data{
  int counter;
};

struct data sendata = {5};
struct data receive ={0};

char packetBuffer[sizeof(receive)]; //buffer to hold incoming packet
char  ReplyBuffer[] = "received";       // a string to send back

WiFiUDP Udp;

void setup() {
  //Initialize serial and wait for port to open:

  WiFi.setPins(8,7,4);
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  Udp.begin(localPort);
}


char b[sizeof(&sendata)];

void loop() {
 
  
  // if there's data available, read a packet
 
  int packetSize = Udp.parsePacket();

  Serial.print(packetSize); Serial.println(": received ");
  
  if (packetSize)
  {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remoteIp = Udp.remoteIP();
    Serial.print(remoteIp);
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // read the packet into packetBufffer
    Udp.read(packetBuffer, sizeof(packetBuffer));
    memcpy(&receive, packetBuffer, sizeof(packetBuffer));
    Serial.println("Contents:");
    Serial.println(receive.counter);
    delay(100);

   /*
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write((byte *) &sendata, sizeof (sendata));
    Udp.endPacket();

    */
  }

  delay(1000);
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

PLEASE can you see what I’m doing INCORRECTLY? Thanks for your response as a I"m on the homestretch to get this functioning for my project

It seems pointless to wrap a single int in a struct. Why are you doing that?

    memcpy(&receive, packetBuffer, sizeof(packetBuffer));

Is there enough room in the destination for the number of bytes you are copying?

    Serial.println("Contents:");
    Serial.println(sizeof(packetBuffer));

Printing the size of the buffer, and claiming that the value represents the contents of the buffer is WRONG!

It is not at all clear what either piece of code is actually doing, or that differs from what you expect.

Hi All, so I’ve been attempting to get two Arduinos to communicate over WiFi using UDP (WiFi101>>WiFiUDP library).

After attempting the WiFiUDPReadWriteString example, I now want to clear some fundamental gaps in my understanding, because I’ve been unsuccessful at sending data from one Arduino to another! But hey, all I need is conceptual clarifications.

  1. can I send data from one Arduino Mega 2560 to another Arduino Mega 2560 over Wifi-UDP using the library above?

  2. how can I do these three things from the sending Arduino?

take a struct
copy it into a buffer
send the data in the buffer to another Arduino?

  1. how can I do these three things in the receiving Arduino?

take a buffer
copy the data into a data
ensure the data bytes are interpreted corrected and parsed on?

…in case you’re wondering here is my sending code.

/*
  adapted from WiFi UDP Send and Receive String
...
 created 30 December 2012
 by dlf (Metodo2 srl)

 */


#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>


IPAddress localip(192, 100, 2, 24);      // local IP  
unsigned int localPort = 8888;            // local port to listen on

IPAddress ard2(192,100,2,37);
unsigned int ard2Port = 2101;


int status = WL_IDLE_STATUS;

char ssid[] = "2";     //  your network SSID (name)
char pass[] = "1";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

struct data{
  int counter;
};

struct data sendata = {2};
struct data receive ={0};

char packetBuffer[sizeof(receive)]; //buffer to hold incoming packet
char  ReplyBuffer[] = "data";       // a string to send back

WiFiUDP Udp;


void setup() {
  //Initialize serial and wait for port to open:

  WiFi.setPins(8,7,4);
  Serial.begin(115200);
  
  Udp.begin(localPort);
}



void loop() {
   
   Udp.beginPacket(ard2, ard2Port);
   Udp.write(ReplyBuffer, sizeof(ReplyBuffer));
   Udp.endPacket();

  
  int packetSize = Udp.parsePacket(); 
  
  Serial.print(packetSize); Serial.println(": received ");
  
  if (packetSize)  
  {    
    Udp.read(packetBuffer, 255);
    memcpy(&receive, packetBuffer, sizeof(packetBuffer));
    Serial.print("Contents:");
    Serial.println(packetBuffer);
    delay(100);
        
   memcpy(ReplyBuffer, &sendata,sizeof(ReplyBuffer));
  
   Udp.beginPacket(ard2, ard2Port);
   Udp.write(ReplyBuffer, sizeof(ReplyBuffer));
   Udp.endPacket();

   Serial.print("sent data size: "); Serial.println(sizeof(ReplyBuffer));
  }

  delay(1000);
}

… and the receiving code which can receive data from a packet sender app but not from the sending Arduino is below. Everything in the code before void loop() is the same as the one in the sending loop.

void loop() {

  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remoteIp = Udp.remoteIP();
    Serial.print(remoteIp);
    Serial.print(", port ");
    Serial.println(Udp.remotePort());


    int len = Udp.read(packetBuffer, sizeof(packetBuffer));
    // if (len > 0) packetBuffer[len] = 0;
    Serial.println("Contents:");
    memcpy(&mydata, packetBuffer,sizeof(packetBuffer)); 
    Serial.print("mydata: "); Serial.println(mydata);
    Serial.print("buffer: "); Serial.println(packetBuffer);
    Udp.flush();
    

    // send a reply, to the IP address and port that sent us the packet we received
    
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(ReplyBuffer, sizeof(ReplyBuffer));
    Udp.endPacket();
  }
}

See attached screen print of the data the receiving end gets from the packet sender app.

udp receive.JPG

The struct in the code is a simplified version of the actual struct in our program.

I realize I'm confused by the programming steps to take to send a struct data (UDP over WiFi), from one Arduino to the another.

Can you give me an overview please? :confused:

@ard_automatica, I see you stripped the comments from the code. Does the license agreement allow you to do that?

@ard_automatica, do not cross-post. Threads merged.

The struct in the code is a simplified version of the actual struct in our program.

Post the real code. There is a limit to the size of a UDP packet. If you are exceeding that size, the transfer will not work.

It's unintentional...thanks for pointing it out.

PaulS:
Post the real code. There is a limit to the size of a UDP packet. If you are exceeding that size, the transfer will not work.

Everything else in the code stays the same except for the struct. See actual struct, showing data types et'al...thanks

struct data{
  
  Testcase selectTest;    // indicates test case selection
  int counter;
  int max;
  int min;
  int intervals;
  bool start;
};

So far I've learned I can cast the struct into a byte array using Udp.write((byte *) &mydata, sizeofdata)? I've also seen the memcpy(data2buffer, mydata, sizeofdata)?

All I want to do is write the data onto a Udp packet and have it transmitted. Then at the receiving end, put the data received back into the struct and access its elements as required.

So, what is the problem?

What is Testcase? You seem to expect us to have crystal balls. Well, sorry, mine are brass.

How many bytes are in the struct? How many are received?

PaulS:
So, what is the problem?

What is Testcase? You seem to expect us to have crystal balls. Well, sorry, mine are brass.

How many bytes are in the struct? How many are received?

The structure is 14 bytes in size. The problem is that the receiving end doesn't get a UDP packet at all. So I then reduced the struct to contain a single int, to send 2 bytes. Still the receiving end didn't register a Udp packet. Hence my confusion.

In debugging further I sent ASCII chars through Packet Sender and these were received, even though it's not the struct. I'm close to finding what am doing incorrectly...but can't place what it is.

In debugging further I sent ASCII chars through Packet Sender and these were received, even though it's not the struct. I'm close to finding what am doing incorrectly...but can't place what it is.

Show the code that works.

Everything else in the code stays the same except for the struct.

That's a bit hard to believe. You must be populating the struct in some way, and THAT will certainly be different.

I don't understand why your sender starts by sending "data", and then receiving a packet.

  if (packetSize) 
  {   
    Udp.read(packetBuffer, 255);

You lied. packetBuffer can NOT hold anywhere near 255 characters. AND, there are almost certainly NOT 255 bytes to read.

    memcpy(&receive, packetBuffer, sizeof(packetBuffer));

Regardless of how much data was received, copy a fixed amount of data to the address where the receive instance of the struct lives. Is THAT reasonable?

    Serial.print("Contents:");
    Serial.println(packetBuffer);

Then, even though you have not NULL terminated packetBuffer, pass the char array to a function that expects a string. That is NOT a reasonable thing to do.

Thanks a lot for all the questions, some of which led me to fill some knowledge gaps. In attempting to solve this problem and having solved it, I can relate to how perplexing
my question seemed.

Here's how I solved the problem:

  1. correctly declare and initialize structs with the datatype size specified. E.g. instead of 'int x', if I need a 32 bit int, use 'int32_t x'.

  2. Use __packed attribute to ensure compiler doesn't pad the data to make up its 'word length'. This ensures receiver doesn't get gabbage data.

  3. Initialize a buffer of type char and make it the sizeof the struct

  4. When doing a transfer of the struct into the buffer (i.e. memcpy--copy of one variable into another in-memory), the arguments of memcpy should be:

memcpy(buffer [destination], reference to data struct [source], sizeof data struct [data source size]);

  1. At the receiving end, declare same struct and a buffer of chars it's size.

  2. Copy buffer into data struct using:

memcpy(reference to data struct [destination], buffer [source], sizeof buffer [data source size]);

There are other ways to do this also.

I fouled on #4 & #5 in particular. Also you're right I was not sharing how the structs were being assessed. I had that covered.

Thanks for your help as I hope this helps other folks who may have an unclear understanding like I did.