Data exchange with 2 Arduino Uno via UDP

Hello erverybody,

I want to exchange Data via write and read UDP Datagrams.

From one to another is working nice, but I cannot get the return telegram.
My program is based on Ethernet/UDPSendReceiveString sample in the IDE (see Code below)

The Arduino on this side of the program works.
The other has first the code for writing, second the code for reading, and reads - nothing.

My basic question is: For the sample below, how has the code to look alike for the other side, which is a Arduino aswell, because the PC sample in the comments seem to be rubbish to me.

I searched the web and did not find a complete sample for 2 Arduinos.

Many thanx in advance

Rudolf

  /*
   UDPSendReceiveString:
   This sketch receives UDP message strings, prints them to the serial port
   and sends an "acknowledge" string back to the sender
  
   A Processing sketch is included at the end of file that can be used to send
   and received messages for testing with a computer.
  
   created 21 Aug 2010
   by Michael Margolis
  
   This code is in the public domain.
   */
  
  
  #include <Ethernet.h>
  #include <EthernetUdp.h>
  
  // Enter a MAC address and IP address for your controller below.
  // The IP address will be dependent on your local network:
  byte mac[] = {
    0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
  };
  IPAddress ip(192, 168, 1, 177);
  
  unsigned int localPort = 8888;      // local port to listen on
  
  // buffers for receiving and sending data
  char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,
  char ReplyBuffer[] = "acknowledged";        // a string to send back
  
  // An EthernetUDP instance to let us send and receive packets over UDP
  EthernetUDP Udp;
  
  void setup() {
    // You can use Ethernet.init(pin) to configure the CS pin
    //Ethernet.init(10);  // Most Arduino shields
    //Ethernet.init(5);   // MKR ETH shield
    //Ethernet.init(0);   // Teensy 2.0
    //Ethernet.init(20);  // Teensy++ 2.0
    //Ethernet.init(15);  // ESP8266 with Adafruit Featherwing Ethernet
    //Ethernet.init(33);  // ESP32 with Adafruit Featherwing Ethernet
  
    // start the Ethernet
    Ethernet.begin(mac, ip);
  
    // Open serial communications and wait for port to open:
    Serial.begin(9600);
    while (!Serial) {
      ; // wait for serial port to connect. Needed for native USB port only
    }
  
    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
      while (true) {
        delay(1); // do nothing, no point running without Ethernet hardware
      }
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
  
    // start UDP
    Udp.begin(localPort);
  }
  
  void loop() {
    // if there's data available, read a packet
    int packetSize = Udp.parsePacket();
    if (packetSize) {
      Serial.print("Received packet of size ");
      Serial.println(packetSize);
      Serial.print("From ");
      IPAddress remote = Udp.remoteIP();
      for (int i=0; i < 4; i++) {
        Serial.print(remote[i], DEC);
        if (i < 3) {
          Serial.print(".");
        }
      }
      Serial.print(", port ");
      Serial.println(Udp.remotePort());
  
      // read the packet into packetBufffer
      Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
      Serial.println("Contents:");
      Serial.println(packetBuffer);
  
      // 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);
      Udp.endPacket();
    }
    delay(10);
  }
  
  
  /*
    Processing sketch to run with this example
   =====================================================
  
   // Processing UDP example to send and receive string data from Arduino
   // press any key to send the "Hello Arduino" message
  
  
   import hypermedia.net.*;
  
   UDP udp;  // define the UDP object
  
  
   void setup() {
   udp = new UDP( this, 6000 );  // create a new datagram connection on port 6000
   //udp.log( true ); 		// <-- printout the connection activity
   udp.listen( true );           // and wait for incoming message
   }
  
   void draw()
   {
   }
  
   void keyPressed() {
   String ip       = "192.168.1.177";	// the remote IP address
   int port        = 8888;		// the destination port
  
   udp.send("Hello World", ip, port );   // the message to send
  
   }
  
   void receive( byte[] data ) { 			// <-- default handler
   //void receive( byte[] data, String ip, int port ) {	// <-- extended handler

 for(int i=0; i < data.length; i++)
 print(char(data[i]));
 println();
 }
 */


it's a Processing sketch (java).

basically the sketch from the example respond with "acknowledged" to an incoming UDP packet.

so you can grab that and just prime the ping-pong game by adding in the setup() of one of the two Arduinos an initial message to the other Arduino. Of course you need to agree on the port and IP of the second Arduino, say it's 192.168.1.178 and both arduino listen to port 888, then you just add that code to the setup() of the arduino with IP 192.168.1.177

    IPAddress otherIP(192, 168, 1, 178);
    Udp.beginPacket(otherIP, 8888);
    Udp.write("Let's start");
    Udp.endPacket();

you might want to add a delay(1000); before responding so that your ping pong does not go too fast

Let me precise the problem:

On Board "A" is running this:

WiFiUDP Udp;

setup()   {
  Udp.begin(cport);
}

loop()   {
  packetSize = Udp.parsePacket();
  if (packetSize) {
    // read the packet into packetBuffer
    int len = Udp.read(transbuf, _buffer_size-1);
    if (len > 0) {
      transbuf[len] = 0;
    }
    // work with the data
    ...
    // send a reply, to the IP address and port that sent us the packet we received
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(replyBuf);
    Udp.endPacket();
  }
}

Board "B" is running this:

WiFiUDP Udp;

setup()   {
  Udp.begin(SceneServerPort)
}

loop()   {
  // Data send (every 2 seconds)
  Udp.beginPacket(SceneServer, SceneServerPort);
  Udp.write(transbuf);
  Udp.endPacket();
  delay(0);                            // tried 0/500/1000ms
  // receive answer
  packetSize = Udp.parsePacket();
  if (packetSize) {
    int len = Udp.read(recBuf, _buffer_size-1);
    if (len > 0) {
      recBuf[len] = 0;
    }
  }
}

Board B sends (every 2 seconds), and receives nothing.
Board A receives (every 2 seconds) and then sends.

If relevant anyhow, on "B" parallel to that a ethernet webserver is running at same time.
The port number is on both sides and both directions 9620.

Program "A" seems quite bugless to me. How should the UDP commands on "B" be placed, so that the comunication is working in both directions, and "B" is the perfect mirror to "A" ?

In this code

you send a message and right after (whatever the delay) check if you have something back and if not you just loop and send transbuf again . if it's important that you await the answer/ack (may be until a timeout) of the command, then the code should mimic this in a non blocking way if you have the web server running at the same time. ➜ a small state machine that does not send transbuf again until you got the answer or timeout for example would do.

Thank you J-M-L,

could have been a pretty good idea. I changed the code of "B" to sending once every 2 seconds on begin of real loop, and receiving every loop at the end.
Its a pitty, that never a telegram was comeing back...

Honestly, has nobody here an idea how a complete communication between A and B with send and receive has to look alike ??

Found nothing about this matter elswhere in the web...

I can’t test for the moment (away from my toys) but it should not be that complicated…

Surely UDP.Begin just defines the port to listen on for incoming messages. The port used to send messages is not defined in the code and is usually the next free port on the transmission side. Using UDP.remotePort() to send to is therefore unlikely to be same port number as that used to listen on.

On Board "A" you are listening on cport and replying to UDP.remotePort(), Board "B" is however sending to port SceneServerPort and listening on SceneServerPort.

Have you tried sending to cport on board "A"?

Have you tried using Wireshark to see what each board appears to be sending and to where? Obviously you may need to replace each board with a PC running Wireshark to inspect the packets sent when running the tests. But it might allow to confirm what port Board "A" is sending to (you may need to use Board "B" to send messages to Board"A" but have Board "A" repsond to the PC ip address to allow Wireshark to inspect the packets.

Finally got it. I made the mistake to send an empty telegram because I assigned the text before making the space with malloc() and writing the area with ´0´ :flushed: :woozy_face:
An empty telegram leads to 0 Bytes received, shame on me...

Anyway many thanks to all for helping.

@countrypaul:
I used same port (9620) on both devices and it worked, although I think its quite common to take next (9621) as you stated. Wireshark would have been the next logical step to me. Thanx.

@J-M-L:
I use in real program "Agenda.h" (although IDE states it as maybe not working with megaAVR4809) and start sending on "B" every 2s, receiving every loop since after.
On "A" every loop I receive; and if, I send the answer (so aswell every 2s).
It pointed out, that a gap from 100-150ms in "A" program is enough to get the answer.
Thank you.

Here I post the full example (with delays for test, not agenda) for SEND and RECEIVE a character array with 2 Arduinos, A with Ethernet shield W5500 and B via WiFiNina 4809:

LED_BUILTIN on each device is toggled IF a telegram was RECEIVED.

Code "A"

/*****************************************************
  Hardware:     Arduino Uno Wifi Rev.2 WiFiNina
  Code A
  Circuit:
  Ethernet shield attached to pins 10, 11, 12, 13
  with WD5500 Chip
*/

#include <Arduino.h>    // Obligat
#include <megaAVR.h>    // Um für 4809 (Uno Wifi Rev.2) zu kompileren
#include <SPI.h>
#include <Ethernet.h>   // Requires Library 2.0 or higher for W5500 chip
#include <EthernetUdp.h>// Library für UDP-Datagramm

// Ethernet
const IPAddress ip(192, 168, 178, 189);
const IPAddress dns(192, 168, 178, 1);
const IPAddress gateway(192, 168, 178, 1);
const IPAddress subnet(255, 255, 255, 0);
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { };

// Addresse vom Esszimmer Server via WiFi
const char SceneServer[] = "192.168.178.188";      // ip address
const int SceneServerPort = 9620;                  // port number
char transbuf[64];
char recBuf[64];

// EthernetUDP to send and receive messages.
EthernetUDP Udp;

// ********************************************************
// *** Class SceneClient Definition

// Class SceneClient
void setup(  )
{

  Serial.begin(57600);
  
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip, gateway, subnet);

  // if you get a connection, report back via serial:
  Serial.print(F("Local Client is at "));
  Serial.println(Ethernet.localIP());
  Serial.print(F("Scene Server is at "));
  Serial.print(SceneServer);
  Serial.print(F(":"));
  Serial.println(SceneServerPort);

  if( Udp.begin(SceneServerPort) ) {
    Serial.println(F("UDP port to send opened.\n"));
  }
  else {
    // If you didn't get a connection to the server:
    Serial.println(F("Connection to SceneServer failed.\n"));
  }
}


void loop()
{
  // variables
  char varbuf[16];

  // Telegramm basteln
  strcpy( transbuf, "Ich komme von A" );
  
  // Bind the packet
  Udp.beginPacket(SceneServer, SceneServerPort);
  // First of all write the bytes
  Udp.write(transbuf);
  // Erfolgreiche Sendung
  Udp.endPacket();

  delay(250);

  // Antwort empfangen
  int packetSize = Udp.parsePacket();
  // Paket da ? Lesen
  if (packetSize) {
    // read the packet into packetBuffer
    int len = Udp.read(recBuf, 64-1);
      if (len >= 0) {
      recBuf[len] = 0;
    }
    Serial.print( "Recv:<" );
    Serial.print( recBuf );
    Serial.println( ">" );
    // Paket anzeigen
    digitalWrite( LED_BUILTIN, !digitalRead(LED_BUILTIN) );

  }
  else  {
    // Sendung fürn Arsch
    Serial.println( "XXXX:<>" );
  }

  delay(1750);
}

Here is Code "B"

/*****************************************************
 Code B
 Hardware:     Arduino Uno Wifi Rev.2 WiFiNina
                
 *****************************************************
 */

#define NINA_FW "1.4.5"

#include <SPI.h>
#include <WiFiNINA.h>
#include <WiFiUdp.h>
#include "Arduino_Secrets.h" 

// Scene server config
#define SceneServerPort 9620
// Size of buffer for transfer in both directions, even number (word)
#define SceneServerBuffer 64

///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;        // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;      // the Wifi radio's status

int packetSize;                   // Empfangende Pakete

byte mac[] = { };
IPAddress ip(192, 168, 178, 188);
IPAddress dns(192, 168, 178, 1);
IPAddress gateway(192, 168, 178, 1);
IPAddress subnet(255, 255, 255, 0);

// External WiFi class (from WiFiNINA.h wrapper)
// WiFiClass WiFi;
WiFiUDP Udp;

char transbuf[64];
char replyBuf[64];


void setup( )
{  
  Serial.begin(57600);

  strcpy( replyBuf, "Von B zurückgesendet" );
  
  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println(F("Communication with WiFi module failed!"));
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < NINA_FW) {
    Serial.println(F("Please upgrade the firmware"));
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print(F("Attempting to connect to WPA SSID: "));
    Serial.println(ssid);
    // Fix the IP address
    WiFi.config(ip, dns, gateway, subnet);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);

    // wait 1 seconds for connection:
    delay(1000);
  }

  // Listen to UDP port
  if( Udp.begin(SceneServerPort) )  {
    // you're connected now, so print out the data:
    Serial.println(F("You're connected to the network, Listener is up.\n"));
  }
  printCurrentNet();
  printWifiData();
  
  // Print server info
  Serial.print(F("Scenelistener (UDP) is at "));
  Serial.print(WiFi.localIP());
  Serial.print(F(":"));
  Serial.print(SceneServerPort);
  Serial.print(F(" - Size "));
  Serial.print(64);
  Serial.println(F(" bytes\n"));
}


// Print Transfer Buffer Contend
void print( )
{
  Serial.print(F("Packet:"));
  Serial.print(packetSize);
  Serial.print(F("b From "));
  IPAddress remoteIp = Udp.remoteIP();
  Serial.print(remoteIp);
  Serial.print(F(":"));
  Serial.print(Udp.remotePort());
  
  Serial.print(F(" Transbuf:<"));
  for( int i = 0; i < 64; ++i )
  {
    Serial.print( transbuf[i] );
  }
  Serial.println(F(">"));
}


// Loop (main) part of SceneServer
void loop( ) {
  // variables
  packetSize = Udp.parsePacket();

  // Read Data
  if (packetSize) {
    // read the packet into packetBuffer
    int len = Udp.read(transbuf, 64-1);
    if (len > 0) {
      transbuf[len] = 0;
    }
    // Buffer Ausgeben
    print();
    // Auswerten der Daten

    // Paket anzeigen
    digitalWrite( LED_BUILTIN, !digitalRead(LED_BUILTIN) );

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


void printWifiData() {
  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print(F("IP Address: "));
  Serial.print(ip);
  Serial.print(F(":"));
  Serial.println(SceneServerPort);

  // print your MAC address:
  byte mac[6];
  WiFi.macAddress(mac);
  Serial.print(F("MAC address: "));
  printMacAddress(mac);
}


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

  // print the MAC address of the router you're attached to:
  byte bssid[6];
  WiFi.BSSID(bssid);
  Serial.print(F("BSSID: "));
  printMacAddress(bssid);

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

  // print the encryption type:
  byte encryption = WiFi.encryptionType();
  Serial.print(F("Encryption Type:"));
  Serial.println(encryption, HEX);
  Serial.println();
}


void printMacAddress(byte mac[]) {
  for (int i = 5; i >= 0; i--) {
    if (mac[i] < 16) {
      Serial.print(F("0"));
    }
    Serial.print(mac[i], HEX);
    if (i > 0) {
      Serial.print(F(":"));
    }
  }
  Serial.println();
}