Last active
December 26, 2015 14:09
-
-
Save fpoto/7163904 to your computer and use it in GitHub Desktop.
Demonstration of the WiFiUdp.write() bug posted as issue #1642.
Works when allTogether is set to true, fails when set to false.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <WiFi.h> | |
#include <WiFiUdp.h> | |
unsigned long inline ntpUnixTime (); | |
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() | |
{ | |
unsigned long unixTime; | |
for (int requests = 0; requests < 5; ++requests) { | |
unixTime = ntpUnixTime(); // send NTP request and get response | |
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 - $Revision: 1.10 $ | |
* | |
* 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 () | |
{ | |
// Statically allocate a WiFiUdp object and initialise it once. | |
// It would be better to allocate it dynamically and use close() | |
// on it when exiting the function, can't until bug #1637 is solved. | |
// For Ethernet, use EthernetUDP rather than WiFiUdp. | |
static WiFiUDP udp; | |
static int udpInited = udp.begin(1963); // open socket | |
const char timeServer[] = "pool.ntp.org"; // NTP server | |
// Only the first four bytes of an outgoing NTP packet need to be set | |
// appropriately, the rest can be whatever. | |
const long ntpFirstFourBytes = 0xEC0600E3; // NTP request header | |
byte buf[48]; | |
// Fail if WiFiUdp.begin() could not init a socket | |
if (! udpInited) | |
return 0; | |
// Clear received data from possible stray received packets | |
udp.flush(); | |
// Send an NTP request | |
udp.beginPacket(timeServer, 123); // 123 is the NTP port | |
*(long *)buf = ntpFirstFourBytes; | |
# define allTogether true | |
# if allTogether | |
udp.write(buf, 48); | |
#else | |
for (byte i = 0; i < 48; ++i) | |
udp.write(buf[i]); | |
#endif | |
if (udp.endPacket()) | |
Serial.println("endPacket successful"); | |
else { | |
Serial.println("endPacket failed"); | |
while (true) ; | |
} | |
// 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 | |
unsigned long time = udp.read(); // NTP time | |
for (byte i = 1; 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