UDP and Serial Monitor

Hello, all. I am working on a program that sends two packets via UDP (one packet of size 14 bytes and another of size 5 bytes). Right now, I am only using two devices for the two-way communication, and I am having a lot of problems. Given below is the code that I am having trouble with (this code is from the "base unit" which is an ESP32-PoE-ISO).

This code works great the first time. However, after the first call of this WiFi_UDPHandler(void) function, my Serial monitor starts spitting out garbage -- even when I comment out ALL Serial.print statements in my code. What's up with that? Also, there seems to be a significant lag between the transmit time and receive time (aka when I unplug the transmitting device, it takes the ESP32-PoE-ISO about 20 seconds to stop receiving the messages).

Any ideas?

void WiFi_UDPHandler(void)
{
  udpPacketSize = UDP.parsePacket(); // get incoming packet size
  if (udpPacketSize > 4) // if there is data to be read
  {
    remoteIP = UDP.remoteIP(); // get IP address from transmitting device
    UDP.read(udpBufferReceive, BUFFER_LEN); // save incoming data packet into udpBufferReceive

    emergencyButtonIndex = 0; // clear first
    emergencyButtonIndex = udpBufferReceive[0]; // get (deviceID)

    //Serial.print("emergencyButtonIndex = "); Serial.println(emergencyButtonIndex);

    // Separate Data
      memcpy(&emergencyButtonData[emergencyButtonIndex], udpBufferReceive, BUFFER_LEN); // copy incoming data (in udpBufferReceive) to the emergencyMessage struct

      Serial.print("Device ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].deviceID, HEX);
      Serial.print("Transmission ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].transmissionID, HEX);
      Serial.print("Transmission Type: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].transmissionType, HEX);
      Serial.print("Emergency Flag: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].emergency, HEX);
      Serial.print("Emergency Message ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].emergencyMessageID, HEX);
      Serial.print("Connectivity Check Message ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].connectivityCheckMessageID, HEX);
      Serial.print("Transmission Location ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].transmissionLocationID, HEX);
}

Here is what my serial monitor (running at 230400 baud) looks like when I comment out ALL Serial.print statements (and it never stops -- even when the transmitting device is powered off):

WiFi_UDPHandler() looks like a callback routine
if it is the problem could well be the serial.println() calls
the general advice is to avoid Serial.println() in interrupt routines, callback routines, etc

Hi, Horace. Thank you for the reply.

This function WiFi_UDPHandler() isn't an ISR (I probably need to get away from the "handler" nomenclature) but a function called in the main loop. Now, I am wondering if my problem lies in my use of the function memcpy. Do you see any issues in this?

This is how I have defined udpBufferReceive:

#define txBuffer_LEN 14 // UDP buffer length
uint8_t udpBufferReceive[rxBuffer_LEN] = {0}; // initialize UDP buffer

And this is how I have defined emergencyButtonData:

struct eButton // message to be received via UDP
    {
      public:
        uint8_t deviceID; // identification of emergency doorbell device
        uint32_t transmissionID; // transmission identification (aka type of transmission)
        uint8_t transmissionType; // type of transmission
          // 0x00 -> initialization message from E-Button
            // This unit must make changes and save the incoming information based on this type of transmission
        uint8_t emergency; // if there is an emergency or not
        uint8_t emergencyMessageID; // ID for 
        uint8_t connectivityCheckMessageID; // message ID for querying receiver for connectivity
        uint32_t transmissionLocationID; // location from whence transmission came
    };

    struct eButton emergencyButtonData[numButtons] = {0}; // declare emergencyButton of type eButton

are the UDP transmitter and receiver both ESP32 devices?
print some information on the received datagram, e.g.
printing the value of

udpPacketSize = UDP.parsePacket();

is it the same as BUFFER_LEN?

value of

emergencyButtonIndex = udpBufferReceive[0]; // get (deviceID)

if invalid you could get array index outside array

Yes, the transmitter is an XIAO-ESP32-C3 and the receiver ESP32-PoE-ISO (both running over WiFi).

The instruction line given in your post above yields a value of 14, which is exactly what I expected, and udpBufferReceive[0] poses no issue.

After some more digging, I may have found the root issue. Using Wireshark to monitor the UPD data transfer, I discovered that my transmitter is broadcasting data to the IP address 0.0.0.0 instead of the IP address of the receiver that I hard coded into the transmitter. These three lines are my instructions (for the transmitting device) for sending a UDP packet. If I have given it the IP address of the receiver (labeled here as the "radioUnitIP"), why doesn't it send the message to the correct IP? (I'm assuming there are issues on my receiver end that are not apparent yet). I'm still digging into this.

UDP.beginPacket(radioUnitIP, udpPort); // begin a packet transfer to the radio unit
UDP.write(udpBufferSend, txBuffer_LEN); // send data packet
UDP.endPacket(); // end packet transfer

NOTE: I changed the variable name from BUFFER_LEN to txBuffer_LEN because I needed to clarify between my TX and RX buffers.

what type is radioUnitIP ? an IPAddress?

in this example I use toString.c_str()

  // Multicast UDP -  IPAddress broadcast;
  IPAddress broadcast = IPAddress(224, 0, 0, 1);
  udp.beginPacket(broadcast.toString().c_str(), UDP_PORT);

Edit: just checked and

  IPAddress broadcast = IPAddress(224, 0, 0, 1);
  udp.beginPacket(broadcast, UDP_PORT);

works OK

Yes, it is type IPAddress:

IPAddress radioUnitIP(10,187,19,51); // Radaio Unit's IP Address

Ok, so I did try changing it to a string but with no luck. I still see destination address of 0.0.0.0 in WireShark too. I'm not too sure what the problem is, but my receiver connects to the internet just fine and has no errors or warnings for any of the UDP instructions. Is it possible that some packets are being corrupted or interpretting incorrectly on the receiver end?

On the receiver end, I load the incoming UDP data into a buffer and use memcpy to copy the data from the udpBufferReceive into another struct.

you must be receiving the first datagram OK
I assume it prints the correct data?
at what point does it print garbage?

in processing the datagram it looks like you are corrupting memory
e.g. memcpy() to the wrong place? overflowing an array? ???

At this point, I'm guessing an error wtih an array or memcpy is the only problem, but I cannot find it. The use of memcpy seems fine, but I will investigate more and bring back a report.

Here are the uses of my arrays and memcpy in the "Radio Unit" code:

/*
  FUNCTION: WiFi_UDPHandler
  RETURN TYPE: void
  INPUTS: none
  OUTPUT: none
  PURPOSE: To read the incoming UDP packet and respond
*/
void WiFi_UDPHandler(void)
{
  udpPacketSize = UDP.parsePacket(); // get incoming packet size
  if (udpPacketSize == rxBuffer_LEN) // only look at packets of 14 bytes
  {
    remoteIP = UDP.remoteIP(); // get IP address from transmitting device
    Serial.print("Incoming packet from "); Serial.println(remoteIP.toString().c_str());
    UDP.read(udpBufferReceive, rxBuffer_LEN); // save incoming data packet into udpBufferReceive

    emergencyButtonIndex = 0; // clear first
    emergencyButtonIndex = udpBufferReceive[0]; // get (deviceID)

    Serial.print("emergencyButtonIndex = "); Serial.println(emergencyButtonIndex);

    if (emergencyButtonIndex < numButtons) // check to make sure emergencyButtonIndex is a valid value
    {
      // Separate Data
      memcpy(&emergencyButtonData[emergencyButtonIndex], udpBufferReceive, rxBuffer_LEN); // copy incoming data (in udpBufferReceive) to the emergencyMessage struct
    }
    else
    {
      while(1)
      {
        Serial.println("Error: Index out of bounds!");
      }
    }

      Serial.print("Device ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].deviceID, HEX);
      Serial.print("Transmission ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].transmissionID, HEX);
      Serial.print("Transmission Type: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].transmissionType, HEX);
      Serial.print("Emergency Flag: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].emergency, HEX);
      Serial.print("Emergency Message ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].emergencyMessageID, HEX);
      Serial.print("Connectivity Check Message ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].connectivityCheckMessageID, HEX);
      Serial.print("Transmission Location ID: 0x"); Serial.println(emergencyButtonData[emergencyButtonIndex].transmissionLocationID, HEX);

      //Serial.print("Incoming Transmission Type: "); Serial.println(emergencyButtonData[emergencyButtonIndex].transmissionType);
      if (!emergencyButtonData[emergencyButtonIndex].transmissionID) // if the transmissionID indicates that the incoming message is for initialization of the corresponding E-Button
      {
        //Serial.println("INITIALIZATION MESSAGE");
        // Save incoming information
        if (emergencyButtonDeviceID[emergencyButtonIndex] != 0xFF) // if there is already an emergency button with this deviceID
        {
          emergencyButtonValidate[emergencyButtonIndex].deviceID_OK = 0x0; // clear to indicate ID already taken
        }
        else
        {
          //Serial.println("Device ID is OK");
          emergencyButtonValidate[emergencyButtonIndex].deviceID_OK = 0xFF; // set to indicate ID OK
          emergencyButtonDeviceID[emergencyButtonIndex] = emergencyButtonData[emergencyButtonIndex].deviceID; // save deviceID into memeroy
          numActiveButtons++; // increment total number of active emergency buttons everytime one comes online
          Serial.print("Number of Active Emergency Buttons: "); Serial.println(numActiveButtons);
        }
        if (emergencyButtonLocationID[emergencyButtonIndex] != 0xFF) // if there is already an emergency button with this location ID
        {
          emergencyButtonValidate[emergencyButtonIndex].locationID_OK = 0x0; // clear to indicate ID already taken
        }
        else
        {
          //Serial.println("Location ID is ok");
          emergencyButtonValidate[emergencyButtonIndex].locationID_OK = 0xFF; // set to indicate ID OK
          emergencyButtonLocationID[emergencyButtonIndex] = emergencyButtonData[emergencyButtonIndex].transmissionLocationID; // save locationID into memory
        }
        if (emergencyMessagesPerLocation[emergencyButtonIndex] != 0xFF) // if the emergency message is NOT unique
        {
          emergencyButtonValidate[emergencyButtonIndex].emergencyMessage_OK = 0x0; // clear to indicate message already being used
        }
        else
        {
          //Serial.println("Emergency message ID is ok");
          emergencyButtonValidate[emergencyButtonIndex].emergencyMessage_OK = 0xFF; // set to indicate message OK
          emergencyMessagesPerLocation[emergencyButtonIndex] = emergencyButtonData[emergencyButtonIndex].emergencyMessageID; // save emergency message ID into memory
        }
        if (connectivityCheckMessagesPerLocation[emergencyButtonIndex] != 0xFF) // check for unique connectivity message
        {
          emergencyButtonValidate[emergencyButtonIndex].connectivityCheckMessageID_OK = 0x00; // clear to indicate message already being used
        }
        else
        {
          //Serial.println("Connectivity Check Message ID is OK");
          emergencyButtonValidate[emergencyButtonIndex].connectivityCheckMessageID_OK = 0xFF; // set to indicate message OK
          connectivityCheckMessagesPerLocation[emergencyButtonIndex] = emergencyButtonData[emergencyButtonIndex].connectivityCheckMessageID; // save connectivityCheckMessageID into memory
        }
      }
      else
      {
        emergencyButtonValidate[emergencyButtonIndex].deviceID_OK = 0x0; // this value isn't important if the incoming message wasn't an initialization request
        emergencyButtonValidate[emergencyButtonIndex].locationID_OK = 0x0; // clear to indicate ID already taken
        emergencyButtonValidate[emergencyButtonIndex].emergencyMessage_OK = 0x0; // clear to indicate message already being used
        emergencyButtonValidate[emergencyButtonIndex].connectivityCheckMessageID_OK = 0x00; // clear to indicate message already being used
        emergencyButtonValidate[emergencyButtonIndex].connectivityCheckMessageID = connectivityCheckMessagesPerLocation[emergencyButtonIndex]; // use the saved connectivityCheckMessageID
      }
    // Send emergencyButtonValidate Packet
      memcpy(udpBufferSend, &emergencyButtonValidate[emergencyButtonIndex], txBuffer_LEN); // copy data from emergencyButtonValidate into udpBufferSend
      UDP.beginPacket(remoteIP, UDP.remotePort()); // begin a packet transfer to the emergency button that just sent a message
      UDP.write(udpBufferSend, sizeof(udpBufferSend)); // send data packet
      UDP.endPacket(); // end packet transfer
  }
}

And for the "emergency button"

/*
  FUNCTION: WiFi_InitializeButton
  RETURN TYPE: void
  INPUTS: none
  OUTPUT: none
  PURPOSE: To connect the emergency button device to the radio unit with valid IDs
*/
void WiFi_InitializeButton(void)
{
  //Serial.println("Initializing button...");
  WiFi_UdpStructInitializeData(); // initialize data

  //Serial.println("Sending information...");
  while(!buttonIDsValid) // if any of the IDs are NOT valid
  {
    // Send Data to Radio Unit
      memcpy(udpBufferSend, &emergencyButton, txBuffer_LEN); // copty data from struct to the transmit buffer

      // Serial.println(); Serial.println(); Serial.println();
      // Serial.println("EMERGENCY BUTTON STRUCT");
      // Serial.print("Device ID: 0x"); Serial.println(emergencyButton.deviceID, HEX);
      // Serial.print("Transmission ID: 0x"); Serial.println(emergencyButton.transmissionID, HEX);
      // Serial.print("Transmission Type: 0x"); Serial.println(emergencyButton.transmissionType, HEX);
      // Serial.print("Emergency Flag: 0x"); Serial.println(emergencyButton.emergency, HEX);
      // Serial.print("Emergency Message ID: 0x"); Serial.println(emergencyButton.emergencyMessageID, HEX);
      // Serial.print("Connectivity Check Message ID: 0x"); Serial.println(emergencyButton.connectivityCheckMessageID, HEX);
      // Serial.print("Transmission Location ID: 0x"); Serial.println(emergencyButton.transmissionLocationID, HEX);

      UDP.beginPacket(radioUnitIP, udpPort); // begin a packet transfer to the radio unit
      UDP.write(udpBufferSend, txBuffer_LEN); // send data packet
      UDP.endPacket(); // end packet transfer
      emergencyButton.transmissionID++; // increment transmissionID

    // Receive Data from Radio Unit
    udpPacketSize = UDP.parsePacket(); // check for incoming packet
    if (udpPacketSize == rxBuffer_LEN) // only look at packets of size rxBuffer_LEN
    {
      remoteIP = UDP.remoteIP(); // save IP address of radio unit
      Serial.print("Incoming data from "); Serial.println(remoteIP.toString().c_str());
      UDP.read(udpBufferReceive, sizeof(udpBufferReceive)); // save incoming data to buffer
    }
    memcpy(&emergencyButtonValidate, udpBufferReceive, rxBuffer_LEN); // copy udpBufferReceive into emergencyButton

    if (emergencyButtonValidate.deviceID_OK == 0x00) // if the device ID is NOT valid
    {
      //Serial.println("deviceID already taken");
      emergencyButton.deviceID++; // increment to a new ID value
      buttonIDsValid = false; // button is NOT valid
    }
    else if (!emergencyButtonValidate.locationID_OK) // if the location ID is NOT valid
    {
      //Serial.println("ERROR: Invalid location ID");
      buttonIDsValid = false; // button IDs are NOT valid
    }
    else if (!emergencyButtonValidate.emergencyMessage_OK) // if the emergency message has already been used
    {
      //Serial.println("Emergency Message ID already taken");
      emergencyButton.emergencyMessageID++; // increment emergency message ID to a new value
      buttonIDsValid = false; // button IDs are NOT valid
    }
    else if (!emergencyButtonValidate.connectivityCheckMessageID_OK) // if the connectivity message has already been used
    {
      //Serial.println("Connectivity Check Message ID already taken");
      emergencyButton.connectivityCheckMessageID++; // ID to a new value
      buttonIDsValid = false; // button IDs are NOT valid
    }
    else
    {
      Serial.println("Successfully connected to radio unit and initialized");
      buttonIDsValid = true; // all IDs have been verified
      savedEmergencyMessageID = emergencyButton.emergencyMessageID; // save emergency message ID into memory
    }
  }
}

/*
  FUNCTION: WiFi_UDPHandler
  RETURN TYPE: void
  INPUTS: emergencyFlag (if there is an emergency), emergencyCallButtonNum (emergency CallButton ID)
  OUTPUT: none
  PURPOSE: To format and send the emergency message via UDP and listen for the response
*/
void WiFi_UDPHandler(bool emergencyFlag, uint8_t emergencyCallButtonNum)
{
  emergencyButton.transmissionType = 0xFF; // do NOT try to re-initialize
  if (emergencyButton.transmissionID >= 0xFFFFFFFF) // if the transmission ID has reached it max limit
  {
    emergencyButton.transmissionID = 0; // reset to 0
  }
  if (emergencyFlag) // if there is an emergency
  {
    emergencyButton.emergency = 0xFF; // raise flag for emergency
    emergencyButton.emergencyMessageID = savedEmergencyMessageID; // pull from memory to send emergency ID message
  }
  else
  {
    emergencyButton.emergency = 0x00; // lower flag for NO emergency
    emergencyButton.emergencyMessageID = 0; // clear flag for NO emergency
  }

  memcpy(udpBufferSend, &emergencyButton, txBuffer_LEN); // copy packet into udpBuffer

  Serial.print("Device ID: 0x"); Serial.println(emergencyButton.deviceID, HEX);
  Serial.print("Transmission ID: 0x"); Serial.println(emergencyButton.transmissionID, HEX);
  Serial.print("Transmission Type: 0x"); Serial.println(emergencyButton.transmissionType, HEX);
  Serial.print("Emergency Flag: 0x"); Serial.println(emergencyButton.emergency, HEX);
  Serial.print("Emergency Message ID: 0x"); Serial.println(emergencyButton.emergencyMessageID, HEX);
  Serial.print("Connectivity Check Message ID: 0x"); Serial.println(emergencyButton.connectivityCheckMessageID, HEX);
  Serial.print("Transmission Location ID: 0x"); Serial.println(emergencyButton.transmissionLocationID, HEX);

  UDP.beginPacket(radioUnitIP, udpPort); // load packet
  UDP.write(udpBufferSend, sizeof(udpBufferSend)); // write packet
  UDP.endPacket(); // end packet transmission

  udpPacketSize = UDP.parsePacket(); // get incoming packet size
  if (udpPacketSize) // if there is data to be read
  {
    IPAddress remoteIp = UDP.remoteIP(); // get IP address from transmitting device
    UDP.read(udpBufferReceive, sizeof(udpBufferReceive)); // save incoming data packet into udpBufferReceive
    memcpy(&emergencyButtonValidate, udpBufferReceive, sizeof(udpBufferReceive)); // copy receive buffer into emergencyButtonValidate

    if (emergencyButtonValidate.connectivityCheckMessageID == emergencyButton.connectivityCheckMessageID) // if received message is the connectivity confirmation number
    {
      if (!connectedToReceiver) // if the status changed from not connected to receiver to connected
      {
        updateLEDs = true; // update LEDs only on a change in status
      }
      disconnectedCounter = 0; // NO disconnection
      connectedToReceiver = true; // established connection to receiver
      emergencyButton.transmissionID++; // increment transmissionID
      heartBeat++; // increment counter to indicate connection
    }
  }
  else
  {
    disconnectedCounter++; // increment counter
  }
  if (disconnectedCounter >= 10) // when the emergency button hasn't heard from the Radio Unit in 10 cycles
  {
    disconnectedCounter = 0; // reset
    if (connectedToReceiver) // if the device was previously connected to the receiver
    {
      updateLEDs = true; // update the LEDs
    }
    connectedToReceiver = false; // lost connection to receiver
  }
}

adapted one of my UDP client/server programs

server receiving datagrams into an array

// ESP32 WiFi AP UDP server - receive UDP datagrams from client neter in array

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com
*********/

// Load Wi-Fi library
#include <WiFi.h>
#include <AsyncUDP.h>

// Replace with your network credentials
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

#define UDP_PORT 4210
//create UDP instance
WiFiUDP udp;

// UDP Datagram
struct UDPDatagram {
  uint8_t deviceID;          // identification of emergency doorbell device
  uint32_t transmissionID;   // transmission identification (aka type of transmission)
  uint8_t transmissionType;  // type of transmission
} udpDatagram;

struct UDPDatagram datagrams[10];

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;
  delay(1000);
  Serial.println();
  Serial.println("ESP32 WiFi AP UDP server - receive UDP datagrams from client");
  Serial.print("Setting AP (Access Point)… ");
  // Remove the password parameter, if you want the AP (Access Point) to be open
  Serial.println(WiFi.softAP(ssid, password) ? "Ready" : "Failed!");
  //WiFi.softAP(ssid, password);
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);
  udp.begin(UDP_PORT);  // Begin listening to UDP port
  Serial.print("Listening on UDP port ");
  Serial.println(UDP_PORT);
}

// receive datagram and check and display contents
void loop() {
  static unsigned long int seq = 0;  // to force seq error check set this none zero
  if (udp.parsePacket()) {           // Receive packet and display it
    int len = udp.read((unsigned char*)&udpDatagram, sizeof(udpDatagram));
    Serial.print("UDP datagram received length ");
    Serial.print(len);
    Serial.print(" From ");
    IPAddress remote = udp.remoteIP();
    Serial.print(remote);
    int index;
    Serial.printf("\narray index %d ",index=udpDatagram.deviceID);
    memcpy(&datagrams[index], &udpDatagram, sizeof(udpDatagram));
    Serial.print("   deviceID ");
    Serial.print((int)datagrams[index].deviceID);
    Serial.print("  transmissionID ");
    Serial.print(datagrams[index].transmissionID);
    Serial.print("  transmissionType ");
    Serial.print(datagrams[index].transmissionType);
    Serial.println();
    // send reply
    udp.beginPacket(udp.remoteIP(), UDP_PORT);
    udp.write((const uint8_t*)"received OK", 12);
    udp.endPacket();
    Serial.println("Transmitted UDP OK");
  }
}

client transmitting datagrams

// Arduino TCP server listen for connection and display messages

//  from https://github.com/evothings/evothings-examples/blob/master/examples/arduino-led-onoff-tcp/arduinowifi/arduinowifi/arduinowifi.ino

// ESP32 WiFi UDP client - send UDP datagrams to server

#include <WiFi.h>
#include <AsyncUDP.h>

// Remove this line once you've entered WiFi SSID and password below.
//#error "WiFi SSID and password required!"

// network SSID (network name). and network password.
char ssid[] = "ESP32-Access-Point";
char pass[] = "123456789";

// network key Index number (needed only for WEP).
int keyIndex = 0;

// UDP information
#define UDP_PORT 4210
WiFiUDP udp;

// UDP Datagram
struct UDPDatagram {
  uint8_t deviceID;          // identification of emergency doorbell device
  uint32_t transmissionID;   // transmission identification (aka type of transmission)
  uint8_t transmissionType;  // type of transmission
} udpDatagram ={0, 34567, 8};

void setup() {
  Serial.begin(115200);
  // Wait for serial port to connect. Needed for Leonardo only
  while (!Serial)
    ;
  delay(1000);
  Serial.println();
  Serial.println("ESP32 WiFi UDP client - send UDP datagrams to server");
  WiFi.mode(WIFI_STA);  // Connect to Wifi network.
  WiFi.begin(ssid, pass);
  Serial.println("");
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("\nGateway IP address: ");
  Serial.println(WiFi.gatewayIP());
  Serial.print("local IP address: ");
  Serial.println(WiFi.localIP());
  // Begin udp port
  udp.begin(UDP_PORT);
  Serial.print("Opening udp port ");
  Serial.println(UDP_PORT);
}

void loop() {
  // generate crc check
  Serial.print("\ntransitting Datagram data ");
  Serial.print(" deviceID ");
    Serial.print((int)udpDatagram.deviceID++);
    if(udpDatagram.deviceID >= 10) udpDatagram.deviceID=0;  // reset for array size
    Serial.print(" transmissionID ");
    Serial.print(udpDatagram.transmissionID++);
    Serial.print(" transmissionType ");
    Serial.print(udpDatagram.transmissionType++);
    Serial.println();
  // Multicast UDP -  IPAddress broadcast;
  IPAddress broadcast = IPAddress(224, 0, 0, 1);
  //udp.beginPacket(broadcast, UDP_PORT);
  // Send Packet to UDP server running on Gateway
  udp.beginPacket(WiFi.gatewayIP(), UDP_PORT);
  int len = udp.write((const uint8_t *)&udpDatagram, sizeof(udpDatagram));
  udp.endPacket();
  Serial.print("UDP datagram transmitted length ");
  Serial.print(len);

  // check for replay from server
  if (udp.parsePacket()) {  // Receive packet and display it
    char data[200] = { 0 };
    int len = udp.read((unsigned char *)&data, sizeof(data));
    Serial.print("\nUDP datagram received length ");
    Serial.print(len);
    Serial.print(" From ");
    IPAddress remote = udp.remoteIP();
    Serial.print(remote);
    Serial.print(" data  ");
    Serial.print(data);
  }
  delay(5000);
}

server serial monitor output

ESP32 WiFi AP UDP server - receive UDP datagrams from client
Setting AP (Access Point)… Ready
AP IP address: 192.168.4.1
Listening on UDP port 4210
UDP datagram received length 12 From 192.168.4.2
array index 1    deviceID 1  transmissionID 34568  transmissionType 9
Transmitted UDP OK
UDP datagram received length 12 From 192.168.4.2
array index 2    deviceID 2  transmissionID 34569  transmissionType 10
Transmitted UDP OK
UDP datagram received length 12 From 192.168.4.2
array index 3    deviceID 3  transmissionID 34570  transmissionType 11
Transmitted UDP OK
UDP datagram received length 12 From 192.168.4.2
array index 4    deviceID 4  transmissionID 34571  transmissionType 12
Transmitted UDP OK
UDP datagram received length 12 From 192.168.4.2
array index 5    deviceID 5  transmissionID 34572  transmissionType 13
Transmitted UDP OK

client serial monitor output

ESP32 WiFi UDP client - send UDP datagrams to server

.
Gateway IP address: 192.168.4.1
local IP address: 192.168.4.2
Opening udp port 4210

transitting Datagram data  deviceID 0 transmissionID 34567 transmissionType 8
UDP datagram transmitted length 12
transitting Datagram data  deviceID 1 transmissionID 34568 transmissionType 9
UDP datagram transmitted length 12
UDP datagram received length 12 From 192.168.4.1 data  received OK
transitting Datagram data  deviceID 2 transmissionID 34569 transmissionType 10
UDP datagram transmitted length 12
UDP datagram received length 12 From 192.168.4.1 data  received OK
transitting Datagram data  deviceID 3 transmissionID 34570 transmissionType 11
UDP datagram transmitted length 12
UDP datagram received length 12 From 192.168.4.1 data  received OK
transitting Datagram data  deviceID 4 transmissionID 34571 transmissionType 12
UDP datagram transmitted length 12
UDP datagram received length 12 From 192.168.4.1 data  received OK
transitting Datagram data  deviceID 5 transmissionID 34572 transmissionType 13
UDP datagram transmitted length 12

Ok, I figured out both problems: the one with communication and the one with the serial monitor spitting out garbage.

To fix the communication issues, I implemented a polling method so that now my "emergency button" device stays in a while loop until it receives a UDP message from the "Radio Unit" device. Before this change, I had my emergency button device send a UDP message and then immediately check for a response. By the time my Radio Unit would have captured this message and prepared another to send, my button was already sending another message. Now, however, I got that fixed with a simple while loop.

I found the source of my serial monitor garbage: an if statement, evaluating an element in a array of structs:

if (emergencyButtonData[emergencyButtonIndex].emergency == 0xFF)

Not sure why this is happening, and I really need to evaluate this variable. However, it bogs down the ESP32 like crazy, creating a 3 second delay every time this instruction is executed. Apparently, I can do bit-math operations on it just fine, so maybe I can find a way to convert this variable into a different variable and use that in an if statement. An unfortunate workout but if it works, it works.

Updated UDP Function:

/*
  FUNCTION: WiFi_InitializeButton
  RETURN TYPE: void
  INPUTS: none
  OUTPUT: none
  PURPOSE: To connect the emergency button device to the radio unit with valid IDs
*/
void WiFi_InitializeButton(void)
{
  WiFi_UdpStructInitializeData(); // initialize data

  while(!buttonIDsValid) // if any of the IDs are NOT valid
  {
    // Send Data to Radio Unit
      memcpy(udpBufferSend, &emergencyButton, txBuffer_LEN); // copty data from struct to the transmit buffer

      UDP.beginPacket(radioUnitIP, udpPort); // begin a packet transfer to the radio unit
      messageSent = UDP.write(udpBufferSend, txBuffer_LEN); // send data packet
      UDP.endPacket(); // end packet transfer
      emergencyButton.transmissionID++; // increment transmissionID
      for (int i = 0; i < txBuffer_LEN; i++)
      {
        udpBufferSend[i] = 0; // clear buffer
      }

    // Receive Data from Radio Unit
    while (messageSent)
    {
      udpPacketSize = UDP.parsePacket(); // check for incoming packet
      if (udpPacketSize == rxBuffer_LEN) // only look at packets of size rxBuffer_LEN
      {
        remoteIP = UDP.remoteIP(); // save IP address of radio unit
        UDP.read(udpBufferReceive, rxBuffer_LEN); // save incoming data to buffer

        memcpy(&emergencyButtonValidate, udpBufferReceive, rxBuffer_LEN); // copy udpBufferReceive into emergencyButton

        if (emergencyButtonValidate.deviceID_OK == 0x00) // if the device ID is NOT valid
        {
          emergencyButton.deviceID++; // increment to a new ID value
          buttonIDsValid = false; // button is NOT valid
        }
        else if (!emergencyButtonValidate.locationID_OK) // if the location ID is NOT valid
        {
          buttonIDsValid = false; // button IDs are NOT valid
        }
        else if (!emergencyButtonValidate.emergencyMessage_OK) // if the emergency message has already been used
        {
          emergencyButton.emergencyMessageID++; // increment emergency message ID to a new value
          buttonIDsValid = false; // button IDs are NOT valid
        }
        else if (!emergencyButtonValidate.connectivityCheckMessageID_OK) // if the connectivity message has already been used
        {
          emergencyButton.connectivityCheckMessageID++; // ID to a new value
          buttonIDsValid = false; // button IDs are NOT valid
        }
        else
        {
          buttonIDsValid = true; // all IDs have been verified
          savedEmergencyMessageID = emergencyButton.emergencyMessageID; // save emergency message ID into memory
        }
        udpPacketSize = 0; // reset
        messageSent = false; // lower flag to allow for sending of the message again
      }
    }
  }
}

that looks like you are assigning 0xFF to the array element
should it be test for equality?

if (emergencyButtonData[emergencyButtonIndex].emergency == 0xFF)`

Yes, and in my code it is that way, I just copied it down into this forum incorrectly. Sorry for the confusion.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.