Why do I have to send UDP packet twice for Udp.read() to get updated value?

I’m working on a project in which I turn a laser on using a UDP packet sent from a PC. The following code works, but with 1 caveat.

I have to send the command twice to get the state to change. For example:

  1. Send the 1st initial ON command - Laser turns on as expected
  2. Send a OFF command - it still thinks I sent the ON command
  3. Send a 2nd OFF command - turns the laser off as expected
  4. Send a 2nd ON command - Still thinks I sent the OFF command
  5. Send a 3rd ON command- Turns the laser ON as expected.

TL;DR: Why do I have to send UDP packet twice for Udp.read() to get updated value?

This code is basically the UDPSendRecieveString example with minor adjustments.

/*
  UDPSendReceive.pde:
 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 <SPI.h>         // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h>         // UDP library from: bjoern@cs.stanford.edu 12/30/2008


// 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, 200);

unsigned int localPort = 8888;      // local port to listen on
bool laserStatus = true;
bool command = true;
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

void setup() {
  // start the Ethernet and UDP:
  Ethernet.begin(mac, ip);
  Udp.begin(localPort);

  Serial.begin(9600);
}

void loop() {
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  Serial.print("Current Packet Size: ");
  Serial.println(packetSize);
  if (packetSize>0)
  {

    // read the packet into packetBufffer
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    Serial.println(packetBuffer);
    String commandString(packetBuffer);
    if (commandString == "ON")
    Serial.println("turn the laser on");
    else
    Serial.println("turn the laser off");
    
        // send a reply, to the IP address and port that sent us the packet we received
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write("Laser Status: ");
    Udp.write(packetBuffer);
    Udp.endPacket();
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    Serial.println("clearing the packet buffer");
    // clear packetBuffer
    for(int i=0;i<UDP_TX_PACKET_MAX_SIZE;i++) packetBuffer[i] = 0;
    Udp.flush();
  }
  delay(1000);
}

Serial output - items marked with are added after the fact and not part of the serialized output.

Current Packet Size: 0
Current Packet Size: 0
Current Packet Size: 2 - < note: 1. Send the 1st initial ON command >
ON    		<note: LASER TURNS ON AS EXPECTED>
turn the laser on
clearing the packet buffer
Current Packet Size: 0
Current Packet Size: 0
Current Packet Size: 0
Current Packet Size: 0
Current Packet Size: 2 - < note: 2. Send the OFF Command >
ON 		<note: UDP thinks we sent the ON command, although we sent the OFF Command>
turn the laser on
clearing the packet buffer
Current Packet Size: 0
Current Packet Size: 3 - < note: 3. Send OFF a second time >
OFF 		<note:  It works as expected the second time>
turn the laser off
clearing the packet buffer
Current Packet Size: 0
Current Packet Size: 0
Current Packet Size: 0
Current Packet Size: 0
Current Packet Size: 3 - < note: 4. Send the ON command >
OFF   		<note: UDP thinks we sent the OFF command, although we sent the ON Command>
turn the laser off
clearing the packet buffer
Current Packet Size: 0
Current Packet Size: 2 - < note: 5.  Send ON command a 2nd time >
ON		<note:  It works as expected the second time>
turn the laser on
clearing the packet buffer
Current Packet Size: 0
Current Packet Size: 0

What app are you using to send the packets? I have not experienced this. I don't use the String data type. I use strcmp instead.

SurferTim:
What app are you using to send the packets? I have not experienced this. I don't use the String data type. I use strcmp instead.

I have to integrate with a LabVIEW control program, so that is the program sending the packets. I'm a full time LabVIEW dev, and I'm pretty confident that the Labview code is working proper, but there could be compatibility issues.

I'm a novice at Arduino (I have quite a bit of C++ experience) so some of the Arduino specific constructs I don't know about.

Isn't strcmp just a fancy way of comparing the strings? Is there a way I can replace the UDP buffer with that? My logic works well ( the IF / Else statement ) the issue is getting the proper data to the Arduino.

I suspect your Labview code. You are receiving the packets correctly. You are printing what you receive to the serial monitor, and it is showing "ON" when you think it should be "OFF".

I don't consider strcmp as fancy. It is a basic comparison function.

SurferTim:
I suspect your Labview code. You are receiving the packets correctly. You are printing what you receive to the serial monitor, and it is showing "ON" when you think it should be "OFF".

I don't consider strcmp as fancy. It is a basic comparison function.

Can you tell me the advantage of using it instead of String?

I just downloaded Wireshark, I'm going to examine the packets being sent and see what is actually being sent.

The advantage of strcmp? You don't need the String data type.

if(strcmp("ON",packetBuffer) == 0) {
  // ON
}

But I don't think that is your problem. You are printing the contents of the packetBuffer to the serial monitor and, according to your expectations, it is showing "ON" when it should show "OFF".

SurferTim:
The advantage of strcmp? You don't need the String data type.

if(strcmp("ON",packetBuffer) == 0) {

// ON
}



But I don't think that is your problem. You are printing the contents of the packetBuffer to the serial monitor and, according to your expectations, it is showing "ON" when it should show "OFF".

Thanks for the insight on strcmp.

You were correct on the Labview program. I'm using a new version and they changed the way something works in the latest version. I moved something out of the event structure and its working perfectly now.

I suspected the Arduino code because I rarely develop in it, but it turns out the problem was in LabVIEW.

Thanks again for your help!!!