From b026daf43bcc2d9be94479187562016871601f1b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 12 Apr 2015 01:09:45 +0800 Subject: [PATCH 1/2] 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. --- README.md | 2 +- .../examples/NTPClient/NTPClient.ino | 146 ++++++++++++++++++ libraries/ESP8266WiFi/src/WiFiUdp.cpp | 21 ++- libraries/ESP8266WiFi/src/WiFiUdp.h | 2 + .../ESP8266WiFi/src/include/UdpContext.h | 8 + 5 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino diff --git a/README.md b/README.md index 8c34a27d2..5ae2faa2c 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ This is mostly similar to WiFi shield library. Differences include: - ```WiFi.printDiag(Serial);``` will print out some diagnostic info WiFiServer, WiFiClient, and WiFiUDP behave mostly the same way as with WiFi shield library. -Three samples are provided for this library. +Four samples are provided for this library. #### Ticker #### diff --git a/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino b/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino new file mode 100644 index 000000000..4a9771b5f --- /dev/null +++ b/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino @@ -0,0 +1,146 @@ +/* + + Udp NTP Client + + Get the time from a Network Time Protocol (NTP) time server + Demonstrates use of UDP sendPacket and ReceivePacket + For more on NTP time servers and the messages needed to communicate with them, + see http://en.wikipedia.org/wiki/Network_Time_Protocol + + created 4 Sep 2010 + by Michael Margolis + modified 9 Apr 2012 + by Tom Igoe + updated for the ESP8266 12 Apr 2015 + by Ivan Grokhotkov + + This code is in the public domain. + + */ + +#include +#include + +char ssid[] = "*************"; // your network SSID (name) +char pass[] = "********"; // your network password + + +unsigned int localPort = 2390; // local port to listen for UDP packets + +IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server + +const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message + +byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets + +// A UDP instance to let us send and receive packets over UDP +WiFiUDP udp; + +void setup() +{ + Serial.begin(115200); + Serial.println(); + Serial.println(); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + WiFi.begin(ssid, pass); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + Serial.println("Starting UDP"); + udp.begin(localPort); + Serial.print("Local port: "); + Serial.println(udp.localPort()); +} + +void loop() +{ + sendNTPpacket(timeServer); // send an NTP packet to a time server + // wait to see if a reply is available + delay(1000); + + int cb = udp.parsePacket(); + if (!cb) { + Serial.println("no packet yet"); + } + else { + Serial.print("packet received, length="); + Serial.println(cb); + // We've received a packet, read the data from it + udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer + + //the timestamp starts at byte 40 of the received packet and is four bytes, + // or two words, long. First, esxtract the two words: + + unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); + unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + Serial.print("Seconds since Jan 1 1900 = " ); + Serial.println(secsSince1900); + + // now convert NTP time into everyday time: + Serial.print("Unix time = "); + // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: + const unsigned long seventyYears = 2208988800UL; + // subtract seventy years: + unsigned long epoch = secsSince1900 - seventyYears; + // print Unix time: + Serial.println(epoch); + + + // print the hour, minute and second: + Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) + Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) + Serial.print(':'); + if ( ((epoch % 3600) / 60) < 10 ) { + // In the first 10 minutes of each hour, we'll want a leading '0' + Serial.print('0'); + } + Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) + Serial.print(':'); + if ( (epoch % 60) < 10 ) { + // In the first 10 seconds of each minute, we'll want a leading '0' + Serial.print('0'); + } + Serial.println(epoch % 60); // print the second + } + // wait ten seconds before asking for the time again + delay(10000); +} + +// send an NTP request to the time server at the given address +unsigned long sendNTPpacket(IPAddress& address) +{ + Serial.println("sending NTP packet..."); + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + udp.beginPacket(address, 123); //NTP requests are to port 123 + udp.write(packetBuffer, NTP_PACKET_SIZE); + udp.endPacket(); +} diff --git a/libraries/ESP8266WiFi/src/WiFiUdp.cpp b/libraries/ESP8266WiFi/src/WiFiUdp.cpp index 298f732f6..96928f24a 100644 --- a/libraries/ESP8266WiFi/src/WiFiUdp.cpp +++ b/libraries/ESP8266WiFi/src/WiFiUdp.cpp @@ -66,10 +66,10 @@ WiFiUDP::~WiFiUDP() /* Start WiFiUDP socket, listening at local port */ uint8_t WiFiUDP::begin(uint16_t port) { - if (_ctx) - { + if (_ctx) { _ctx->unref(); } + _ctx = new UdpContext; ip_addr_t addr; addr.addr = INADDR_ANY; @@ -78,13 +78,11 @@ uint8_t WiFiUDP::begin(uint16_t port) uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) { - if (_ctx) - { + if (_ctx) { _ctx->unref(); _ctx = 0; } - ip_addr_t ifaddr; ifaddr.addr = (uint32_t) interfaceAddr; ip_addr_t multicast_addr; @@ -95,6 +93,7 @@ uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, ui } _ctx = new UdpContext; + if (!_ctx->listen(*IP_ADDR_ANY, port)) { return 0; } @@ -134,9 +133,8 @@ int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) ip_addr_t addr; addr.addr = ip; - if (_ctx) - _ctx->unref(); - _ctx = new UdpContext; + if (!_ctx) + _ctx = new UdpContext; return (_ctx->connect(addr, port)) ? 1 : 0; } @@ -227,3 +225,10 @@ uint16_t WiFiUDP::remotePort() return _ctx->getRemotePort(); } +uint16_t WiFiUDP::localPort() +{ + if (!_ctx) + return 0; + + return _ctx->getLocalPort(); +} diff --git a/libraries/ESP8266WiFi/src/WiFiUdp.h b/libraries/ESP8266WiFi/src/WiFiUdp.h index 06b39d0fe..4f0941af1 100644 --- a/libraries/ESP8266WiFi/src/WiFiUdp.h +++ b/libraries/ESP8266WiFi/src/WiFiUdp.h @@ -86,6 +86,8 @@ public: virtual IPAddress remoteIP(); // Return the port of the host who sent the current incoming packet virtual uint16_t remotePort(); + // Return the local port for outgoing packets + uint16_t localPort(); }; diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index 576d4200b..216c53928 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -120,6 +120,14 @@ public: return ntohs(udphdr->src); } + uint16_t getLocalPort() + { + if (!_pcb) + return 0; + + return _pcb->local_port; + } + bool next() { if (!_rx_buf) From 6b593a79780fb2e956e4930f4f4456c849986f4c Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 12 Apr 2015 02:07:56 +0800 Subject: [PATCH 2/2] Add ESP.reset() method --- README.md | 2 ++ cores/esp8266/Esp.cpp | 5 +++++ cores/esp8266/Esp.h | 2 ++ 3 files changed, 9 insertions(+) diff --git a/README.md b/README.md index 5ae2faa2c..ad1c571f8 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,8 @@ APIs related to deep sleep and watchdog timer are available in the ```ESP``` obj ```ESP.wdtEnable()```, ```ESP.wdtDisable()```, and ```ESP.wdtFeed()``` provide some control over the watchdog timer. +```ESP.reset()``` resets the CPU. + #### OneWire (from https://www.pjrc.com/teensy/td_libs_OneWire.html) #### Library was adapted to work with ESP8266 by including register definitions into OneWire.h diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index 8e7caf6e6..28deeff28 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -55,3 +55,8 @@ void EspClass::deepSleep(uint32_t time_us, WakeMode mode) system_deep_sleep_set_option(static_cast(mode)); system_deep_sleep(time_us); } + +void EspClass::reset() +{ + ((void (*)(void))0x40000080)(); +} diff --git a/cores/esp8266/Esp.h b/cores/esp8266/Esp.h index 7f10ec1d6..c91e7e7b8 100644 --- a/cores/esp8266/Esp.h +++ b/cores/esp8266/Esp.h @@ -39,6 +39,8 @@ class EspClass { void wdtFeed(); void deepSleep(uint32_t time_us, WakeMode mode = WAKE_RF_DEFAULT); + + void reset(); }; extern EspClass ESP;