Andrew Boyson
/
iot
Backing up an unused program in case of future need
Diff: ntp.cpp
- Revision:
- 0:09f915e6f9f6
- Child:
- 2:06fa34661f19
diff -r 000000000000 -r 09f915e6f9f6 ntp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ntp.cpp Wed Apr 13 09:21:02 2016 +0000 @@ -0,0 +1,189 @@ +#include <mbed.h> +#include "log.h" +#include "esp.h" +#include "wifi.h" +#include "time.h" +#include "io.h" +#include "at.h" + +#define GET_TIME_INTERVAL 600 +#define RETRY_INTERVAL 60 + +#define ID 0 + +#define SIXTEENTHS_TO_ADD 1 + +Timer timer; + +struct Packet { +/* + LI: 00 no warning; 01 last minute has 61 seconds; 10 last minute has 59 seconds; 11 alarm condition (clock not synchronized) + VN: 3 = 011 + Mode: 3 = 011 for client request; 4 = 100 for server reply + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |LI | VN |Mode | Stratum | Poll | Precision | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0 0 0 1|1 0 1 1| + + Mode: If the Mode field of the request is 3 (client), the reply is set to 4 (server). + If this field is set to 1 (symmetric active), the reply is set to 2 (symmetric passive). + This allows clients configured in either client (NTP mode 3) or symmetric active (NTP mode 1) to + interoperate successfully, even if configured in possibly suboptimal ways. + + Poll: signed integer indicating the minimum interval between transmitted messages, in seconds as a power of two. + For instance, a value of six indicates a minimum interval of 64 seconds. + + Precision: signed integer indicating the precision of the various clocks, in seconds to the nearest power of two. + The value must be rounded to the next larger power of two; + for instance, a 50-Hz (20 ms) or 60-Hz (16.67 ms) power-frequency clock would be assigned the value -5 (31.25 ms), + while a 1000-Hz (1 ms) crystal-controlled clock would be assigned the value -9 (1.95 ms). + + Root Delay (rootdelay): Total round-trip delay to the reference clock, in NTP short format (16bitseconds; 16bit fraction). + + Root Dispersion (rootdisp): Total dispersion to the reference clock, in NTP short format (16bitseconds; 16bit fraction).. +*/ + union + { + uint32_t FirstLine; + struct + { + unsigned Mode : 3; + unsigned VN : 3; + unsigned LI : 2; + uint8_t Stratum; + int8_t Poll; + int8_t Precision; + }; + }; + uint32_t RootDelay; + uint32_t Dispersion; + uint32_t RefIdentifier; + + uint64_t RefTimeStamp; + uint64_t OriTimeStamp; + uint64_t RecTimeStamp; + uint64_t TraTimeStamp; +}; +static struct Packet packet; + +static uint64_t ntohll(uint64_t n) { + int testInt = 0x0001; //Big end contains 0x00; little end contains 0x01 + int *pTestInt = &testInt; + char *pTestByte = (char*)pTestInt; + char testByte = *pTestByte; //fetch the first byte + if (testByte == 0x00) return n; //If the first byte is the big end then host and network have same endianess + + union ull + { + uint64_t Whole; + char Bytes[8]; + }; + union ull h; + h.Whole = n; + + char t; + t = h.Bytes[7]; h.Bytes[7] = h.Bytes[0]; h.Bytes[0] = t; + t = h.Bytes[6]; h.Bytes[6] = h.Bytes[1]; h.Bytes[1] = t; + t = h.Bytes[5]; h.Bytes[5] = h.Bytes[2]; h.Bytes[2] = t; + t = h.Bytes[4]; h.Bytes[4] = h.Bytes[3]; h.Bytes[3] = t; + + return h.Whole; +} +uint64_t getTimeAsNtp() +{ + uint64_t ntpTime = 2208988800ULL << 32; + ntpTime += TimeGet16ths() << 28; + return ntpTime; +} +void setTimeAsNtp(uint64_t ntpTime) +{ + ntpTime -= 2208988800ULL << 32; + uint64_t time16ths = (ntpTime >> 28) + SIXTEENTHS_TO_ADD; + TimeSet16ths(time16ths); +} +void NtpInit() +{ + EspIpdReserved[ID] = true; +} +int preparePacket() +{ + memset(&packet, 0, sizeof(packet)); + packet.LI = 0; + packet.VN = 1; + packet.Mode = 3; //Client + packet.TraTimeStamp = ntohll(getTimeAsNtp()); + return 0; +} +int handlePacket() +{ + + //Handle the reply + char leap = packet.LI; + char version = packet.VN; + char mode = packet.Mode; + char stratum = packet.Stratum; + if (leap == 3) { LogF("Remote clock has a fault\r\n"); return -1; } + if (version < 1) { LogF("Version is %d\r\n", version); return -1; } + if (mode != 4) { LogF("Mode is %d\r\n", mode); return -1; } + if (stratum == 0) { LogF("Received Kiss of Death packet (stratum is 0)\r\n"); return -1; } + +/* + See http://www.eecis.udel.edu/~mills/time.html for timestamp calculations + Ori + ----t1---------t4---- RTC + \ / + -------t2---t3------- NTP + Rec Tra + offset (RTC - NTP) = (t1 + t4)/2 - (t2 + t3)/2 ==> [(t1 - t2) + (t4 - t3)] / 2 + delay = (t4 - t1) - (t3 - t2) +*/ + + //Set the RTC + setTimeAsNtp(ntohll(packet.RecTimeStamp)); + + return 0; +} +int NtpIdConnectStatus = AT_NONE; +static void outgoingMain() +{ + if (AtBusy()) return; + if (!WifiStarted()) return; + + static int firstAttempt = true; + static int result = AT_NONE; + + if (NtpIdConnectStatus == AT_SUCCESS) + { + int retryAfterFailure = timer.read() > RETRY_INTERVAL && result != AT_SUCCESS; + int repeat = timer.read() > GET_TIME_INTERVAL; + + if (firstAttempt || retryAfterFailure || repeat) + { + preparePacket(); + AtSendData(ID, sizeof(packet), &packet, &result); + firstAttempt = false; + timer.reset(); + timer.start(); + } + } + else + { + AtConnectId(ID, "UDP", "192.168.1.3", 123, &packet, sizeof(packet), &NtpIdConnectStatus); + } +} +static void incomingMain() +{ + if (EspDataAvailable == ESP_AVAILABLE && EspIpdId == ID) + { + if (EspIpdLength == sizeof(packet)) handlePacket(); + else LogF("Incorrect NTP packet length of %d bytes", EspIpdLength); + } +} +int NtpMain() +{ + outgoingMain(); + incomingMain(); + return 0; +} \ No newline at end of file