diff --git a/lib/ArduinoNTPd/NTPPacket.cpp b/lib/ArduinoNTPd/NTPPacket.cpp new file mode 100644 index 000000000..e3cdf6b32 --- /dev/null +++ b/lib/ArduinoNTPd/NTPPacket.cpp @@ -0,0 +1,39 @@ +/* + * File: NTPPacket.cpp + * Description: + * NTP packet representation. + * Author: Mooneer Salem + * License: New BSD License + */ + +#include "NTPPacket.h" + +void NtpPacket::swapEndian() +{ + reverseBytes_(&rootDelay); + reverseBytes_(&rootDispersion); + reverseBytes_(&referenceTimestampSeconds); + reverseBytes_(&referenceTimestampFraction); + reverseBytes_(&originTimestampSeconds); + reverseBytes_(&originTimestampFraction); + reverseBytes_(&receiveTimestampSeconds); + reverseBytes_(&receiveTimestampFraction); + reverseBytes_(&transmitTimestampSeconds); + reverseBytes_(&transmitTimestampFraction); +} + +void NtpPacket::reverseBytes_(uint32_t *number) +{ + char buf[4]; + char *numberAsChar = (char*)number; + + buf[0] = numberAsChar[3]; + buf[1] = numberAsChar[2]; + buf[2] = numberAsChar[1]; + buf[3] = numberAsChar[0]; + + numberAsChar[0] = buf[0]; + numberAsChar[1] = buf[1]; + numberAsChar[2] = buf[2]; + numberAsChar[3] = buf[3]; +} diff --git a/lib/ArduinoNTPd/NTPPacket.h b/lib/ArduinoNTPd/NTPPacket.h new file mode 100644 index 000000000..80a1366f5 --- /dev/null +++ b/lib/ArduinoNTPd/NTPPacket.h @@ -0,0 +1,75 @@ +/* + * File: NTPPacket.h + * Description: + * NTP packet representation. + * Author: Mooneer Salem + * License: New BSD License + */ + +#ifndef NTP_PACKET_H +#define NTP_PACKET_H + +#include "Arduino.h" + + +/* + * Contains the data in a typical NTP packet. + */ +struct NtpPacket +{ + static const int PACKET_SIZE = 48; + + unsigned char leapVersionMode; + + unsigned int leapIndicator() const { return leapVersionMode >> 6; } + void leapIndicator(unsigned int newValue) { leapVersionMode = (0x3F & leapVersionMode) | ((newValue & 0x03) << 6); } + + unsigned int versionNumber() const { return (leapVersionMode >> 3) & 0x07; } + void versionNumber(unsigned int newValue) { leapVersionMode = (0xC7 & leapVersionMode) | ((newValue & 0x07) << 3); } + + unsigned int mode() const { return (leapVersionMode & 0x07); } + void mode(unsigned int newValue) { leapVersionMode = (leapVersionMode & 0xF8) | (newValue & 0x07); } + + char stratum; + char poll; + char precision; + uint32_t rootDelay; + uint32_t rootDispersion; + char referenceId[4]; + uint32_t referenceTimestampSeconds; + uint32_t referenceTimestampFraction; + uint32_t originTimestampSeconds; + uint32_t originTimestampFraction; + uint32_t receiveTimestampSeconds; + uint32_t receiveTimestampFraction; + uint32_t transmitTimestampSeconds; + uint32_t transmitTimestampFraction; + + /* + * Rearranges bytes in 32 bit values from big-endian (NTP protocol) + * to little-endian (Arduino/PC), or vice versa. Must be called before + * modifying the structure or sending the packet. + */ + void swapEndian(); + + /* + * Returns packet as a char array for transmission via network. + * WARNING: modifying the return value is unsafe. + */ + const char *packet() { return (const char*)this; } + + /* + * Copies packet buffer to packet object. + */ + void populatePacket(const char *buffer) + { + memcpy(this, buffer, PACKET_SIZE); + } +private: + /* + * Reverses bytes in a number. + */ + void reverseBytes_(uint32_t *number); +}; + +#endif // NTP_PACKET_H diff --git a/lib/ArduinoNTPd/NTPServer.cpp b/lib/ArduinoNTPd/NTPServer.cpp new file mode 100644 index 000000000..6ee82bd6c --- /dev/null +++ b/lib/ArduinoNTPd/NTPServer.cpp @@ -0,0 +1,79 @@ +/* + * File: NTPServer.cpp + * Description: + * NTP server implementation. + * Author: Mooneer Salem + * License: New BSD License + */ + + +#include + +#include "NTPPacket.h" +#include "NTPServer.h" + +#define NTP_PORT 123 +#define NTP_TIMESTAMP_DIFF (2208988800) // 1900 to 1970 in seconds + +bool NtpServer::beginListening() +{ + if (timeServerPort_.begin(NTP_PORT)){ + return true; + } + return false; +} + +bool NtpServer::processOneRequest(uint32_t utc, uint32_t millisecs) +{ + // We need the time we've received the packet in our response. + uint32_t recvSecs = utc + NTP_TIMESTAMP_DIFF; + double recvFractDouble = (double)millisecs/0.00023283064365386963; // millisec/((10^6)/(2^32)) + uint32_t recvFract = (double)recvFractDouble; //TODO: really handle this!!! + bool processed = false; + + int packetDataSize = timeServerPort_.parsePacket(); + if (packetDataSize && packetDataSize >= NtpPacket::PACKET_SIZE) + { + // Received what is probably an NTP packet. Read it in and verify + // that it's legit. + NtpPacket packet; + timeServerPort_.read((char*)&packet, NtpPacket::PACKET_SIZE); + // TODO: verify packet. + + // Populate response. + packet.swapEndian(); + packet.leapIndicator(0); + packet.versionNumber(4); + packet.mode(4); + packet.stratum = 2; // I guess stratum 1 is too optimistic + packet.poll = 10; // 6-10 per RFC 5905. + packet.precision = -21; // ~0.5 microsecond precision. + packet.rootDelay = 0; //60 * (0xFFFF / 1000); // ~60 milliseconds, TBD + packet.rootDispersion = 0; //10 * (0xFFFF / 1000); // ~10 millisecond dispersion, TBD + packet.referenceId[0] = 'G'; + packet.referenceId[1] = 'P'; + packet.referenceId[2] = 'S'; + packet.referenceId[3] = 0; + packet.referenceTimestampSeconds = utc; + packet.referenceTimestampFraction = recvFract; + packet.originTimestampSeconds = packet.transmitTimestampSeconds; + packet.originTimestampFraction = packet.transmitTimestampFraction; + packet.receiveTimestampSeconds = recvSecs; + packet.receiveTimestampFraction = recvFract; + + // ...and the transmit time. + // timeSource_.now(&packet.transmitTimestampSeconds, &packet.transmitTimestampFraction); + + // Now transmit the response to the client. + packet.swapEndian(); + timeServerPort_.beginPacket(timeServerPort_.remoteIP(), timeServerPort_.remotePort()); + for (int count = 0; count < NtpPacket::PACKET_SIZE; count++) + { + timeServerPort_.write(packet.packet()[count]); + } + timeServerPort_.endPacket(); + processed = true; + } + + return processed; +} \ No newline at end of file diff --git a/lib/ArduinoNTPd/NTPServer.h b/lib/ArduinoNTPd/NTPServer.h new file mode 100644 index 000000000..121d905ce --- /dev/null +++ b/lib/ArduinoNTPd/NTPServer.h @@ -0,0 +1,35 @@ +/* + * File: NTPServer.h + * Description: + * NTP server implementation. + * Author: Mooneer Salem + * License: New BSD License + */ + +#ifndef NTP_SERVER_H +#define NTP_SERVER_H + +class NtpServer +{ +public: + NtpServer(WiFiUDP Port) + { + timeServerPort_=Port; + } + + /* + * Begins listening for NTP requests. + */ + bool beginListening(void); + + + /* + * Processes a single NTP request. + */ + bool processOneRequest(uint32_t utc, uint32_t millisecs); + +private: + WiFiUDP timeServerPort_; +}; + +#endif // NTP_SERVER_H diff --git a/tasmota/xsns_58_GPS.ino b/tasmota/xsns_58_GPS.ino index f2808f8fd..1871ff85f 100644 --- a/tasmota/xsns_58_GPS.ino +++ b/tasmota/xsns_58_GPS.ino @@ -1,5 +1,5 @@ /* - xsns_92_GPS_UBX.ino - GPS UBLOX support for Sonoff-Tasmota + xsns_58_GPS_UBX.ino - GPS UBLOX support for Sonoff-Tasmota Copyright (C) 2019 Theo Arends, Christian Baars and Adrian Scillato