Skip to content

Instantly share code, notes, and snippets.

@fpoto
Last active December 26, 2015 10:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fpoto/7135314 to your computer and use it in GitHub Desktop.
Save fpoto/7135314 to your computer and use it in GitHub Desktop.
Example code for the "WiFiUdp stop() does not release UDP socket" bug reported at https://github.com/arduino/Arduino/issues/1637. Only thing to change is the name (and possibly password) of your WiFi network. See the bug report for the expected output.
#include <WiFi.h>
#include <WiFiUdp.h>
unsigned long inline ntpUnixTime (WiFiUDP&);
char ssid[] = "xxxxxxxx"; // your network SSID (name)
void setup()
{
Serial.begin(115200);
Serial.print("Attempting to connect to SSID: ");
Serial.print(ssid);
if (WiFi.begin(ssid) == WL_CONNECTED)
Serial.println(" connected");
else {
Serial.println(" failed");
while (true) ;
}
}
void loop()
{
WiFiUDP udp;
int inited;
unsigned long unixTime;
# define initonce true // open socket once or every packet sent
#if initonce
inited = udp.begin(1963); // open socket
for (int requests = 0; requests < 5; ++requests) {
unixTime = ntpUnixTime(udp); // send NTP request and get response
#else
for (int requests = 0; requests < 5; ++requests) {
inited = udp.begin(1963); // open socket
unixTime = ntpUnixTime(udp); // send NTP request and get response
udp.stop(); // close socket
#endif
if (! inited)
Serial.println("begin failed");
else if (! unixTime)
Serial.println("request failed");
else {
Serial.print("UTC time: ");
Serial.println(unixTime);
}
delay(2000); // wait for a while before next request
}
while (true) ; // stop here
}
/*
* Francesco Potortì, 2013, GPLv3, version 1
* Send an NTP packet and wait for the response, return the Unix time
*
* To lower the memory footprint, no buffers are allocated for sending
* and receiving the NTP packets. Four bytes of memory are allocated
* for transmision, the rest is random garbage collected from the data
* memory segment, and the received packet is read one byte at a time.
* Time returned is the Unix time, that is, seconds from 1970-01-01.
*/
unsigned long inline ntpUnixTime (WiFiUDP& udp)
{
const char timeServer[] = "pool.ntp.org"; // NTP server
const long ntpFirstFourBytes = 0xEC0600E3; // NTP request header
unsigned long time = 0; // NTP time
// Clear received data
udp.flush();
// Send an NTP request
if (! (udp.beginPacket(timeServer, 123) // 123 is the NTP port
&& udp.write((byte *)&ntpFirstFourBytes, 48) == 48
&& udp.endPacket()))
return 0; // sending request failed
// Wait for response; check every pollIntv ms up to maxPoll times
const int pollIntv = 150; // poll every this many ms
const byte maxPoll = 15; // poll up to this many times
int pktLen; // received packet length
for (byte i=0; i<maxPoll; i++) {
if ((pktLen = udp.parsePacket()) == 48)
break;
delay(pollIntv);
}
if (pktLen != 48)
return 0; // no correct packet received
// Read and discard the first useless bytes
// We use the server receive time if we want to save 8 udp.read()
// else we use the server send time which is closest to the real time.
// Set useless to 32 for speed; set to 40 for accuracy.
const byte useless = 32;
for (byte i = 0; i < useless; ++i)
udp.read();
// Read the integer part of sending time
for (byte i = 0; i < 4; i++)
time = time << 8 | udp.read();
// Round to the nearest second if we want accuracy
if (useless == 40) // we want accuracy
// The fractionary part is the next byte divided by 256: if it is
// greater than 500ms we round to the next second; we also account
// for an assumed network delay of 50ms, and (0.5-0.05)*256=115;
// additionally, we account for how much we delayed reading the packet
// since its arrival, which we assume on average to be pollIntv/2.
time += (udp.read() > 115 - pollIntv/8);
// Discard the rest of the packet
udp.flush();
return time - 2208988800ul; // convert NTP time to Unix time
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment