Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Revision:
112:f8694d0b8858
Child:
113:904b40231907
diff -r 3600389d1add -r f8694d0b8858 udp/ntp/ntpclient.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/udp/ntp/ntpclient.c	Mon Jan 21 16:58:28 2019 +0000
@@ -0,0 +1,193 @@
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include      "log.h"
+#include      "clk.h"
+#include  "mstimer.h"
+#include  "clktime.h"
+#include   "clkntp.h"
+#include   "clkutc.h"
+#include   "clkgov.h"
+#include    "clktm.h"
+#include      "net.h"
+#include      "ntp.h"
+#include      "dns.h"
+#include      "ip4.h"
+#include    "ar4.h"
+#include    "ar6.h"
+#include    "arp.h"
+#include    "eth.h"
+#include    "nr4.h"
+#include    "nr6.h"
+#include "ip6addr.h"
+#include    "mac.h"
+#include "action.h"
+
+#define ONE_BILLION 1000000000ULL
+#define ONE_MILLION     1000000LL
+
+char    NtpClientServerName[DNS_MAX_LABEL_LENGTH+1]; 
+int32_t NtpClientInitialInterval;                    
+int32_t NtpClientNormalInterval;                     
+int32_t NtpClientRetryInterval;                      
+int32_t NtpClientOffsetMs;                           
+int32_t NtpClientMaxDelayMs;                         
+
+bool       NtpClientSendRequestsViaIp4 = false;
+uint32_t   NtpClientServerIp4;
+char       NtpClientServerIp6[16];
+bool       NtpClientTrace   = false;
+
+enum {
+    INTERVAL_INITIAL,
+    INTERVAL_NORMAL,
+    INTERVAL_RETRY
+};
+
+static uint64_t startNtpMs = 0;
+static int  intervalTypeNtp = INTERVAL_INITIAL;
+static bool intervalCompleteNtp()
+{
+    uint32_t interval;
+    switch(intervalTypeNtp)
+    {
+        case INTERVAL_INITIAL: interval = NtpClientInitialInterval; break;
+        case INTERVAL_NORMAL:  interval = NtpClientNormalInterval;  break;
+        case INTERVAL_RETRY:   interval = NtpClientRetryInterval;   break;
+    }
+    return MsTimerHasElapsed(startNtpMs, interval * 1000);
+}
+static void startIntervalNtp(int type)
+{
+    startNtpMs = MsTimerCount;
+    intervalTypeNtp = type;
+}
+
+void NtpClientSetClockTime(uint64_t ori, uint64_t rec, int li)
+{
+    //Check the received timestamp delay
+    int64_t oriTicks = ClkTimeFromNtpTimeStamp(ori);
+    int64_t ntpTicks = ClkTimeFromNtpTimeStamp(rec);
+    int64_t clkTicks = ClkTimeGet();
+    
+    int64_t roundTripTicks = clkTicks - oriTicks;
+    int64_t delayMs        = roundTripTicks >> CLK_TIME_ONE_MS_ISH_SHIFT;
+    int64_t limit          = NtpClientMaxDelayMs;
+    if (delayMs > limit)
+    {
+        LogTimeF("NtpClient error: delay %lld ms is greater than limit %lld ms\r\n", delayMs, limit);
+        return; 
+    }
+    
+    if (NtpClientTrace)
+    {
+        int64_t diffMs = ((int64_t)(ntpTicks - clkTicks)) >> CLK_TIME_ONE_MS_ISH_SHIFT;
+        LogTimeF("NtpClient difference (ext-int) is %lld ms\r\n", diffMs);
+    }
+    
+    //Handle the LI
+    if (li == 3) 
+    {
+        LogTimeF("NtpClient error: NTP server is not synchronised (LI = 3)\r\n");
+        return; 
+    }
+    if (li == 1 || li == 2)
+    {
+        struct tm tm;
+        ClkTimeToTmUtc(clkTicks, &tm);
+        int year1970 = tm.tm_year - 70; //1900
+        int month    = tm.tm_mon;       //0 to 11
+        ClkUtcSetNextEpochMonth1970(year1970 * 12 + month + 1); //+1 as new UTC epoch is at the start of next month
+        ClkUtcSetNextLeapForward(li == 1);
+        ClkUtcSetNextLeapEnable(true);
+    }
+    if (li == 0)
+    {
+        ClkUtcSetNextLeapEnable(false);
+    }
+    
+    //Set the clock
+    int64_t offsetTime = NtpClientOffsetMs << CLK_TIME_ONE_MS_ISH_SHIFT;
+    ClkGovSyncTime(ntpTicks + offsetTime);
+    
+    //Wait for next time
+    startIntervalNtp(INTERVAL_NORMAL);
+    ClkGovIsReceivingTime = true;
+    
+}
+
+void  NtpClientInit()
+{
+    startIntervalNtp(INTERVAL_INITIAL);
+    ClkGovIsReceivingTime = false;
+}
+
+static bool resolve4(char* server, uint32_t* pIp)
+{
+    //Check if have IP, if not, then request it and stop
+    Nr4NameToIp(server, pIp);
+    if (!*pIp)
+    {
+        Nr4MakeRequestForIpFromName(server); //The request is only repeated if made after a freeze time - call as often as you want.
+        return false;
+    }
+
+    //Check if have MAC and, if not, request it and stop
+    char mac[6];
+    Ar4IpToMac(*pIp, mac);
+    if (MacIsEmpty(mac))
+    {
+        Ar4MakeRequestForMacFromIp(*pIp); //The request is only repeated if made after a freeze time - call as often as you want.
+        return false;
+    }
+    
+    return true;
+}
+static bool resolve6(char* server, char* ip)
+{
+    //Check if have IP, if not, then request it and stop
+    Nr6NameToIp(server, ip);
+    if (Ip6AddressIsEmpty(ip))
+    {
+        Nr6MakeRequestForIpFromName(server); //The request is only repeated if made after a freeze time - call as often as you want.
+        return false;
+    }
+
+    //Check if have MAC and, if not, request it and stop
+    char mac[6];
+    Ar6IpToMac(ip, mac);
+    if (MacIsEmpty(mac))
+    {
+        Ar6MakeRequestForMacFromIp(ip); //The request is only repeated if made after a freeze time - call as often as you want.
+        return false;
+    }
+    
+    return true;
+}
+static bool haveIpAndMac(int type)
+{
+    if      (type == IPV4) return resolve4(NtpClientServerName, &NtpClientServerIp4);
+    else if (type == IPV6) return resolve6(NtpClientServerName,  NtpClientServerIp6);
+    else                   return false;
+}
+int NtpClientPollForPacketToSend(int type, void* pPacket, int* pSize)
+{
+    if (NtpClientServerName[0]) //An empty name means ntp client is not enabled
+    {
+        if (intervalCompleteNtp()) //Wait for the time out
+        {
+            bool isMulticast = NtpClientServerName[0] == '*';
+            if (isMulticast || haveIpAndMac(type))
+            {
+                ClkGovIsReceivingTime = false;
+                startIntervalNtp(INTERVAL_RETRY);
+                NtpHdrWriteRequest(pPacket, pSize);
+                
+                if (isMulticast) return MULTICAST_NTP;
+                else             return   UNICAST_NTP;
+            }
+        }
+    }
+    return DO_NOTHING;
+}
\ No newline at end of file