NTP Client library to set local time using the Internet.
Dependents: WebTimer DISCO-F746NG_light_control_system_tth
Revision 0:9282d46b9f92, committed 2020-11-11
- Comitter:
- hudakz
- Date:
- Wed Nov 11 16:50:36 2020 +0000
- Commit message:
- NTP Client library to set local time using the Internet.
Changed in this revision
NTPClient.cpp | Show annotated file Show diff for this revision Revisions of this file |
NTPClient.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 9282d46b9f92 NTPClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NTPClient.cpp Wed Nov 11 16:50:36 2020 +0000 @@ -0,0 +1,177 @@ +/* NTPClient.cpp */ +/* Copyright (C) 2012 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +//Debug is disabled by default +#if 0 +//Enable debug + +#define __DEBUG__ +#include <cstdio> +#define DBG(x, ...) std::printf("[NTPClient : DBG]"x "\r\n", ##__VA_ARGS__); +#define WARN(x, ...) std::printf("[NTPClient : WARN]"x "\r\n", ##__VA_ARGS__); +#define ERR(x, ...) std::printf("[NTPClient : ERR]"x "\r\n", ##__VA_ARGS__); + +#else + +//Disable debug +#define DBG(x, ...) +#define WARN(x, ...) +#define ERR(x, ...) +#endif + +#include "NetworkInterface.h" +#include "NTPClient.h" +#include "UDPSocket.h" +#include "mbed.h" //time() and set_time() + +#define NTP_PORT 123 +#define NTP_CLIENT_PORT 0 //Random port + +#define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900) + +NTPClient::NTPClient(NetworkInterface& _m_intf) : + m_intf(_m_intf) +{ } + +#ifdef htons +#undef htons +#endif /* htons */ + +#ifdef htonl +#undef htonl +#endif /* htonl */ + +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ + +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + +#if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)) +#define htons(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) +#define ntohs(x) htons(x) +#define htonl(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000UL) >> 8) | (((x) & 0xff000000UL) >> 24)) +#define ntohl(x) htonl(x) +#else +#define htons(x) (x) +#define htonl(x) (x) +#define ntohl(x) (x) +#define ntohs(x) (x) +#endif + +/** + * @brief + * @note + * @param + * @retval + */ +NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout) +{ +#ifdef __DEBUG__ + time_t ctTime; + ctTime = time(NULL); + set_time(ctTime); + DBG("Time is set to (UTC): %s", ctime(&ctTime)); +#endif + + SocketAddress address(0, port); + int r = m_intf.gethostbyname(host, &address); + if (r) { + printf("error: 'gethostbyname(\"%s\")' failed with code %d\r\n", host, r); + } + else + if (!address) { + printf("error: 'gethostbyname(\"%s\")' returned null IP address\r\n", host); + } + + //printf ("address: %s\n\r",address.get_ip_address()); + //Create & bind socket + if (m_sock.open(&m_intf) < 0) + printf("ERROR sock open \n\r"); + m_sock.set_timeout(timeout); + + struct NTPPacket pkt; + memset(&pkt, 0, sizeof(NTPPacket)); + + //Now ping the server and wait for response + DBG("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 + int ret = m_sock.sendto(address, (char*) &pkt, sizeof(NTPPacket)); + if (ret < 0) { + ERR("Could not send packet %d", ret); + m_sock.close(); + return NTP_CONN; + } + + //Read response + DBG("Pong"); + + ret = m_sock.recvfrom(&address, (char*) &pkt, sizeof(NTPPacket)); // LICIO + if (ret < 0) { + ERR("Could not receive packet %d", ret); + m_sock.close(); + return NTP_CONN; + } + + if (ret < sizeof(NTPPacket)) { + + //TODO: Accept chunks + ERR("Receive packet size does not match"); + m_sock.close(); + return NTP_PRTCL; + } + + if (pkt.stratum == 0) { + + //Kiss of death message : Not good ! + ERR("Kissed to death!"); + m_sock.close(); + return NTP_PRTCL; + } + + //Correct Endianness + pkt.refTm_s = ntohl(pkt.refTm_s); + pkt.refTm_f = ntohl(pkt.refTm_f); + pkt.origTm_s = ntohl(pkt.origTm_s); + pkt.origTm_f = ntohl(pkt.origTm_f); + pkt.rxTm_s = ntohl(pkt.rxTm_s); + pkt.rxTm_f = ntohl(pkt.rxTm_f); + pkt.txTm_s = ntohl(pkt.txTm_s); + pkt.txTm_f = ntohl(pkt.txTm_f); + + // see RFC 4330 p.13 + time_t txTm = (time_t) (pkt.txTm_s - NTP_TIMESTAMP_DELTA); + set_time(txTm); + +#ifdef __DEBUG__ + ctTime = time(NULL); + DBG("Time is now (UTC): %s", ctime(&ctTime)); +#endif + m_sock.close(); + + return NTP_OK; +}
diff -r 000000000000 -r 9282d46b9f92 NTPClient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NTPClient.h Wed Nov 11 16:50:36 2020 +0000 @@ -0,0 +1,97 @@ +/* NTPClient.h */ +/* Copyright (C) 2012 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** \file + * NTP Client header file + */ + +#ifndef NTPCLIENT_H_ +#define NTPCLIENT_H_ + +#include <stdint.h> +#include "UDPSocket.h" +#include "NetworkInterface.h" + +#define NTP_DEFAULT_PORT 123 +#define NTP_DEFAULT_TIMEOUT 4000 + +///NTP client results +enum NTPResult +{ + NTP_DNS, ///<Could not resolve name + NTP_PRTCL, ///<Protocol error + NTP_TIMEOUT, ///<Connection timeout + NTP_CONN, ///<Connection error + NTP_OK = 0, ///<Success +}; + +/** NTP Client to update the mbed's RTC using a remote time server +* +*/ +class NTPClient +{ +public: + /** + * Instantiate the NTP client + */ + NTPClient(NetworkInterface & _m_intf); + + /**Get current time (blocking) + Update the time using the server host + Blocks until completion + @param host NTP server IPv4 address or hostname (will be resolved via DNS) + @param port port to use; defaults to 123 + @param timeout waiting timeout in ms (osWaitForever for blocking function, not recommended) + @return 0 on success, NTP error code (<0) on failure + */ + NTPResult setTime(const char* host, uint16_t port = NTP_DEFAULT_PORT, uint32_t timeout = NTP_DEFAULT_TIMEOUT); + +private: + struct NTPPacket //See RFC 4330 for Simple NTP + { + //WARN: We are in Little Endian! Network is Big Endian! + //LSb first + unsigned mode : 3; + unsigned vn : 3; + unsigned li : 2; + + uint8_t stratum; + uint8_t poll; + uint8_t precision; + //32 bits header + + uint32_t rootDelay; + uint32_t rootDispersion; + uint32_t refId; + + uint32_t refTm_s; + uint32_t refTm_f; + uint32_t origTm_s; + uint32_t origTm_f; + uint32_t rxTm_s; + uint32_t rxTm_f; + uint32_t txTm_s; + uint32_t txTm_f; + } __attribute__ ((packed)); + + NetworkInterface & m_intf; + UDPSocket m_sock; +}; + +#endif /* NTPCLIENT_H_ */