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.
Dependents: CI-data-logger-server WattEye X10Svr SSDP_Server
Revision 27:67e4e2ab048a, committed 2020-01-12
- Comitter:
- WiredHome
- Date:
- Sun Jan 12 19:04:47 2020 +0000
- Parent:
- 26:9ee3fac64626
- Child:
- 28:3fa154ab6ffd
- Commit message:
- Update working to code-align the OS2 and OS5 variant for the time query.
Changed in this revision
NTPClient/NTPClient.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/NTPClient/NTPClient.cpp Mon Jan 14 03:17:30 2019 +0000 +++ b/NTPClient/NTPClient.cpp Sun Jan 12 19:04:47 2020 +0000 @@ -87,10 +87,11 @@ INFO("Time is currently (UTC): %s", ctime(&ctTime)); #endif +#if MBED_MAJOR_VERSION == 5 + // // MBED OS 5 // -#if MBED_MAJOR_VERSION == 5 struct NTPPacket pkt; @@ -120,42 +121,38 @@ pkt.refTm_s = 0; pkt.origTm_s = 0; pkt.rxTm_s = 0; - pkt.txTm_s = NTP_TIMESTAMP_DELTA + tQueryTime; + pkt.txTm_s = NTP_TIMESTAMP_DELTA + tQueryTime; //WARN: We are in LE format, network byte order is BE pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0; - - INFO(" ctime: %s", ctime(&tQueryTime)); + HexDump("NTP Post", (uint8_t *)&pkt, sizeof(NTPPacket)); + pkt.txTm_s = htonl(pkt.txTm_s); - //WARN: We are in LE format, network byte order is BE - INFO(" pkt.txTm_s %08X, %u, time to send to server", pkt.txTm_s, pkt.txTm_s); - pkt.txTm_s = htonl(pkt.txTm_s); - INFO(" pkt.txTm_s %08X, %u, time to send to server", pkt.txTm_s, pkt.txTm_s); - HexDump("sending", &pkt, sizeof(NTPPacket)); - + // Contact the server UDPSocket sock; nsapi_error_t ret = sock.open(net); INFO("sock.open(...) returned %d", ret); - - sock.set_timeout(timeout); + sock.set_timeout(timeout); //Set timeout, non-blocking and wait using select + // Send the query int ret_send = sock.sendto(nist, (void *)&pkt, sizeof(NTPPacket)); INFO("sock.sendto(...) returned %d", ret_send); SocketAddress source; + + // Set the inEndpoint address property source.set_ip_address(nist.get_ip_address()); const int n = sock.recvfrom(&source, (void *)&pkt, sizeof(NTPPacket)); uint32_t destTimeStamp = NTP_TIMESTAMP_DELTA + time(NULL); INFO("recvfrom(...) returned %d", n); - + if (pkt.stratum == 0) { //Kiss of death message : Not good ! ERR("Kissed to death!"); - m_sock.close(); + sock.close(); return NTP_PRTCL; } - - HexDump("received", &pkt, sizeof(NTPPacket)); - + + HexDump("NTP Info", (uint8_t *)&pkt, sizeof(NTPPacket)); + //Correct Endianness - #if 1 pkt.refTm_s = ntohl( pkt.refTm_s ); pkt.refTm_f = ntohl( pkt.refTm_f ); pkt.origTm_s = ntohl( pkt.origTm_s ); @@ -164,7 +161,6 @@ pkt.rxTm_f = ntohl( pkt.rxTm_f ); pkt.txTm_s = ntohl( pkt.txTm_s ); pkt.txTm_f = ntohl( pkt.txTm_f ); - #endif #ifdef DEBUG const char *ModeList[] = { @@ -191,28 +187,13 @@ INFO("sock.close() returned %d", ret); if (n == sizeof(NTPPacket)) { - int64_t t; - #ifdef DEBUG - uint32_t T1, T2, T3, T4; - T1 = pkt.origTm_s; - T2 = pkt.rxTm_s; - T3 = pkt.txTm_s; - T4 = destTimeStamp; - - uint32_t d = (T4 - T1) - (T3 - T2); - INFO("d = %d = (%d - %d) - (%d - %d)", d, T4,T1,T3,T2); - INFO("d = %d = ( %d ) - ( %d )", d, (T4-T1), (T3-T2)); - t = ((T2 - T1) + (T3 - T4))/2; - INFO("t = %lld = ((%d - %d) + (%d - %d)) / 2;", t, T2,T1,T3,T4); - INFO("t = %lld = (( %d ) + ( %d )) / 2", t, (T2-T1), (T3-T4)); - #endif // Modification by David Smart // The setTime function was computing the offset incorrectly as the value was promoted to 64-bit. // The side effect was that a negative offset ended up as a very large positive (e.g. jump from // 2016 to 2084). This change revises that computation. - t = (((int64_t)pkt.rxTm_s - pkt.origTm_s) + ((int64_t)pkt.txTm_s - destTimeStamp))/2; - set_time( time(NULL) + t ); + int64_t offset = (((int64_t)pkt.rxTm_s - pkt.origTm_s) + ((int64_t)pkt.txTm_s - destTimeStamp))/2; + set_time( time(NULL) + offset ); } else { ERR("bad return from recvfrom() %d", n); if (n < 0) { @@ -226,49 +207,56 @@ #else // MBED OS 2 - //Create & bind socket - INFO("Binding socket"); - m_sock.bind(0); //Bind to a random port - // // MBED OS 2 // - m_sock.set_blocking(false, timeout); //Set not blocking struct NTPPacket pkt; - //Now ping the server and wait for response - INFO("Ping"); - //Prepare NTP Packet: - pkt.li = 0; //Leap Indicator : No warning - pkt.vn = 4; //Version Number : 4 - pkt.mode = 3; //Client mode - pkt.stratum = 0; //Not relevant here - pkt.poll = 0; //Not significant as well - pkt.precision = 0; //Neither this one is + Endpoint nist; + int ret_gethostbyname = nist.set_address(host, port); + INFO("gethostbyname(%s) returned %d", host, ret_gethostbyname); + if (ret_gethostbyname < 0) { + m_sock.close(); + return NTP_DNS; // Network error on DNS lookup + } + INFO("nist: %s:%d", nist.get_address(), nist.get_port()); + + //Create & bind socket + INFO("Binding socket"); + m_sock.bind(0); //Bind to a random port + m_sock.set_blocking(false, timeout); //Set not blocking - pkt.rootDelay = 0; //Or this one + time_t tQueryTime = time(NULL); + // + //Prepare NTP Packet for the query: + // + pkt.li = 0; //Leap Indicator : No warning + pkt.vn = 4; //Version Number : 4 + pkt.mode = 3; //Client mode + pkt.stratum = 0; //Not relevant here + pkt.poll = 0; //Not significant as well + pkt.precision = 0; //Neither this one is + pkt.rootDelay = 0; //Or this one pkt.rootDispersion = 0; //Or that one - pkt.refId = 0; //... - + pkt.refId = 0; //... pkt.refTm_s = 0; pkt.origTm_s = 0; pkt.rxTm_s = 0; - pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE - INFO("pkt.txTm_s = %u", ntohl(pkt.txTm_s) ); + pkt.txTm_s = NTP_TIMESTAMP_DELTA + tQueryTime; //WARN: We are in LE format, network byte order is BE pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0; - HexDump("NTP Post", (uint8_t *)&pkt, sizeof(NTPPacket)); - - Endpoint outEndpoint; - INFO("outEndpoint instantiated"); - if( outEndpoint.set_address(host, port) < 0) { - m_sock.close(); - return NTP_DNS; - } - INFO("outEndpoint: %s:%d", outEndpoint.get_address(), outEndpoint.get_port()); - //Set timeout, non-blocking and wait using select - int ret = m_sock.sendTo( outEndpoint, (char*)&pkt, sizeof(NTPPacket) ); + pkt.txTm_s = htonl(pkt.txTm_s); + + // Contact the server + // UDPSocket sock; + // nsapi_error_t ret = sock.open(net); + // INFO("sock.open(...) returned %d", ret); + // sock.set_timeout(timeout); //Set timeout, non-blocking and wait using select + + // Send the query + int ret = m_sock.sendTo(nist, (char*)&pkt, sizeof(NTPPacket)); + INFO("m_sock.sendto(...) returned %d", ret_send); if (ret < 0 ) { ERR("Could not send packet"); m_sock.close(); @@ -278,11 +266,10 @@ //Read response Endpoint inEndpoint; INFO(" inEndpoint instantiated: %s.", inEndpoint.get_address()); + // Set the inEndpoint address property - inEndpoint.set_address(outEndpoint.get_address(), 0); - INFO(" inEndpoint: %s", inEndpoint.get_address()); + inEndpoint.set_address(nist.get_address(), 0); - INFO("Pong"); int loopLimit = 20; // semi-randomly selected so it doesn't hang forever here... do { ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); @@ -293,7 +280,7 @@ } INFO("."); loopLimit--; - } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 && loopLimit > 0); + } while( strcmp(nist.get_address(), inEndpoint.get_address()) != 0 && loopLimit > 0); if(ret < (int)sizeof(NTPPacket)) { //TODO: Accept chunks ERR("Receive packet size does not match"); @@ -301,7 +288,7 @@ return NTP_PRTCL; } - if( pkt.stratum == 0) { //Kiss of death message : Not good ! + if (pkt.stratum == 0) { //Kiss of death message : Not good ! ERR("Kissed to death!"); m_sock.close(); return NTP_PRTCL; @@ -319,30 +306,40 @@ pkt.txTm_s = ntohl( pkt.txTm_s ); pkt.txTm_f = ntohl( pkt.txTm_f ); + #ifdef DEBUG + const char *ModeList[] = { + "reserved", "symmetric active", "symmetric passive", "client", + "server", "broadcast", "reserved for NTP ctrl", "reserved for priv use" + }; + INFO(" pkt.li (Leap Ind) %d", pkt.li); + INFO(" pkt.vn (Vers #) %d", pkt.vn); + INFO(" pkt.mode %d, mode %s", pkt.mode, ModeList[pkt.mode]); + INFO(" pkt.stratum %d, 0=kiss-o'-death, 1=prim, 2=secd", pkt.stratum); + INFO(" pkt.poll %d", pkt.poll); + INFO(" pkt.precision %d", pkt.precision); + INFO(" pkt.rootDelay %d", pkt.rootDelay); + INFO(" pkt.rootDispersion %d", pkt.rootDispersion); + INFO(" pkt.refId %08X, %u", pkt.refId, pkt.refId); + INFO(" pkt.refTm_s %08X, %u, ref time (last set)", pkt.refTm_s, pkt.refTm_s); + INFO(" pkt.origTm_s %08X, %u, time sent from client", pkt.origTm_s, pkt.origTm_s); + INFO(" pkt.rxTm_s %08X, %u, time rcvd at server", pkt.rxTm_s, pkt.rxTm_s); + INFO(" pkt.txTm_s %08X, %u, time sent from server", pkt.txTm_s, pkt.txTm_s); + INFO(" pkt.refTm_f %08X, %u, fraction", pkt.refTm_f, pkt.refTm_f); + #endif + //Compute offset, see RFC 4330 p.13 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL)); - INFO("destTm_s = %u", destTm_s); - INFO("pkt.txTm_s = %u", pkt.txTm_s ); - + + // Modification by David Smart // The setTime function was computing the offset incorrectly as the value was promoted to 64-bit. // The side effect was that a negative offset ended up as a very large positive (e.g. jump from // 2016 to 2084). This change revises that computation. int64_t offset = ( ((int64_t)pkt.rxTm_s - pkt.origTm_s ) + ((int64_t) pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow - - // delay is not needed, this was for diagnostic purposes only. - //int64_t delay = ((int64_t) destTm_s - pkt.origTm_s) - ((int64_t) pkt.txTm_s - pkt.rxTm_s); - INFO("txTm_s @%u", pkt.txTm_s); - INFO("origTm_s @%u", pkt.origTm_s); - INFO("rxTm_s @%u", pkt.rxTm_s); - INFO("destTm_s @%u", destTm_s); - INFO("Offset: %lld", offset); - //INFO("Delay: %lld", delay); - INFO(" time: %u", time(NULL)); - //Set time accordingly set_time( time(NULL) + offset ); m_sock.close(); + #endif // OS version #ifdef DEBUG