Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
udp/ntp/ntpclient.c
- Committer:
- andrewboyson
- Date:
- 2019-01-21
- Revision:
- 112:f8694d0b8858
- Child:
- 113:904b40231907
File content as of revision 112:f8694d0b8858:
#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;
}