Skip to content

Commit 00247bb

Browse files
committed
Fix UdpClient semantics, add NTPClient example
UdpClient used to create a new socket for each begin/beginPacket call. This made bidirectional communication impossible. Fix #64, fix #53.
1 parent 5ba3a59 commit 00247bb

File tree

5 files changed

+170
-9
lines changed

5 files changed

+170
-9
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ This is mostly similar to WiFi shield library. Differences include:
7979
- ```WiFi.printDiag(Serial);``` will print out some diagnostic info
8080

8181
WiFiServer, WiFiClient, and WiFiUDP behave mostly the same way as with WiFi shield library.
82-
Three samples are provided for this library.
82+
Four samples are provided for this library.
8383

8484
#### Ticker ####
8585

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
3+
Udp NTP Client
4+
5+
Get the time from a Network Time Protocol (NTP) time server
6+
Demonstrates use of UDP sendPacket and ReceivePacket
7+
For more on NTP time servers and the messages needed to communicate with them,
8+
see http://en.wikipedia.org/wiki/Network_Time_Protocol
9+
10+
created 4 Sep 2010
11+
by Michael Margolis
12+
modified 9 Apr 2012
13+
by Tom Igoe
14+
updated for the ESP8266 12 Apr 2015
15+
by Ivan Grokhotkov
16+
17+
This code is in the public domain.
18+
19+
*/
20+
21+
#include <ESP8266WiFi.h>
22+
#include <WiFiUdp.h>
23+
24+
char ssid[] = "*************"; // your network SSID (name)
25+
char pass[] = "********"; // your network password
26+
27+
28+
unsigned int localPort = 2390; // local port to listen for UDP packets
29+
30+
IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
31+
32+
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
33+
34+
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
35+
36+
// A UDP instance to let us send and receive packets over UDP
37+
WiFiUDP udp;
38+
39+
void setup()
40+
{
41+
Serial.begin(115200);
42+
Serial.println();
43+
Serial.println();
44+
45+
// We start by connecting to a WiFi network
46+
Serial.print("Connecting to ");
47+
Serial.println(ssid);
48+
WiFi.begin(ssid, pass);
49+
50+
while (WiFi.status() != WL_CONNECTED) {
51+
delay(500);
52+
Serial.print(".");
53+
}
54+
Serial.println("");
55+
56+
Serial.println("WiFi connected");
57+
Serial.println("IP address: ");
58+
Serial.println(WiFi.localIP());
59+
60+
Serial.println("Starting UDP");
61+
udp.begin(localPort);
62+
Serial.print("Local port: ");
63+
Serial.println(udp.localPort());
64+
}
65+
66+
void loop()
67+
{
68+
sendNTPpacket(timeServer); // send an NTP packet to a time server
69+
// wait to see if a reply is available
70+
delay(1000);
71+
72+
int cb = udp.parsePacket();
73+
if (!cb) {
74+
Serial.println("no packet yet");
75+
}
76+
else {
77+
Serial.print("packet received, length=");
78+
Serial.println(cb);
79+
// We've received a packet, read the data from it
80+
udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
81+
82+
//the timestamp starts at byte 40 of the received packet and is four bytes,
83+
// or two words, long. First, esxtract the two words:
84+
85+
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
86+
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
87+
// combine the four bytes (two words) into a long integer
88+
// this is NTP time (seconds since Jan 1 1900):
89+
unsigned long secsSince1900 = highWord << 16 | lowWord;
90+
Serial.print("Seconds since Jan 1 1900 = " );
91+
Serial.println(secsSince1900);
92+
93+
// now convert NTP time into everyday time:
94+
Serial.print("Unix time = ");
95+
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
96+
const unsigned long seventyYears = 2208988800UL;
97+
// subtract seventy years:
98+
unsigned long epoch = secsSince1900 - seventyYears;
99+
// print Unix time:
100+
Serial.println(epoch);
101+
102+
103+
// print the hour, minute and second:
104+
Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
105+
Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
106+
Serial.print(':');
107+
if ( ((epoch % 3600) / 60) < 10 ) {
108+
// In the first 10 minutes of each hour, we'll want a leading '0'
109+
Serial.print('0');
110+
}
111+
Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
112+
Serial.print(':');
113+
if ( (epoch % 60) < 10 ) {
114+
// In the first 10 seconds of each minute, we'll want a leading '0'
115+
Serial.print('0');
116+
}
117+
Serial.println(epoch % 60); // print the second
118+
}
119+
// wait ten seconds before asking for the time again
120+
delay(10000);
121+
}
122+
123+
// send an NTP request to the time server at the given address
124+
unsigned long sendNTPpacket(IPAddress& address)
125+
{
126+
Serial.println("sending NTP packet...");
127+
// set all bytes in the buffer to 0
128+
memset(packetBuffer, 0, NTP_PACKET_SIZE);
129+
// Initialize values needed to form NTP request
130+
// (see URL above for details on the packets)
131+
packetBuffer[0] = 0b11100011; // LI, Version, Mode
132+
packetBuffer[1] = 0; // Stratum, or type of clock
133+
packetBuffer[2] = 6; // Polling Interval
134+
packetBuffer[3] = 0xEC; // Peer Clock Precision
135+
// 8 bytes of zero for Root Delay & Root Dispersion
136+
packetBuffer[12] = 49;
137+
packetBuffer[13] = 0x4E;
138+
packetBuffer[14] = 49;
139+
packetBuffer[15] = 52;
140+
141+
// all NTP fields have been given values, now
142+
// you can send a packet requesting a timestamp:
143+
udp.beginPacket(address, 123); //NTP requests are to port 123
144+
udp.write(packetBuffer, NTP_PACKET_SIZE);
145+
udp.endPacket();
146+
}

hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.cpp

+13-8
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ WiFiUDP::~WiFiUDP()
6666
/* Start WiFiUDP socket, listening at local port */
6767
uint8_t WiFiUDP::begin(uint16_t port)
6868
{
69-
if (_ctx)
70-
{
69+
if (_ctx) {
7170
_ctx->unref();
7271
}
72+
7373
_ctx = new UdpContext;
7474
ip_addr_t addr;
7575
addr.addr = INADDR_ANY;
@@ -78,13 +78,11 @@ uint8_t WiFiUDP::begin(uint16_t port)
7878

7979
uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port)
8080
{
81-
if (_ctx)
82-
{
81+
if (_ctx) {
8382
_ctx->unref();
8483
_ctx = 0;
8584
}
8685

87-
8886
ip_addr_t ifaddr;
8987
ifaddr.addr = (uint32_t) interfaceAddr;
9088
ip_addr_t multicast_addr;
@@ -95,6 +93,7 @@ uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, ui
9593
}
9694

9795
_ctx = new UdpContext;
96+
9897
if (!_ctx->listen(*IP_ADDR_ANY, port)) {
9998
return 0;
10099
}
@@ -134,9 +133,8 @@ int WiFiUDP::beginPacket(IPAddress ip, uint16_t port)
134133
ip_addr_t addr;
135134
addr.addr = ip;
136135

137-
if (_ctx)
138-
_ctx->unref();
139-
_ctx = new UdpContext;
136+
if (!_ctx)
137+
_ctx = new UdpContext;
140138
return (_ctx->connect(addr, port)) ? 1 : 0;
141139
}
142140

@@ -227,3 +225,10 @@ uint16_t WiFiUDP::remotePort()
227225
return _ctx->getRemotePort();
228226
}
229227

228+
uint16_t WiFiUDP::localPort()
229+
{
230+
if (!_ctx)
231+
return 0;
232+
233+
return _ctx->getLocalPort();
234+
}

hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.h

+2
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ class WiFiUDP : public UDP {
8686
virtual IPAddress remoteIP();
8787
// Return the port of the host who sent the current incoming packet
8888
virtual uint16_t remotePort();
89+
// Return the local port for outgoing packets
90+
uint16_t localPort();
8991

9092
};
9193

hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/UdpContext.h

+8
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@ class UdpContext
120120
return ntohs(udphdr->src);
121121
}
122122

123+
uint16_t getLocalPort()
124+
{
125+
if (!_pcb)
126+
return 0;
127+
128+
return _pcb->local_port;
129+
}
130+
123131
bool next()
124132
{
125133
if (!_rx_buf)

0 commit comments

Comments
 (0)