UDP - disable buffering

I am using a keypad to choose between different modes in my program, one mode is to read data using UDP from a computer which is continuously sending me time values. The issue I am having is that it seems to be buffering my data if when I am not in that mode.

For example, if I go into this mode and receive:
1:55:47.5
1:55:47.6
1:55:47.7
1:55:47.8
1:55:47.9
1:55:48.0

Then click the button to change modes, play around in another mode, then eventually switch back to this time mode, it will start counting like this:
1:55:48.1
1:55:48.2
1:55:48.3
1:55:48.4
1:55:48.5
1:55:48.6

That is sequentially in order... but since i spent time in another mode, the time that is being read in is not actually what is being sent to me anymore, that was sent maybe a few minutes ago.

So it seems like this data is being buffered somehow.
I have tried clearing the packetBuffer but all this does is clear out just one of the time values, not the entire "buffer".

Since I am using UDP I was expecting that if I wasn't actively listening/capturing the packets that they would just be ignored, but that does not seem to be the case. They are being captured somehow.

Alternatively, if I change my delay(100) to delay(2000), it will only print out one time value every two seconds as expected. The issue is that is still prints out the time in tenths of a second like shown above. With the two second delay this quickly gets me way out of sync with the computer sending me the time. I would expect to only print out the accurate time every two seconds and ignore all values in between.

Maybe I am completely wrong about how UDP works and maybe this is impossible to do, but I hope there is a way to solve my problem.

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Keypad.h>
#include <FlexiTimer2.h>

String mode = "";

char keys[4][4] = 
{
  {'0','1','2','3'},
  {'4','5','6','7'},
  {'8','9','A','B'}, 
  {'C','D','E','F'},
};
byte rowPins[4] = {2,3,4,5};
byte colPins[4] = {6,7,8,9}; 

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, 4, 4);

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(172, 16, 0, 72);
unsigned int localPort = 8888;
EthernetUDP Udp;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];

char myString[6] = {' ',' ',' ',' ',' ',' '};

void setup()
{
  Ethernet.begin(mac,ip);
  Udp.begin(localPort);
  
  FlexiTimer2::set(100, checkKey);
  FlexiTimer2::start();
  
  Serial.begin(9600);
}

void checkKey()
{
   char key = kpd.getKey();
   if(key)
   {
       if(key == 'C') // C is the SELECT MODE button
       {
           mode = "";
       }

       if(mode == "lynx")
       {

       }
       else // select mode
       {
           if(key == '0')
           {      
               mode = "lynx";
           }
       } 
   }
}

void loop()
{
   Serial.println(packetBuffer);
  
   if(mode == "lynx")
   {
        int packetSize = Udp.parsePacket();
        Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
        //Serial.println(packetBuffer);
        delay(100);
  
   }  
   else // select mode
   {
       delay(1000);
   }
}

Doing some more reading

This code sends a request for data, then waits one second, then reads the data (assuming data came in). So essentially it is buffering a packet and waiting for it to be read.

Knowing that it is buffering packets, I went to my code and instead of only reading packets in one specific mode, I put that code in the loop. So I am reading packets every loop, but I am only parsing the data and acting on the data if my mode is set correctly.

This seems like a waste of processing power and it forces me to change up some more of my code to handle delays properly for my different modes, but it is working right now.

The code below is from the NTP example

void loop()
{
  sendNTPpacket(timeServer); // send an NTP packet to a time server

  // wait to see if a reply is available
  delay(1000);  
  if ( Udp.parsePacket() ) {  
    // We've received a packet, read the data from it
    Udp.read(packetBuffer,NTP_PACKET_SIZE);

UDP is a "send a packet, get a packet" protocol. There is no connection. The "buffering" is done by the w5100.

NTP isn't really designed to be used as a clock, only to set a clock to the correct time and adjust it occasionally. The way the Arduino NTP code works, you will get accuracy of about 1 to 2 seconds.

Some NTP servers will block you if you start requesting the time too often. I do not recommend any more often than 10 minutes initially, and no more often than 20 minutes once you get your clock adjusted.

I wasn't looking to use NTP at all, I was just looking at its code since it uses UDP.
I do not want to use NTP at all for my program.

And I need to take in data in real time.
The computer can send other data to the arduino as well but for now im just trying to get the time to come over and the buffering caused a problem only when I try to do other things.

I want to be able to "get a packet" at the same time it is sent.
I don't want to wait 30 seconds for the buffer to run through and then read the packet I wanted. So I am still looking for some sort of option then.

I went through the ethernet library code and found some buffer sizes but changing them just caused my program to crash when the buffer filled up.

I want to be able to "get a packet" at the same time it is sent.

That won't happen. It takes time for a packet to get to the destination UDP box, processed, and time for the response packet to get back to you. The closer they are to each other, the better response time you will get. Both UDP devices on the same localnet is best. But even over the internet, one second there and back should be doable. That is what I use for NTP.

edit: If the UDP boxes are not sending a request and getting a response, you could do that. If they are just talkers, they can work very fast.

For my case they will both be on the same switch.
And by the same time I mean within the same second.

Like I have been saying, it works perfect until I go to do something else.
When I am doing something else I am not reading in the packets, but instead they are all buffering up. Then when I go back to my timer mode, it has to go through all the buffered packets, but I don't care about those buffered packets, I just want to start fresh again.

Within a second on the same localnet is easily doable.

You can disable the UDP service. I wrote a test sketch a while back to test UDP when running TCP services.
http://forum.arduino.cc/index.php?topic=167184.msg1364572#msg1364572
Take a look at the checkTime() function. It calls UDP.begin() at the start, and UDP.stop() at the end. UDP is disabled while not in that function.

wow does UDP.stop() actually work?
the documentation doesn't list a stop method for the EthernetUDP or Ethernet classes.
if that does work then I just wasted a lot of time over nothing.
I will test that out tomororw, thanks.

Yes, it works well. Load and run that sketch. It displays the socket status of the w5100 during each of those operations so you can see for yourself. If there is no socket with a status of 0x22, then UDP is disabled and will not receive UDP packets.

the documentation doesn't list a stop method for the EthernetUDP or Ethernet classes.

Just as a follow-up, I will try to submit that to the Arduino crew as a change, but FYI I have tried this before more than once with no success.

UDP.stop() is in the EthernetUdp.h file, but not in the online reference guide.

public:
  EthernetUDP();  // Constructor
  virtual uint8_t begin(uint16_t);	// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
  virtual void stop();  // Finish with the UDP socket

UDP.stop() worked perfectly, thank you!

UDP.stop() is now in the reference docs. :slight_smile: