A time interface class. This class replicates the normal time functions, but goes a couple of steps further. mbed library 82 and prior has a defective gmtime function. Also, this class enables access to setting the time, and adjusting the accuracy of the RTC.

Dependencies:   CalendarPage

Dependents:   CI-data-logger-server WattEye X10Svr SSDP_Server

Committer:
WiredHome
Date:
Tue Nov 21 17:04:12 2017 +0000
Revision:
21:f3818e2e0370
Child:
27:67e4e2ab048a
Updates for OS5 and integrate NTPClient for network time sync.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 21:f3818e2e0370 1 /* NTPClient.cpp */
WiredHome 21:f3818e2e0370 2 /* Copyright (C) 2012 mbed.org, MIT License
WiredHome 21:f3818e2e0370 3 *
WiredHome 21:f3818e2e0370 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
WiredHome 21:f3818e2e0370 5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
WiredHome 21:f3818e2e0370 6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
WiredHome 21:f3818e2e0370 7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
WiredHome 21:f3818e2e0370 8 * furnished to do so, subject to the following conditions:
WiredHome 21:f3818e2e0370 9 *
WiredHome 21:f3818e2e0370 10 * The above copyright notice and this permission notice shall be included in all copies or
WiredHome 21:f3818e2e0370 11 * substantial portions of the Software.
WiredHome 21:f3818e2e0370 12 *
WiredHome 21:f3818e2e0370 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
WiredHome 21:f3818e2e0370 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
WiredHome 21:f3818e2e0370 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
WiredHome 21:f3818e2e0370 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
WiredHome 21:f3818e2e0370 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
WiredHome 21:f3818e2e0370 18 */
WiredHome 21:f3818e2e0370 19 #include "mbed.h" //time() and set_time()
WiredHome 21:f3818e2e0370 20
WiredHome 21:f3818e2e0370 21 #include "EthernetInterface.h"
WiredHome 21:f3818e2e0370 22 #include "UDPSocket.h"
WiredHome 21:f3818e2e0370 23 #include "Socket.h"
WiredHome 21:f3818e2e0370 24 #include "NTPClient.h"
WiredHome 21:f3818e2e0370 25
WiredHome 21:f3818e2e0370 26
WiredHome 21:f3818e2e0370 27 //#define DEBUG "NTPc"
WiredHome 21:f3818e2e0370 28
WiredHome 21:f3818e2e0370 29 #if (defined(DEBUG))
WiredHome 21:f3818e2e0370 30 #include <cstdio>
WiredHome 21:f3818e2e0370 31 #define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 21:f3818e2e0370 32 #define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 21:f3818e2e0370 33 #define ERR(x, ...) std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 21:f3818e2e0370 34 static void HexDump(const char * title, void * pT, int count)
WiredHome 21:f3818e2e0370 35 {
WiredHome 21:f3818e2e0370 36 int i;
WiredHome 21:f3818e2e0370 37 uint8_t * p = (uint8_t *)pT;
WiredHome 21:f3818e2e0370 38 char buf[100] = "0000: ";
WiredHome 21:f3818e2e0370 39
WiredHome 21:f3818e2e0370 40 if (*title)
WiredHome 21:f3818e2e0370 41 INFO("%s", title);
WiredHome 21:f3818e2e0370 42 for (i=0; i<count; ) {
WiredHome 21:f3818e2e0370 43 sprintf(buf + strlen(buf), "%02X ", *(p+i));
WiredHome 21:f3818e2e0370 44 if ((++i & 0x0F) == 0x00) {
WiredHome 21:f3818e2e0370 45 INFO("%s", buf);
WiredHome 21:f3818e2e0370 46 if (i < count)
WiredHome 21:f3818e2e0370 47 sprintf(buf, "%04X: ", i);
WiredHome 21:f3818e2e0370 48 else
WiredHome 21:f3818e2e0370 49 buf[0] = '\0';
WiredHome 21:f3818e2e0370 50 }
WiredHome 21:f3818e2e0370 51 }
WiredHome 21:f3818e2e0370 52 if (strlen(buf))
WiredHome 21:f3818e2e0370 53 INFO("%s", buf);
WiredHome 21:f3818e2e0370 54 }
WiredHome 21:f3818e2e0370 55 #else
WiredHome 21:f3818e2e0370 56 //Disable debug
WiredHome 21:f3818e2e0370 57 #define INFO(x, ...)
WiredHome 21:f3818e2e0370 58 #define WARN(x, ...)
WiredHome 21:f3818e2e0370 59 #define ERR(x, ...)
WiredHome 21:f3818e2e0370 60 #define HexDump(a,b,c)
WiredHome 21:f3818e2e0370 61 #endif
WiredHome 21:f3818e2e0370 62
WiredHome 21:f3818e2e0370 63
WiredHome 21:f3818e2e0370 64 #define NTP_PORT 123
WiredHome 21:f3818e2e0370 65 #define NTP_CLIENT_PORT 0 //Random port
WiredHome 21:f3818e2e0370 66 #define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900)
WiredHome 21:f3818e2e0370 67
WiredHome 21:f3818e2e0370 68 #if 0 && MBED_MAJOR_VERSION == 5
WiredHome 21:f3818e2e0370 69 #define htonl(x) ((((x) & 0x000000ffUL) << 24) | \
WiredHome 21:f3818e2e0370 70 (((x) & 0x0000ff00UL) << 8) | \
WiredHome 21:f3818e2e0370 71 (((x) & 0x00ff0000UL) >> 8) | \
WiredHome 21:f3818e2e0370 72 (((x) & 0xff000000UL) >> 24))
WiredHome 21:f3818e2e0370 73 #define ntohl(x) htonl(x)
WiredHome 21:f3818e2e0370 74 #endif
WiredHome 21:f3818e2e0370 75
WiredHome 21:f3818e2e0370 76 NTPClient::NTPClient(EthernetInterface * _net) : m_sock()
WiredHome 21:f3818e2e0370 77 {
WiredHome 21:f3818e2e0370 78 net = _net;
WiredHome 21:f3818e2e0370 79 }
WiredHome 21:f3818e2e0370 80
WiredHome 21:f3818e2e0370 81
WiredHome 21:f3818e2e0370 82 NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout)
WiredHome 21:f3818e2e0370 83 {
WiredHome 21:f3818e2e0370 84 #ifdef DEBUG
WiredHome 21:f3818e2e0370 85 time_t ctTime;
WiredHome 21:f3818e2e0370 86 ctTime = time(NULL);
WiredHome 21:f3818e2e0370 87 INFO("Time is currently (UTC): %s", ctime(&ctTime));
WiredHome 21:f3818e2e0370 88 #endif
WiredHome 21:f3818e2e0370 89
WiredHome 21:f3818e2e0370 90 //
WiredHome 21:f3818e2e0370 91 // MBED OS 5
WiredHome 21:f3818e2e0370 92 //
WiredHome 21:f3818e2e0370 93 #if MBED_MAJOR_VERSION == 5
WiredHome 21:f3818e2e0370 94
WiredHome 21:f3818e2e0370 95 struct NTPPacket pkt;
WiredHome 21:f3818e2e0370 96
WiredHome 21:f3818e2e0370 97 SocketAddress nist;
WiredHome 21:f3818e2e0370 98 int ret_gethostbyname = net->gethostbyname(host, &nist);
WiredHome 21:f3818e2e0370 99 INFO("gethostbyname(%s) returned %d", host, ret_gethostbyname);
WiredHome 21:f3818e2e0370 100 if (ret_gethostbyname < 0) {
WiredHome 21:f3818e2e0370 101 return NTP_DNS; // Network error on DNS lookup
WiredHome 21:f3818e2e0370 102 }
WiredHome 21:f3818e2e0370 103
WiredHome 21:f3818e2e0370 104 nist.set_port(port);
WiredHome 21:f3818e2e0370 105 INFO("set_port(%d)", port);
WiredHome 21:f3818e2e0370 106
WiredHome 21:f3818e2e0370 107 time_t tQueryTime = time(NULL);
WiredHome 21:f3818e2e0370 108 //
WiredHome 21:f3818e2e0370 109 //Prepare NTP Packet for the query:
WiredHome 21:f3818e2e0370 110 //
WiredHome 21:f3818e2e0370 111 pkt.li = 0; //Leap Indicator : No warning
WiredHome 21:f3818e2e0370 112 pkt.vn = 4; //Version Number : 4
WiredHome 21:f3818e2e0370 113 pkt.mode = 3; //Client mode
WiredHome 21:f3818e2e0370 114 pkt.stratum = 0; //Not relevant here
WiredHome 21:f3818e2e0370 115 pkt.poll = 0; //Not significant as well
WiredHome 21:f3818e2e0370 116 pkt.precision = 0; //Neither this one is
WiredHome 21:f3818e2e0370 117 pkt.rootDelay = 0; //Or this one
WiredHome 21:f3818e2e0370 118 pkt.rootDispersion = 0; //Or that one
WiredHome 21:f3818e2e0370 119 pkt.refId = 0; //...
WiredHome 21:f3818e2e0370 120 pkt.refTm_s = 0;
WiredHome 21:f3818e2e0370 121 pkt.origTm_s = 0;
WiredHome 21:f3818e2e0370 122 pkt.rxTm_s = 0;
WiredHome 21:f3818e2e0370 123 pkt.txTm_s = NTP_TIMESTAMP_DELTA + tQueryTime;
WiredHome 21:f3818e2e0370 124 pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0;
WiredHome 21:f3818e2e0370 125
WiredHome 21:f3818e2e0370 126 INFO(" ctime: %s", ctime(&tQueryTime));
WiredHome 21:f3818e2e0370 127
WiredHome 21:f3818e2e0370 128 //WARN: We are in LE format, network byte order is BE
WiredHome 21:f3818e2e0370 129 INFO(" pkt.txTm_s %08X, %u, time to send to server", pkt.txTm_s, pkt.txTm_s);
WiredHome 21:f3818e2e0370 130 pkt.txTm_s = htonl(pkt.txTm_s);
WiredHome 21:f3818e2e0370 131 INFO(" pkt.txTm_s %08X, %u, time to send to server", pkt.txTm_s, pkt.txTm_s);
WiredHome 21:f3818e2e0370 132 HexDump("sending", &pkt, sizeof(NTPPacket));
WiredHome 21:f3818e2e0370 133
WiredHome 21:f3818e2e0370 134 UDPSocket sock;
WiredHome 21:f3818e2e0370 135 nsapi_error_t ret = sock.open(net);
WiredHome 21:f3818e2e0370 136 INFO("sock.open(...) returned %d", ret);
WiredHome 21:f3818e2e0370 137
WiredHome 21:f3818e2e0370 138 sock.set_timeout(timeout);
WiredHome 21:f3818e2e0370 139
WiredHome 21:f3818e2e0370 140 int ret_send = sock.sendto(nist, (void *)&pkt, sizeof(NTPPacket));
WiredHome 21:f3818e2e0370 141 INFO("sock.sendto(...) returned %d", ret_send);
WiredHome 21:f3818e2e0370 142
WiredHome 21:f3818e2e0370 143 SocketAddress source;
WiredHome 21:f3818e2e0370 144 source.set_ip_address(nist.get_ip_address());
WiredHome 21:f3818e2e0370 145 const int n = sock.recvfrom(&source, (void *)&pkt, sizeof(NTPPacket));
WiredHome 21:f3818e2e0370 146 uint32_t destTimeStamp = NTP_TIMESTAMP_DELTA + time(NULL);
WiredHome 21:f3818e2e0370 147 INFO("recvfrom(...) returned %d", n);
WiredHome 21:f3818e2e0370 148
WiredHome 21:f3818e2e0370 149 if (pkt.stratum == 0) { //Kiss of death message : Not good !
WiredHome 21:f3818e2e0370 150 ERR("Kissed to death!");
WiredHome 21:f3818e2e0370 151 m_sock.close();
WiredHome 21:f3818e2e0370 152 return NTP_PRTCL;
WiredHome 21:f3818e2e0370 153 }
WiredHome 21:f3818e2e0370 154
WiredHome 21:f3818e2e0370 155 HexDump("received", &pkt, sizeof(NTPPacket));
WiredHome 21:f3818e2e0370 156
WiredHome 21:f3818e2e0370 157 //Correct Endianness
WiredHome 21:f3818e2e0370 158 #if 1
WiredHome 21:f3818e2e0370 159 pkt.refTm_s = ntohl( pkt.refTm_s );
WiredHome 21:f3818e2e0370 160 pkt.refTm_f = ntohl( pkt.refTm_f );
WiredHome 21:f3818e2e0370 161 pkt.origTm_s = ntohl( pkt.origTm_s );
WiredHome 21:f3818e2e0370 162 pkt.origTm_f = ntohl( pkt.origTm_f );
WiredHome 21:f3818e2e0370 163 pkt.rxTm_s = ntohl( pkt.rxTm_s );
WiredHome 21:f3818e2e0370 164 pkt.rxTm_f = ntohl( pkt.rxTm_f );
WiredHome 21:f3818e2e0370 165 pkt.txTm_s = ntohl( pkt.txTm_s );
WiredHome 21:f3818e2e0370 166 pkt.txTm_f = ntohl( pkt.txTm_f );
WiredHome 21:f3818e2e0370 167 #endif
WiredHome 21:f3818e2e0370 168
WiredHome 21:f3818e2e0370 169 #ifdef DEBUG
WiredHome 21:f3818e2e0370 170 const char *ModeList[] = {
WiredHome 21:f3818e2e0370 171 "reserved", "symmetric active", "symmetric passive", "client",
WiredHome 21:f3818e2e0370 172 "server", "broadcast", "reserved for NTP ctrl", "reserved for priv use"
WiredHome 21:f3818e2e0370 173 };
WiredHome 21:f3818e2e0370 174 INFO(" pkt.li (Leap Ind) %d", pkt.li);
WiredHome 21:f3818e2e0370 175 INFO(" pkt.vn (Vers #) %d", pkt.vn);
WiredHome 21:f3818e2e0370 176 INFO(" pkt.mode %d, mode %s", pkt.mode, ModeList[pkt.mode]);
WiredHome 21:f3818e2e0370 177 INFO(" pkt.stratum %d, 0=kiss-o'-death, 1=prim, 2=secd", pkt.stratum);
WiredHome 21:f3818e2e0370 178 INFO(" pkt.poll %d", pkt.poll);
WiredHome 21:f3818e2e0370 179 INFO(" pkt.precision %d", pkt.precision);
WiredHome 21:f3818e2e0370 180 INFO(" pkt.rootDelay %d", pkt.rootDelay);
WiredHome 21:f3818e2e0370 181 INFO(" pkt.rootDispersion %d", pkt.rootDispersion);
WiredHome 21:f3818e2e0370 182 INFO(" pkt.refId %08X, %u", pkt.refId, pkt.refId);
WiredHome 21:f3818e2e0370 183 INFO(" pkt.refTm_s %08X, %u, ref time (last set)", pkt.refTm_s, pkt.refTm_s);
WiredHome 21:f3818e2e0370 184 INFO(" pkt.origTm_s %08X, %u, time sent from client", pkt.origTm_s, pkt.origTm_s);
WiredHome 21:f3818e2e0370 185 INFO(" pkt.rxTm_s %08X, %u, time rcvd at server", pkt.rxTm_s, pkt.rxTm_s);
WiredHome 21:f3818e2e0370 186 INFO(" pkt.txTm_s %08X, %u, time sent from server", pkt.txTm_s, pkt.txTm_s);
WiredHome 21:f3818e2e0370 187 INFO(" pkt.refTm_f %08X, %u, fraction", pkt.refTm_f, pkt.refTm_f);
WiredHome 21:f3818e2e0370 188 #endif
WiredHome 21:f3818e2e0370 189
WiredHome 21:f3818e2e0370 190 ret = sock.close();
WiredHome 21:f3818e2e0370 191 INFO("sock.close() returned %d", ret);
WiredHome 21:f3818e2e0370 192
WiredHome 21:f3818e2e0370 193 if (n == sizeof(NTPPacket)) {
WiredHome 21:f3818e2e0370 194 int64_t t;
WiredHome 21:f3818e2e0370 195 #ifdef DEBUG
WiredHome 21:f3818e2e0370 196 uint32_t T1, T2, T3, T4;
WiredHome 21:f3818e2e0370 197 T1 = pkt.origTm_s;
WiredHome 21:f3818e2e0370 198 T2 = pkt.rxTm_s;
WiredHome 21:f3818e2e0370 199 T3 = pkt.txTm_s;
WiredHome 21:f3818e2e0370 200 T4 = destTimeStamp;
WiredHome 21:f3818e2e0370 201
WiredHome 21:f3818e2e0370 202 uint32_t d = (T4 - T1) - (T3 - T2);
WiredHome 21:f3818e2e0370 203 INFO("d = %d = (%d - %d) - (%d - %d)", d, T4,T1,T3,T2);
WiredHome 21:f3818e2e0370 204 INFO("d = %d = ( %d ) - ( %d )", d, (T4-T1), (T3-T2));
WiredHome 21:f3818e2e0370 205 t = ((T2 - T1) + (T3 - T4))/2;
WiredHome 21:f3818e2e0370 206 INFO("t = %lld = ((%d - %d) + (%d - %d)) / 2;", t, T2,T1,T3,T4);
WiredHome 21:f3818e2e0370 207 INFO("t = %lld = (( %d ) + ( %d )) / 2", t, (T2-T1), (T3-T4));
WiredHome 21:f3818e2e0370 208 #endif
WiredHome 21:f3818e2e0370 209
WiredHome 21:f3818e2e0370 210 // Modification by David Smart
WiredHome 21:f3818e2e0370 211 // The setTime function was computing the offset incorrectly as the value was promoted to 64-bit.
WiredHome 21:f3818e2e0370 212 // The side effect was that a negative offset ended up as a very large positive (e.g. jump from
WiredHome 21:f3818e2e0370 213 // 2016 to 2084). This change revises that computation.
WiredHome 21:f3818e2e0370 214 t = (((int64_t)pkt.rxTm_s - pkt.origTm_s) + ((int64_t)pkt.txTm_s - destTimeStamp))/2;
WiredHome 21:f3818e2e0370 215 set_time( time(NULL) + t );
WiredHome 21:f3818e2e0370 216 } else {
WiredHome 21:f3818e2e0370 217 ERR("bad return from recvfrom() %d", n);
WiredHome 21:f3818e2e0370 218 if (n < 0) {
WiredHome 21:f3818e2e0370 219 // Network error
WiredHome 21:f3818e2e0370 220 return NTP_CONN;
WiredHome 21:f3818e2e0370 221 } else {
WiredHome 21:f3818e2e0370 222 // No or partial data returned
WiredHome 21:f3818e2e0370 223 return NTP_PRTCL;
WiredHome 21:f3818e2e0370 224 }
WiredHome 21:f3818e2e0370 225 }
WiredHome 21:f3818e2e0370 226
WiredHome 21:f3818e2e0370 227 #else // MBED OS 2
WiredHome 21:f3818e2e0370 228
WiredHome 21:f3818e2e0370 229 //Create & bind socket
WiredHome 21:f3818e2e0370 230 INFO("Binding socket");
WiredHome 21:f3818e2e0370 231 m_sock.bind(0); //Bind to a random port
WiredHome 21:f3818e2e0370 232
WiredHome 21:f3818e2e0370 233 //
WiredHome 21:f3818e2e0370 234 // MBED OS 2
WiredHome 21:f3818e2e0370 235 //
WiredHome 21:f3818e2e0370 236 m_sock.set_blocking(false, timeout); //Set not blocking
WiredHome 21:f3818e2e0370 237
WiredHome 21:f3818e2e0370 238 struct NTPPacket pkt;
WiredHome 21:f3818e2e0370 239
WiredHome 21:f3818e2e0370 240 //Now ping the server and wait for response
WiredHome 21:f3818e2e0370 241 INFO("Ping");
WiredHome 21:f3818e2e0370 242 //Prepare NTP Packet:
WiredHome 21:f3818e2e0370 243 pkt.li = 0; //Leap Indicator : No warning
WiredHome 21:f3818e2e0370 244 pkt.vn = 4; //Version Number : 4
WiredHome 21:f3818e2e0370 245 pkt.mode = 3; //Client mode
WiredHome 21:f3818e2e0370 246 pkt.stratum = 0; //Not relevant here
WiredHome 21:f3818e2e0370 247 pkt.poll = 0; //Not significant as well
WiredHome 21:f3818e2e0370 248 pkt.precision = 0; //Neither this one is
WiredHome 21:f3818e2e0370 249
WiredHome 21:f3818e2e0370 250 pkt.rootDelay = 0; //Or this one
WiredHome 21:f3818e2e0370 251 pkt.rootDispersion = 0; //Or that one
WiredHome 21:f3818e2e0370 252 pkt.refId = 0; //...
WiredHome 21:f3818e2e0370 253
WiredHome 21:f3818e2e0370 254 pkt.refTm_s = 0;
WiredHome 21:f3818e2e0370 255 pkt.origTm_s = 0;
WiredHome 21:f3818e2e0370 256 pkt.rxTm_s = 0;
WiredHome 21:f3818e2e0370 257 pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE
WiredHome 21:f3818e2e0370 258 INFO("pkt.txTm_s = %u", ntohl(pkt.txTm_s) );
WiredHome 21:f3818e2e0370 259 pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0;
WiredHome 21:f3818e2e0370 260
WiredHome 21:f3818e2e0370 261 HexDump("NTP Post", (uint8_t *)&pkt, sizeof(NTPPacket));
WiredHome 21:f3818e2e0370 262
WiredHome 21:f3818e2e0370 263 Endpoint outEndpoint;
WiredHome 21:f3818e2e0370 264 INFO("outEndpoint instantiated");
WiredHome 21:f3818e2e0370 265 if( outEndpoint.set_address(host, port) < 0) {
WiredHome 21:f3818e2e0370 266 m_sock.close();
WiredHome 21:f3818e2e0370 267 return NTP_DNS;
WiredHome 21:f3818e2e0370 268 }
WiredHome 21:f3818e2e0370 269 INFO("outEndpoint: %s:%d", outEndpoint.get_address(), outEndpoint.get_port());
WiredHome 21:f3818e2e0370 270 //Set timeout, non-blocking and wait using select
WiredHome 21:f3818e2e0370 271 int ret = m_sock.sendTo( outEndpoint, (char*)&pkt, sizeof(NTPPacket) );
WiredHome 21:f3818e2e0370 272 if (ret < 0 ) {
WiredHome 21:f3818e2e0370 273 ERR("Could not send packet");
WiredHome 21:f3818e2e0370 274 m_sock.close();
WiredHome 21:f3818e2e0370 275 return NTP_CONN;
WiredHome 21:f3818e2e0370 276 }
WiredHome 21:f3818e2e0370 277
WiredHome 21:f3818e2e0370 278 //Read response
WiredHome 21:f3818e2e0370 279 Endpoint inEndpoint;
WiredHome 21:f3818e2e0370 280 INFO(" inEndpoint instantiated: %s.", inEndpoint.get_address());
WiredHome 21:f3818e2e0370 281 // Set the inEndpoint address property
WiredHome 21:f3818e2e0370 282 inEndpoint.set_address(outEndpoint.get_address(), 0);
WiredHome 21:f3818e2e0370 283 INFO(" inEndpoint: %s", inEndpoint.get_address());
WiredHome 21:f3818e2e0370 284
WiredHome 21:f3818e2e0370 285 INFO("Pong");
WiredHome 21:f3818e2e0370 286 int loopLimit = 20; // semi-randomly selected so it doesn't hang forever here...
WiredHome 21:f3818e2e0370 287 do {
WiredHome 21:f3818e2e0370 288 ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) );
WiredHome 21:f3818e2e0370 289 if(ret < 0) {
WiredHome 21:f3818e2e0370 290 ERR("Could not receive packet");
WiredHome 21:f3818e2e0370 291 m_sock.close();
WiredHome 21:f3818e2e0370 292 return NTP_CONN;
WiredHome 21:f3818e2e0370 293 }
WiredHome 21:f3818e2e0370 294 INFO(".");
WiredHome 21:f3818e2e0370 295 loopLimit--;
WiredHome 21:f3818e2e0370 296 } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 && loopLimit > 0);
WiredHome 21:f3818e2e0370 297
WiredHome 21:f3818e2e0370 298 if(ret < (int)sizeof(NTPPacket)) { //TODO: Accept chunks
WiredHome 21:f3818e2e0370 299 ERR("Receive packet size does not match");
WiredHome 21:f3818e2e0370 300 m_sock.close();
WiredHome 21:f3818e2e0370 301 return NTP_PRTCL;
WiredHome 21:f3818e2e0370 302 }
WiredHome 21:f3818e2e0370 303
WiredHome 21:f3818e2e0370 304 if( pkt.stratum == 0) { //Kiss of death message : Not good !
WiredHome 21:f3818e2e0370 305 ERR("Kissed to death!");
WiredHome 21:f3818e2e0370 306 m_sock.close();
WiredHome 21:f3818e2e0370 307 return NTP_PRTCL;
WiredHome 21:f3818e2e0370 308 }
WiredHome 21:f3818e2e0370 309
WiredHome 21:f3818e2e0370 310 HexDump("NTP Info", (uint8_t *)&pkt, sizeof(NTPPacket));
WiredHome 21:f3818e2e0370 311
WiredHome 21:f3818e2e0370 312 //Correct Endianness
WiredHome 21:f3818e2e0370 313 pkt.refTm_s = ntohl( pkt.refTm_s );
WiredHome 21:f3818e2e0370 314 pkt.refTm_f = ntohl( pkt.refTm_f );
WiredHome 21:f3818e2e0370 315 pkt.origTm_s = ntohl( pkt.origTm_s );
WiredHome 21:f3818e2e0370 316 pkt.origTm_f = ntohl( pkt.origTm_f );
WiredHome 21:f3818e2e0370 317 pkt.rxTm_s = ntohl( pkt.rxTm_s );
WiredHome 21:f3818e2e0370 318 pkt.rxTm_f = ntohl( pkt.rxTm_f );
WiredHome 21:f3818e2e0370 319 pkt.txTm_s = ntohl( pkt.txTm_s );
WiredHome 21:f3818e2e0370 320 pkt.txTm_f = ntohl( pkt.txTm_f );
WiredHome 21:f3818e2e0370 321
WiredHome 21:f3818e2e0370 322 //Compute offset, see RFC 4330 p.13
WiredHome 21:f3818e2e0370 323 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL));
WiredHome 21:f3818e2e0370 324 INFO("destTm_s = %u", destTm_s);
WiredHome 21:f3818e2e0370 325 INFO("pkt.txTm_s = %u", pkt.txTm_s );
WiredHome 21:f3818e2e0370 326
WiredHome 21:f3818e2e0370 327 // Modification by David Smart
WiredHome 21:f3818e2e0370 328 // The setTime function was computing the offset incorrectly as the value was promoted to 64-bit.
WiredHome 21:f3818e2e0370 329 // The side effect was that a negative offset ended up as a very large positive (e.g. jump from
WiredHome 21:f3818e2e0370 330 // 2016 to 2084). This change revises that computation.
WiredHome 21:f3818e2e0370 331 int64_t offset = ( ((int64_t)pkt.rxTm_s - pkt.origTm_s ) + ((int64_t) pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow
WiredHome 21:f3818e2e0370 332
WiredHome 21:f3818e2e0370 333 // delay is not needed, this was for diagnostic purposes only.
WiredHome 21:f3818e2e0370 334 //int64_t delay = ((int64_t) destTm_s - pkt.origTm_s) - ((int64_t) pkt.txTm_s - pkt.rxTm_s);
WiredHome 21:f3818e2e0370 335 INFO("txTm_s @%u", pkt.txTm_s);
WiredHome 21:f3818e2e0370 336 INFO("origTm_s @%u", pkt.origTm_s);
WiredHome 21:f3818e2e0370 337 INFO("rxTm_s @%u", pkt.rxTm_s);
WiredHome 21:f3818e2e0370 338 INFO("destTm_s @%u", destTm_s);
WiredHome 21:f3818e2e0370 339 INFO("Offset: %lld", offset);
WiredHome 21:f3818e2e0370 340 //INFO("Delay: %lld", delay);
WiredHome 21:f3818e2e0370 341 INFO(" time: %u", time(NULL));
WiredHome 21:f3818e2e0370 342 //Set time accordingly
WiredHome 21:f3818e2e0370 343 set_time( time(NULL) + offset );
WiredHome 21:f3818e2e0370 344
WiredHome 21:f3818e2e0370 345 m_sock.close();
WiredHome 21:f3818e2e0370 346 #endif // OS version
WiredHome 21:f3818e2e0370 347
WiredHome 21:f3818e2e0370 348 #ifdef DEBUG
WiredHome 21:f3818e2e0370 349 ctTime = time(NULL);
WiredHome 21:f3818e2e0370 350 INFO(" ctime: %s", ctime(&ctTime));
WiredHome 21:f3818e2e0370 351 #endif
WiredHome 21:f3818e2e0370 352 return NTP_OK;
WiredHome 21:f3818e2e0370 353 }
WiredHome 21:f3818e2e0370 354