test code for our MBED board

Dependencies:   mbed lwip

Committer:
lolpcc
Date:
Wed May 04 08:30:52 2011 +0000
Revision:
1:6877bb99aa17

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
lolpcc 1:6877bb99aa17 1 /*
lolpcc 1:6877bb99aa17 2 * SNTPClient.cpp
lolpcc 1:6877bb99aa17 3 * SNTP (Simple NTP) client
lolpcc 1:6877bb99aa17 4 * Written by iva2k
lolpcc 1:6877bb99aa17 5 *
lolpcc 1:6877bb99aa17 6 * Wrapper around LWIP/sntp for MBED, with DST rules.
lolpcc 1:6877bb99aa17 7 * This implementation relies on:
lolpcc 1:6877bb99aa17 8 * 1. LWIP (http://www.sics.se/~adam/lwip/) adopted for MBED
lolpcc 1:6877bb99aa17 9 * http://mbed.org/projects/cookbook/svn/EMAC/lwip/trunk
lolpcc 1:6877bb99aa17 10 * 2. LWIP's contributed SNTP client (sntp.c and sntp.h) from
lolpcc 1:6877bb99aa17 11 * http://cvs.savannah.gnu.org/viewvc/contrib/apps/sntp/?root=lwip
lolpcc 1:6877bb99aa17 12 * (used version 1.8)
lolpcc 1:6877bb99aa17 13 *
lolpcc 1:6877bb99aa17 14 * Changes needed in LWIP/sntp:
lolpcc 1:6877bb99aa17 15 * - pointer typecast (line 594) - fixes mbed compiler problem
lolpcc 1:6877bb99aa17 16 * - #include "sntp.h" moved after lwip/opt.h et.al - for re-defines.
lolpcc 1:6877bb99aa17 17 * - pbuf_free(p) in sntp_send_request() (line 602) - fixes memory leak BUG.
lolpcc 1:6877bb99aa17 18 * - changing sntp_dns_found() to delayed sntp_try_next_server() - to unblock if network is disconnected.
lolpcc 1:6877bb99aa17 19 *
lolpcc 1:6877bb99aa17 20 * Changes in MBED's LWIP:
lolpcc 1:6877bb99aa17 21 * - modified lwipopts.h (this file is automatically included into sntp.c)
lolpcc 1:6877bb99aa17 22 *
lolpcc 1:6877bb99aa17 23 * Requirements:
lolpcc 1:6877bb99aa17 24 * + direct RTC update from receiving the NTP time packet
lolpcc 1:6877bb99aa17 25 * + optionally support more than one NTP server
lolpcc 1:6877bb99aa17 26 * + the IP address of the NTP server(s) stored in a local file
lolpcc 1:6877bb99aa17 27 * + timeout error recovery should the NTP server(s) not be available. No RTC update should the NTP access fail
lolpcc 1:6877bb99aa17 28 * + allow for a UTC offset, also stored in the local file
lolpcc 1:6877bb99aa17 29 * + DST correction
lolpcc 1:6877bb99aa17 30 * + use DNS for NTP servers IP address resolution
lolpcc 1:6877bb99aa17 31 * + periodic updates at specified time intervals
lolpcc 1:6877bb99aa17 32 *
lolpcc 1:6877bb99aa17 33 * TODO:
lolpcc 1:6877bb99aa17 34 * . DST correction
lolpcc 1:6877bb99aa17 35 * - record metrics (count of updates, failed tries?, correction more than epsilon, etc.?)
lolpcc 1:6877bb99aa17 36 */
lolpcc 1:6877bb99aa17 37
lolpcc 1:6877bb99aa17 38 #include "mbed.h"
lolpcc 1:6877bb99aa17 39 #include "lwip/opt.h"
lolpcc 1:6877bb99aa17 40 #include "SNTPClient.h"
lolpcc 1:6877bb99aa17 41 #include "useful.h"
lolpcc 1:6877bb99aa17 42
lolpcc 1:6877bb99aa17 43 #define SNTP_EPSILON 10 // time difference noticed as big update (in seconds).
lolpcc 1:6877bb99aa17 44
lolpcc 1:6877bb99aa17 45 //#define SNTP_DST_TESTS // Define this to run DST algorithms tests
lolpcc 1:6877bb99aa17 46
lolpcc 1:6877bb99aa17 47 typedef struct DST_ZONE_DESCR {
lolpcc 1:6877bb99aa17 48 tDST_ZONE zone;
lolpcc 1:6877bb99aa17 49 const char *name;
lolpcc 1:6877bb99aa17 50 int gmt;
lolpcc 1:6877bb99aa17 51 int dst;
lolpcc 1:6877bb99aa17 52 int hr1;
lolpcc 1:6877bb99aa17 53 int wk1;
lolpcc 1:6877bb99aa17 54 int wday1;
lolpcc 1:6877bb99aa17 55 int mon1;
lolpcc 1:6877bb99aa17 56 int hr2;
lolpcc 1:6877bb99aa17 57 int wk2;
lolpcc 1:6877bb99aa17 58 int wday2;
lolpcc 1:6877bb99aa17 59 int mon2;
lolpcc 1:6877bb99aa17 60 pFncDstCalc fnc;
lolpcc 1:6877bb99aa17 61 } tDST_ZONE_DESR;
lolpcc 1:6877bb99aa17 62
lolpcc 1:6877bb99aa17 63 static tDST_ZONE_DESR gSntpDstZones[] = {
lolpcc 1:6877bb99aa17 64 #define _(z, fnc, gmt, dst, hr1,wk1,wday1,mon1, hr2,wk2,wday2,mon2) \
lolpcc 1:6877bb99aa17 65 { z, #z, gmt, dst, hr1,wk1,wday1,mon1, hr2,wk2,wday2,mon2, fnc },
lolpcc 1:6877bb99aa17 66 #include "DstZones.h"
lolpcc 1:6877bb99aa17 67 };
lolpcc 1:6877bb99aa17 68 #define DST_ZONE_DESCR_CNT (sizeof(gSntpDstZones)/sizeof(gSntpDstZones[0]))
lolpcc 1:6877bb99aa17 69
lolpcc 1:6877bb99aa17 70 const char *SNTPDstZoneName(tDST_ZONE zone) {
lolpcc 1:6877bb99aa17 71 if (zone >= DST_ZONE_DESCR_CNT)
lolpcc 1:6877bb99aa17 72 return "";
lolpcc 1:6877bb99aa17 73 return gSntpDstZones[zone].name;
lolpcc 1:6877bb99aa17 74 }
lolpcc 1:6877bb99aa17 75 #ifdef __cplusplus
lolpcc 1:6877bb99aa17 76 extern "C" {
lolpcc 1:6877bb99aa17 77 #endif
lolpcc 1:6877bb99aa17 78 tDST_ZONE gSntpDstZone = DST_NONE; // DST zone - rule selector
lolpcc 1:6877bb99aa17 79 unsigned int gSntpRecvTimeout_s = 3; // 3 sec; SNTP_RECV_TIMEOUT
lolpcc 1:6877bb99aa17 80 unsigned int gSntpUpdateDelay_s = 3600; // 1 hour; SNTP_UPDATE_DELAY
lolpcc 1:6877bb99aa17 81 signed int gSntpTimezone = 0*3600; // seconds from UTC to local time
lolpcc 1:6877bb99aa17 82 signed int gSntpDST = 0*3600; // seconds from UTC to local time
lolpcc 1:6877bb99aa17 83 bool gSntpRtcUtc = false; // true to keep RTC in UTC, false to keep in local time
lolpcc 1:6877bb99aa17 84 unsigned int gSntpUpdates = 0; // Track number of all clock NTP updates
lolpcc 1:6877bb99aa17 85 unsigned int gSntpUpdatesBig = 0; // Track number of significant clock NTP updates
lolpcc 1:6877bb99aa17 86 bool gSntpRunning = false; // true if SNTP service is running
lolpcc 1:6877bb99aa17 87 Timeout gSntpDelay; // For async calls.
lolpcc 1:6877bb99aa17 88 Ticker gSntpTicker; // There is no RTC interrupt on MBED (yet). Use (more wastefull) timer.
lolpcc 1:6877bb99aa17 89 time_t gSntpRtcTCR = 0; // Timer Capture Register equivalent (in RTC time - either local or UTC depending on gSntpRtcUtc)
lolpcc 1:6877bb99aa17 90 signed int gSntpRtcTCRDST = 0; // New DST value for when RTC crosses gSntpRtcTCR
lolpcc 1:6877bb99aa17 91
lolpcc 1:6877bb99aa17 92 static void SNTPSetDSTEx(unsigned int dst, bool adjust_clock) {
lolpcc 1:6877bb99aa17 93 if (adjust_clock && !gSntpRtcUtc && gSntpDST != dst) {
lolpcc 1:6877bb99aa17 94 time_t seconds = time(NULL);
lolpcc 1:6877bb99aa17 95 seconds -= gSntpDST; // Convert from old local time
lolpcc 1:6877bb99aa17 96 seconds += dst; // Convert to new local time
lolpcc 1:6877bb99aa17 97 set_time(seconds);
lolpcc 1:6877bb99aa17 98 if (gSntpRtcTCR) {
lolpcc 1:6877bb99aa17 99 // Adjust our alarm clock
lolpcc 1:6877bb99aa17 100 gSntpRtcTCR -= gSntpDST;
lolpcc 1:6877bb99aa17 101 gSntpRtcTCR += dst;
lolpcc 1:6877bb99aa17 102 }
lolpcc 1:6877bb99aa17 103 }
lolpcc 1:6877bb99aa17 104 gSntpDST = dst;
lolpcc 1:6877bb99aa17 105 }
lolpcc 1:6877bb99aa17 106
lolpcc 1:6877bb99aa17 107 #if 0
lolpcc 1:6877bb99aa17 108 // Custom DST zone function example
lolpcc 1:6877bb99aa17 109 // USA (since 2007)
lolpcc 1:6877bb99aa17 110 // Calculate start or stop DST point for given year based on rules
lolpcc 1:6877bb99aa17 111 // tz - Timezone
lolpcc 1:6877bb99aa17 112 // year - current year. DST changes well away from year end, so does not matter what timezone.
lolpcc 1:6877bb99aa17 113 // start - DST_START for start, DST_STOP for stop
lolpcc 1:6877bb99aa17 114 // Returns DST point (in local time). DST_STOP time is in DST
lolpcc 1:6877bb99aa17 115 static tDstPoint _sntp_dst_calc_custom(int tz, int year, tDST_START start) {
lolpcc 1:6877bb99aa17 116 tDstPoint ret;
lolpcc 1:6877bb99aa17 117 struct tm t;
lolpcc 1:6877bb99aa17 118
lolpcc 1:6877bb99aa17 119 // USA: 3600; 2, Second SUN, March; 2, First SUN, November
lolpcc 1:6877bb99aa17 120 int dst = 3600; // DST shift (seconds)
lolpcc 1:6877bb99aa17 121 int hour; // Hour of the change
lolpcc 1:6877bb99aa17 122 int N; // Week in the month
lolpcc 1:6877bb99aa17 123 int wday; // Day of the week
lolpcc 1:6877bb99aa17 124 int month;
lolpcc 1:6877bb99aa17 125 if (start == DST_START) {
lolpcc 1:6877bb99aa17 126 hour = 2; // (0-23) Hour of the change
lolpcc 1:6877bb99aa17 127 N = 2-1; // 2nd in the month
lolpcc 1:6877bb99aa17 128 wday = 0; // Sunday
lolpcc 1:6877bb99aa17 129 month = 2; // March
lolpcc 1:6877bb99aa17 130 } else { // DST_STOP
lolpcc 1:6877bb99aa17 131 hour = 2; // (0-23) Hour of the change
lolpcc 1:6877bb99aa17 132 N = 1-1; // 1st in the month
lolpcc 1:6877bb99aa17 133 wday = 0; // Sunday
lolpcc 1:6877bb99aa17 134 month = 10; // November
lolpcc 1:6877bb99aa17 135 }
lolpcc 1:6877bb99aa17 136
lolpcc 1:6877bb99aa17 137 t.tm_sec = 0; // 0-59
lolpcc 1:6877bb99aa17 138 t.tm_min = 0; // 0-59
lolpcc 1:6877bb99aa17 139 t.tm_hour = hour; // 0-23
lolpcc 1:6877bb99aa17 140 t.tm_year = year - 1900; //
lolpcc 1:6877bb99aa17 141 t.tm_mon = month; // 0-11
lolpcc 1:6877bb99aa17 142 t.tm_mday = 1+N*7; // 1-31, first possible date for Nth given weekday
lolpcc 1:6877bb99aa17 143 mktime(&t); // Calculate tm_wday
lolpcc 1:6877bb99aa17 144 t.tm_mday += (wday-t.tm_wday+14)%7; // Shift to wday
lolpcc 1:6877bb99aa17 145 ret.t = mktime(&t);
lolpcc 1:6877bb99aa17 146 ret.dst = (start == DST_START) ? dst : 0;
lolpcc 1:6877bb99aa17 147 ret.dstshift = dst;
lolpcc 1:6877bb99aa17 148 return ret;
lolpcc 1:6877bb99aa17 149 }
lolpcc 1:6877bb99aa17 150 #endif
lolpcc 1:6877bb99aa17 151
lolpcc 1:6877bb99aa17 152 // Calculate start or stop DST point for given year based on rules for the DST zone
lolpcc 1:6877bb99aa17 153 // tz - Timezone
lolpcc 1:6877bb99aa17 154 // zone - DST zone
lolpcc 1:6877bb99aa17 155 // year - current year. DST changes well away from year end, so does not matter timezone.
lolpcc 1:6877bb99aa17 156 // start - DST_START for start, DST_STOP for stop
lolpcc 1:6877bb99aa17 157 // Returns DST point (in standard local time). DST_STOP time is in NOT IN DST
lolpcc 1:6877bb99aa17 158 static tDstPoint _sntp_dst_calc(int tz, tDST_ZONE zone, int year, tDST_START start) {
lolpcc 1:6877bb99aa17 159 tDstPoint ret;
lolpcc 1:6877bb99aa17 160
lolpcc 1:6877bb99aa17 161 ret.t = 0;
lolpcc 1:6877bb99aa17 162 ret.dst = 0;
lolpcc 1:6877bb99aa17 163 ret.dstshift = 0;
lolpcc 1:6877bb99aa17 164 if (zone == DST_NONE || zone >= DST_ZONE_DESCR_CNT)
lolpcc 1:6877bb99aa17 165 return ret;
lolpcc 1:6877bb99aa17 166
lolpcc 1:6877bb99aa17 167 tDST_ZONE_DESR *descr = &gSntpDstZones[zone];
lolpcc 1:6877bb99aa17 168 if (descr->fnc) {
lolpcc 1:6877bb99aa17 169 // Use custom function
lolpcc 1:6877bb99aa17 170 ret = descr->fnc(tz, year, start);
lolpcc 1:6877bb99aa17 171 } else {
lolpcc 1:6877bb99aa17 172 // Use rules
lolpcc 1:6877bb99aa17 173 struct tm t;
lolpcc 1:6877bb99aa17 174 t.tm_sec = 0; // 0-59
lolpcc 1:6877bb99aa17 175 t.tm_min = 0; // 0-59
lolpcc 1:6877bb99aa17 176 t.tm_hour = (start == DST_START) ? descr->hr1 : descr->hr2;
lolpcc 1:6877bb99aa17 177 t.tm_year = year - 1900; //
lolpcc 1:6877bb99aa17 178 t.tm_mon = (start == DST_START) ? descr->mon1 : descr->mon2; // 0-11
lolpcc 1:6877bb99aa17 179 int wk =((start == DST_START) ? descr->wk1 : descr->wk2) -1;
lolpcc 1:6877bb99aa17 180 int wday = (start == DST_START) ? descr->wday1: descr->wday2;
lolpcc 1:6877bb99aa17 181 if (wk < 0) {
lolpcc 1:6877bb99aa17 182 // For "Last in the month" - we go to next month, then move back by one week
lolpcc 1:6877bb99aa17 183 t.tm_mon += 1; // 0-11
lolpcc 1:6877bb99aa17 184 if (t.tm_mon > 11) {
lolpcc 1:6877bb99aa17 185 t.tm_mon -= 12;
lolpcc 1:6877bb99aa17 186 t.tm_year += 1;
lolpcc 1:6877bb99aa17 187 }
lolpcc 1:6877bb99aa17 188 t.tm_mday = 1+0*7; // 1-31, first possible date for Nth given weekday
lolpcc 1:6877bb99aa17 189 } else {
lolpcc 1:6877bb99aa17 190 t.tm_mday = 1+wk*7; // 1-31, first possible date for Nth given weekday
lolpcc 1:6877bb99aa17 191 }
lolpcc 1:6877bb99aa17 192 mktime(&t); // Calculate tm_wday
lolpcc 1:6877bb99aa17 193 t.tm_mday += (wday-t.tm_wday+14)%7; // Shift to wday
lolpcc 1:6877bb99aa17 194 ret.t = mktime(&t);
lolpcc 1:6877bb99aa17 195 if (wk < 0) {
lolpcc 1:6877bb99aa17 196 ret.t -= 7 * 24 * 3600;
lolpcc 1:6877bb99aa17 197 }
lolpcc 1:6877bb99aa17 198 if (descr->gmt) {
lolpcc 1:6877bb99aa17 199 ret.t += tz;
lolpcc 1:6877bb99aa17 200 }
lolpcc 1:6877bb99aa17 201 ret.dst = (start == DST_START) ? descr->dst : 0;
lolpcc 1:6877bb99aa17 202 ret.dstshift = descr->dst;
lolpcc 1:6877bb99aa17 203 }
lolpcc 1:6877bb99aa17 204 if (start == DST_STOP) {
lolpcc 1:6877bb99aa17 205 ret.t -= ret.dstshift;
lolpcc 1:6877bb99aa17 206 // this correction is due to the fact that rules are given in local time with DST,
lolpcc 1:6877bb99aa17 207 // but calculations are made in standard local time (without DST adjustment)
lolpcc 1:6877bb99aa17 208 }
lolpcc 1:6877bb99aa17 209 return ret;
lolpcc 1:6877bb99aa17 210 }
lolpcc 1:6877bb99aa17 211
lolpcc 1:6877bb99aa17 212 // Calculate desired DST point relative to now based on rules for the DST zone
lolpcc 1:6877bb99aa17 213 // tz - timezone
lolpcc 1:6877bb99aa17 214 // zone - DST zone
lolpcc 1:6877bb99aa17 215 // now - current time (standard local time = excluding DST).
lolpcc 1:6877bb99aa17 216 // index - 0 for immediate next, +1 for second next, -1 for immediate previous
lolpcc 1:6877bb99aa17 217 // Returns DST point (in standard local time)
lolpcc 1:6877bb99aa17 218 static tDstPoint _sntp_dst_point(int tz, tDST_ZONE zone, time_t now, int index) {
lolpcc 1:6877bb99aa17 219 tDstPoint ret;
lolpcc 1:6877bb99aa17 220 int year;
lolpcc 1:6877bb99aa17 221 tDST_START type;
lolpcc 1:6877bb99aa17 222 struct tm *pt = localtime(&now);
lolpcc 1:6877bb99aa17 223 ret.t = 0;
lolpcc 1:6877bb99aa17 224 ret.dst = 0;
lolpcc 1:6877bb99aa17 225 ret.dstshift = 0;
lolpcc 1:6877bb99aa17 226 if (zone == DST_NONE || zone >= DST_ZONE_DESCR_CNT)
lolpcc 1:6877bb99aa17 227 return ret;
lolpcc 1:6877bb99aa17 228
lolpcc 1:6877bb99aa17 229 // Algorithm
lolpcc 1:6877bb99aa17 230 // 1. Determine where now is in respect to current year DST points (find for index=0)
lolpcc 1:6877bb99aa17 231 // 2. Use index to shift year and type
lolpcc 1:6877bb99aa17 232 // 3. return the point
lolpcc 1:6877bb99aa17 233 // This algorithm relies on DST start date being before DST stop date in the year.
lolpcc 1:6877bb99aa17 234 year = pt->tm_year + 1900;
lolpcc 1:6877bb99aa17 235 type = DST_START;
lolpcc 1:6877bb99aa17 236 ret = _sntp_dst_calc(tz, zone, year, type);
lolpcc 1:6877bb99aa17 237 if (now > ret.t) {
lolpcc 1:6877bb99aa17 238 type = DST_STOP;
lolpcc 1:6877bb99aa17 239 ret = _sntp_dst_calc(tz, zone, year, type);
lolpcc 1:6877bb99aa17 240 if (now > ret.t) {
lolpcc 1:6877bb99aa17 241 // It is next year's start point
lolpcc 1:6877bb99aa17 242 type = DST_START;
lolpcc 1:6877bb99aa17 243 year += 1;
lolpcc 1:6877bb99aa17 244 }
lolpcc 1:6877bb99aa17 245 }
lolpcc 1:6877bb99aa17 246 // Now year and type are right for index=0
lolpcc 1:6877bb99aa17 247
lolpcc 1:6877bb99aa17 248 // Calculate where index points to - shift year and type
lolpcc 1:6877bb99aa17 249 int norm = (index > 0) ? (int)(index/2) : (int)((index-1)/2);
lolpcc 1:6877bb99aa17 250 year += norm;
lolpcc 1:6877bb99aa17 251 index -= norm*2; // Now index is (0,1)
lolpcc 1:6877bb99aa17 252 if (index) {
lolpcc 1:6877bb99aa17 253 // Flip the type
lolpcc 1:6877bb99aa17 254 type = (type == DST_START) ? DST_STOP : DST_START;
lolpcc 1:6877bb99aa17 255 }
lolpcc 1:6877bb99aa17 256
lolpcc 1:6877bb99aa17 257 ret = _sntp_dst_calc(tz, zone, year, type);
lolpcc 1:6877bb99aa17 258 return ret;
lolpcc 1:6877bb99aa17 259 // struct tm t;
lolpcc 1:6877bb99aa17 260 // t.tm_sec = 0; // 0-59
lolpcc 1:6877bb99aa17 261 // t.tm_min = 0; // 0-59
lolpcc 1:6877bb99aa17 262 // t.tm_hour = 0; // 0-23
lolpcc 1:6877bb99aa17 263 // t.tm_mday = 0; // 1-31
lolpcc 1:6877bb99aa17 264 // t.tm_mon = 0; // 0-11
lolpcc 1:6877bb99aa17 265 // t.tm_year = 2005-1900; // year since 1900
lolpcc 1:6877bb99aa17 266 // t.tm_wday = 0; // 0-6 Day of week (Sunday = 0)
lolpcc 1:6877bb99aa17 267 // t.tm_yday = 0; // Day of year (0 - 365)
lolpcc 1:6877bb99aa17 268 // t.tm_isdst = -1; // Nonzero = Daylight saving time
lolpcc 1:6877bb99aa17 269 }
lolpcc 1:6877bb99aa17 270
lolpcc 1:6877bb99aa17 271 #if defined(LWIP_DEBUG)
lolpcc 1:6877bb99aa17 272 // Print DST dates report
lolpcc 1:6877bb99aa17 273 static void _sntp_dst_dates(int tz, tDST_ZONE zone, int year) {
lolpcc 1:6877bb99aa17 274 char _buffer[64];
lolpcc 1:6877bb99aa17 275 tDstPoint r;
lolpcc 1:6877bb99aa17 276 printf("\r\nDST DATES for zone %d/%s:\r\n", (int)zone, SNTPDstZoneName(zone));
lolpcc 1:6877bb99aa17 277 r = _sntp_dst_calc(tz, zone, year, DST_START);
lolpcc 1:6877bb99aa17 278 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t));
lolpcc 1:6877bb99aa17 279 printf(" %d DST BEGINS (+%04d sec) %s\r\n", year, r.dst, _buffer);
lolpcc 1:6877bb99aa17 280
lolpcc 1:6877bb99aa17 281 r = _sntp_dst_calc(tz, zone, year, DST_STOP);
lolpcc 1:6877bb99aa17 282 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t));
lolpcc 1:6877bb99aa17 283 printf(" %d DST ENDS (+%04d sec) %s\r\n", year, r.dst, _buffer);
lolpcc 1:6877bb99aa17 284 }
lolpcc 1:6877bb99aa17 285 #endif
lolpcc 1:6877bb99aa17 286 #ifdef SNTP_DST_TESTS
lolpcc 1:6877bb99aa17 287 static void test_sntp_dst_calc(int tz, tDST_ZONE zone) {
lolpcc 1:6877bb99aa17 288 char _buffer[64];
lolpcc 1:6877bb99aa17 289 tDstPoint r;
lolpcc 1:6877bb99aa17 290 int year;
lolpcc 1:6877bb99aa17 291
lolpcc 1:6877bb99aa17 292 printf("\r\nTEST: _sntp_dst_calc(tz=%d, zone=%d/%s)\r\n", tz, (int)zone, SNTPDstZoneName(zone));
lolpcc 1:6877bb99aa17 293
lolpcc 1:6877bb99aa17 294 for (year = 1999; year < 2016; year++) {
lolpcc 1:6877bb99aa17 295 r = _sntp_dst_calc(tz, zone, year, DST_START);
lolpcc 1:6877bb99aa17 296 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t));
lolpcc 1:6877bb99aa17 297 printf(" (0,%d,start) %s %d\r\n", year, _buffer, r.dst);
lolpcc 1:6877bb99aa17 298 r = _sntp_dst_calc(tz, zone, year, DST_STOP);
lolpcc 1:6877bb99aa17 299 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t));
lolpcc 1:6877bb99aa17 300 printf(" (0,%d,stop ) %s %d\r\n", year, _buffer, r.dst);
lolpcc 1:6877bb99aa17 301 }
lolpcc 1:6877bb99aa17 302 }
lolpcc 1:6877bb99aa17 303 static void test_sntp_dst_point(int index) {
lolpcc 1:6877bb99aa17 304 char _buffer[64];
lolpcc 1:6877bb99aa17 305 struct tm t;
lolpcc 1:6877bb99aa17 306 tDstPoint r;
lolpcc 1:6877bb99aa17 307 int tz=gSntpTimezone;
lolpcc 1:6877bb99aa17 308 tDST_ZONE zone=gSntpDstZone;
lolpcc 1:6877bb99aa17 309 int year = 2009, day, month;
lolpcc 1:6877bb99aa17 310
lolpcc 1:6877bb99aa17 311 int norm = (index > 0) ? (int)(index/2) : (int)((index-1)/2);
lolpcc 1:6877bb99aa17 312 printf("\r\nTEST: _sntp_dst_point(%d) norm=%d\r\n", index, norm);
lolpcc 1:6877bb99aa17 313 t.tm_sec = 0; // 0-59
lolpcc 1:6877bb99aa17 314 t.tm_min = 0; // 0-59
lolpcc 1:6877bb99aa17 315 t.tm_hour = 9; // 0-23
lolpcc 1:6877bb99aa17 316 t.tm_year = year-1900;
lolpcc 1:6877bb99aa17 317 day = 1;
lolpcc 1:6877bb99aa17 318 for (month = 0; month < 2; month++) {
lolpcc 1:6877bb99aa17 319 t.tm_mon = month;
lolpcc 1:6877bb99aa17 320 t.tm_mday = day;
lolpcc 1:6877bb99aa17 321 t.tm_year = year-1900;
lolpcc 1:6877bb99aa17 322 r = _sntp_dst_point(tz, zone, mktime(&t), index);
lolpcc 1:6877bb99aa17 323 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t));
lolpcc 1:6877bb99aa17 324 printf(" (0,%02d/%02d/%d,%d) %s %d\r\n", month+1, day, year, index, _buffer, r.dst);
lolpcc 1:6877bb99aa17 325 }
lolpcc 1:6877bb99aa17 326 for (day = 1; day < 32; day++) {
lolpcc 1:6877bb99aa17 327 t.tm_mon = month;
lolpcc 1:6877bb99aa17 328 t.tm_mday = day;
lolpcc 1:6877bb99aa17 329 t.tm_year = year-1900;
lolpcc 1:6877bb99aa17 330 r = _sntp_dst_point(tz, zone, mktime(&t), index);
lolpcc 1:6877bb99aa17 331 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t));
lolpcc 1:6877bb99aa17 332 printf(" (0,%02d/%02d/%d,%d) %s %d\r\n", month+1, day, year, index, _buffer, r.dst);
lolpcc 1:6877bb99aa17 333 }
lolpcc 1:6877bb99aa17 334 day = 30;
lolpcc 1:6877bb99aa17 335 for (; month < 10; month++) {
lolpcc 1:6877bb99aa17 336 t.tm_mon = month;
lolpcc 1:6877bb99aa17 337 t.tm_mday = day;
lolpcc 1:6877bb99aa17 338 t.tm_year = year-1900;
lolpcc 1:6877bb99aa17 339 r = _sntp_dst_point(tz, zone, mktime(&t), index);
lolpcc 1:6877bb99aa17 340 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t));
lolpcc 1:6877bb99aa17 341 printf(" (0,%02d/%02d/%d,%d) %s %d\r\n", month+1, day, year, index, _buffer, r.dst);
lolpcc 1:6877bb99aa17 342 }
lolpcc 1:6877bb99aa17 343
lolpcc 1:6877bb99aa17 344 for (day = 1; day < 32; day++) {
lolpcc 1:6877bb99aa17 345 t.tm_mon = month;
lolpcc 1:6877bb99aa17 346 t.tm_mday = day;
lolpcc 1:6877bb99aa17 347 t.tm_year = year-1900;
lolpcc 1:6877bb99aa17 348 r = _sntp_dst_point(tz, zone, mktime(&t), index);
lolpcc 1:6877bb99aa17 349 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t));
lolpcc 1:6877bb99aa17 350 printf(" (0,%02d/%02d/%d,%d) %s %d\r\n", month+1, day, year, index, _buffer, r.dst);
lolpcc 1:6877bb99aa17 351 }
lolpcc 1:6877bb99aa17 352 }
lolpcc 1:6877bb99aa17 353 #endif // SNTP_DST_TESTS
lolpcc 1:6877bb99aa17 354 // Set current DST
lolpcc 1:6877bb99aa17 355 static void _sntp_dst_now(void) {
lolpcc 1:6877bb99aa17 356 time_t now = time(NULL);
lolpcc 1:6877bb99aa17 357 // Convert to standart local time (no DST)
lolpcc 1:6877bb99aa17 358 now = gSntpRtcUtc ? (now + gSntpTimezone) : (now - gSntpDST);
lolpcc 1:6877bb99aa17 359
lolpcc 1:6877bb99aa17 360 // Check DST setting for now
lolpcc 1:6877bb99aa17 361 tDstPoint dst = _sntp_dst_point(gSntpTimezone, gSntpDstZone, now, -1);
lolpcc 1:6877bb99aa17 362 #ifdef LWIP_DEBUG
lolpcc 1:6877bb99aa17 363 char _buffer[64];
lolpcc 1:6877bb99aa17 364 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&dst.t));
lolpcc 1:6877bb99aa17 365 LWIP_DEBUGF(SNTP_DEBUG_STATE, (
lolpcc 1:6877bb99aa17 366 "DEBUG: _sntp_dst_now(%d) based on last DST change on (%d) %s to (+%04d sec)\r\n",
lolpcc 1:6877bb99aa17 367 now, dst.t, _buffer, dst.dst));
lolpcc 1:6877bb99aa17 368 #endif
lolpcc 1:6877bb99aa17 369 // Change RTC
lolpcc 1:6877bb99aa17 370 SNTPSetDSTEx(dst.dst, true);
lolpcc 1:6877bb99aa17 371 }
lolpcc 1:6877bb99aa17 372
lolpcc 1:6877bb99aa17 373 // Plan for next DST change
lolpcc 1:6877bb99aa17 374 static void _sntp_dst_schedule(void) {
lolpcc 1:6877bb99aa17 375 time_t now = time(NULL);
lolpcc 1:6877bb99aa17 376 // Convert to standart local time (no DST)
lolpcc 1:6877bb99aa17 377 now = gSntpRtcUtc ? (now + gSntpTimezone) : (now - gSntpDST);
lolpcc 1:6877bb99aa17 378 // Check next DST change point
lolpcc 1:6877bb99aa17 379 tDstPoint dst = _sntp_dst_point(gSntpTimezone, gSntpDstZone, now, 0);
lolpcc 1:6877bb99aa17 380 if (dst.t) {
lolpcc 1:6877bb99aa17 381 #ifdef LWIP_DEBUG
lolpcc 1:6877bb99aa17 382 char _buffer[64];
lolpcc 1:6877bb99aa17 383 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&dst.t));
lolpcc 1:6877bb99aa17 384 #endif
lolpcc 1:6877bb99aa17 385
lolpcc 1:6877bb99aa17 386 // Set our alarm clock
lolpcc 1:6877bb99aa17 387 // Convert from standard local to UTC time or local time
lolpcc 1:6877bb99aa17 388 dst.t = gSntpRtcUtc ? (dst.t - gSntpTimezone) : (dst.t + gSntpDST);
lolpcc 1:6877bb99aa17 389
lolpcc 1:6877bb99aa17 390 #ifdef LWIP_DEBUG
lolpcc 1:6877bb99aa17 391 if (time(NULL) > dst.t) {
lolpcc 1:6877bb99aa17 392 LWIP_DEBUGF(SNTP_DEBUG_STATE, (
lolpcc 1:6877bb99aa17 393 "DEBUG: _sntp_dst_schedule() ASSERTION FAILED !(%d<%d) trying to schedule for the past: %s (+%04d sec)\r\n",
lolpcc 1:6877bb99aa17 394 time(NULL), dst.t, _buffer, dst.dst));
lolpcc 1:6877bb99aa17 395 } else {
lolpcc 1:6877bb99aa17 396 LWIP_DEBUGF(SNTP_DEBUG_STATE, (
lolpcc 1:6877bb99aa17 397 "DEBUG: _sntp_dst_schedule() scheduled in %d seconds, set for %s (+%04d sec)\r\n",
lolpcc 1:6877bb99aa17 398 dst.t-time(NULL), _buffer, dst.dst));
lolpcc 1:6877bb99aa17 399 }
lolpcc 1:6877bb99aa17 400 #endif
lolpcc 1:6877bb99aa17 401 }
lolpcc 1:6877bb99aa17 402 gSntpRtcTCR = dst.t;
lolpcc 1:6877bb99aa17 403 gSntpRtcTCRDST = dst.dst;
lolpcc 1:6877bb99aa17 404 }
lolpcc 1:6877bb99aa17 405
lolpcc 1:6877bb99aa17 406 // RTC ISR - called upon each RTC tick
lolpcc 1:6877bb99aa17 407 static void _sntp_isr(void) {
lolpcc 1:6877bb99aa17 408 time_t seconds = time(NULL);
lolpcc 1:6877bb99aa17 409 if (gSntpRtcTCR && seconds > gSntpRtcTCR ) {
lolpcc 1:6877bb99aa17 410 // DST change has arrived
lolpcc 1:6877bb99aa17 411 gSntpRtcTCR = 0;
lolpcc 1:6877bb99aa17 412 // Disable ISR and avoid extra calcs in SNTPSetDSTEx()
lolpcc 1:6877bb99aa17 413 //if (gSntpRtcTCRDST != gSntpDST) {
lolpcc 1:6877bb99aa17 414 // Change to/from DST
lolpcc 1:6877bb99aa17 415 SNTPSetDSTEx(gSntpRtcTCRDST, true);
lolpcc 1:6877bb99aa17 416 gSntpRtcTCRDST = 0;
lolpcc 1:6877bb99aa17 417 // Schedule callback to plan for next DST change (take it out of ISR context)
lolpcc 1:6877bb99aa17 418 gSntpDelay.attach(_sntp_dst_schedule, 1.0);
lolpcc 1:6877bb99aa17 419 #ifdef LWIP_DEBUG
lolpcc 1:6877bb99aa17 420 char _buffer[64];
lolpcc 1:6877bb99aa17 421 if (gSntpRtcUtc) {
lolpcc 1:6877bb99aa17 422 seconds += gSntpTimezone + gSntpDST; // Convert to local time
lolpcc 1:6877bb99aa17 423 }
lolpcc 1:6877bb99aa17 424 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&seconds));
lolpcc 1:6877bb99aa17 425 LWIP_DEBUGF(SNTP_DEBUG_STATE, (
lolpcc 1:6877bb99aa17 426 "DEBUG: _sntp_isr() changed DST. datetime=%s\r\n", _buffer));
lolpcc 1:6877bb99aa17 427 #endif
lolpcc 1:6877bb99aa17 428 //}
lolpcc 1:6877bb99aa17 429 }
lolpcc 1:6877bb99aa17 430 }
lolpcc 1:6877bb99aa17 431
lolpcc 1:6877bb99aa17 432 // NTP Callback - timestamp from NTP server arrives here
lolpcc 1:6877bb99aa17 433 void SntpClientSet(time_t seconds) {
lolpcc 1:6877bb99aa17 434 time_t old_seconds = time(NULL);
lolpcc 1:6877bb99aa17 435 if (!gSntpRtcUtc) {
lolpcc 1:6877bb99aa17 436 seconds += gSntpTimezone + gSntpDST; // Convert to local time
lolpcc 1:6877bb99aa17 437 }
lolpcc 1:6877bb99aa17 438 set_time(seconds);
lolpcc 1:6877bb99aa17 439
lolpcc 1:6877bb99aa17 440 // Special tasks for the very first NTP updates
lolpcc 1:6877bb99aa17 441 if (!gSntpUpdates) {
lolpcc 1:6877bb99aa17 442 #if defined(LWIP_DEBUG)
lolpcc 1:6877bb99aa17 443 // Report DST dates for the zone
lolpcc 1:6877bb99aa17 444 struct tm *pt = localtime(&seconds);
lolpcc 1:6877bb99aa17 445 _sntp_dst_dates(gSntpTimezone, gSntpDstZone, pt->tm_year+1900);
lolpcc 1:6877bb99aa17 446 #endif
lolpcc 1:6877bb99aa17 447
lolpcc 1:6877bb99aa17 448 // DST scheduler
lolpcc 1:6877bb99aa17 449 _sntp_dst_now();
lolpcc 1:6877bb99aa17 450 _sntp_dst_schedule();
lolpcc 1:6877bb99aa17 451
lolpcc 1:6877bb99aa17 452 // Enable RTC ISR
lolpcc 1:6877bb99aa17 453 gSntpTicker.attach(_sntp_isr, 1.0);
lolpcc 1:6877bb99aa17 454 }
lolpcc 1:6877bb99aa17 455 if (gSntpUpdates && abs((int)(old_seconds - seconds)) > SNTP_EPSILON) {
lolpcc 1:6877bb99aa17 456 printf("SNTP settime() corrected big difference: (%d) seconds, more than %d. Big updates count=%d.\r\n",
lolpcc 1:6877bb99aa17 457 old_seconds-seconds, SNTP_EPSILON, gSntpUpdatesBig);
lolpcc 1:6877bb99aa17 458 gSntpUpdatesBig ++;
lolpcc 1:6877bb99aa17 459 }
lolpcc 1:6877bb99aa17 460
lolpcc 1:6877bb99aa17 461 gSntpUpdates++;
lolpcc 1:6877bb99aa17 462
lolpcc 1:6877bb99aa17 463 if (1) {
lolpcc 1:6877bb99aa17 464 char _buffer[64];
lolpcc 1:6877bb99aa17 465 if (gSntpRtcUtc) {
lolpcc 1:6877bb99aa17 466 seconds += gSntpTimezone + gSntpDST; // Convert to local time
lolpcc 1:6877bb99aa17 467 }
lolpcc 1:6877bb99aa17 468 strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&seconds));
lolpcc 1:6877bb99aa17 469 printf("SNTP settime() #%d seconds=%d TZ=%0.1f datetime=%s\r\n",
lolpcc 1:6877bb99aa17 470 gSntpUpdates, seconds, gSntpTimezone/3600.0, _buffer);
lolpcc 1:6877bb99aa17 471 }
lolpcc 1:6877bb99aa17 472 }
lolpcc 1:6877bb99aa17 473 #ifdef __cplusplus
lolpcc 1:6877bb99aa17 474 };
lolpcc 1:6877bb99aa17 475 #endif
lolpcc 1:6877bb99aa17 476 #ifdef __cplusplus
lolpcc 1:6877bb99aa17 477 extern "C" {
lolpcc 1:6877bb99aa17 478 #endif
lolpcc 1:6877bb99aa17 479 #include "lwip/def.h"
lolpcc 1:6877bb99aa17 480 #include "lwip/pbuf.h"
lolpcc 1:6877bb99aa17 481 #include "lwip/sys.h"
lolpcc 1:6877bb99aa17 482 #include "lwip/stats.h"
lolpcc 1:6877bb99aa17 483 #include "netif/etharp.h"
lolpcc 1:6877bb99aa17 484 #include "string.h"
lolpcc 1:6877bb99aa17 485 #ifdef __cplusplus
lolpcc 1:6877bb99aa17 486 };
lolpcc 1:6877bb99aa17 487 #endif
lolpcc 1:6877bb99aa17 488 // Accomodating sntp timeout functions
lolpcc 1:6877bb99aa17 489 #if NO_SYS
lolpcc 1:6877bb99aa17 490 #include "sntp.h"
lolpcc 1:6877bb99aa17 491 extern void sntp_request(void *arg); // this is dirty hack around "static" function. Some linkers may revolt!
lolpcc 1:6877bb99aa17 492 extern void sntp_try_next_server(void *arg);
lolpcc 1:6877bb99aa17 493 extern char* sntp_server_addresses[];
lolpcc 1:6877bb99aa17 494 extern u8_t sntp_current_server;
lolpcc 1:6877bb99aa17 495 extern u8_t sntp_num_servers;
lolpcc 1:6877bb99aa17 496 static void (*sntp_addresses_free)(void*) = NULL;
lolpcc 1:6877bb99aa17 497 static Timeout _sntp_timer1;
lolpcc 1:6877bb99aa17 498 static Timeout _sntp_timer2;
lolpcc 1:6877bb99aa17 499 void sntp_sys_timeout(u32_t timeout_s, void (*func)(void *arg), void *arg) {
lolpcc 1:6877bb99aa17 500 // all we really need to track is only 2 functions: sntp_request, sntp_try_next_server
lolpcc 1:6877bb99aa17 501 Timeout *t = NULL;
lolpcc 1:6877bb99aa17 502 if (func == &sntp_request) {
lolpcc 1:6877bb99aa17 503 t = &_sntp_timer1;
lolpcc 1:6877bb99aa17 504 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("DEBUG: IN sntp_sys_timeout(), func=sntp_request\r\n"));
lolpcc 1:6877bb99aa17 505 } else if (func == &sntp_try_next_server) {
lolpcc 1:6877bb99aa17 506 t = &_sntp_timer2;
lolpcc 1:6877bb99aa17 507 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("DEBUG: IN sntp_sys_timeout(), func=sntp_try_next_server\r\n"));
lolpcc 1:6877bb99aa17 508 }
lolpcc 1:6877bb99aa17 509 if (t) {
lolpcc 1:6877bb99aa17 510 t->detach();
lolpcc 1:6877bb99aa17 511 t->attach((void(*)(void))func, 1.0*timeout_s);
lolpcc 1:6877bb99aa17 512 // Another shortcut - we have no arg to pass, so just typecast the func.
lolpcc 1:6877bb99aa17 513 }
lolpcc 1:6877bb99aa17 514 }
lolpcc 1:6877bb99aa17 515 void sntp_sys_untimeout(void (*func)(void *arg), void *arg) {
lolpcc 1:6877bb99aa17 516
lolpcc 1:6877bb99aa17 517 Timeout *t = NULL;
lolpcc 1:6877bb99aa17 518 if (func == &sntp_request) {
lolpcc 1:6877bb99aa17 519 t = &_sntp_timer1;
lolpcc 1:6877bb99aa17 520 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("DEBUG: IN sntp_sys_untimeout(), func=sntp_request\r\n"));
lolpcc 1:6877bb99aa17 521 } else if (func == &sntp_try_next_server) {
lolpcc 1:6877bb99aa17 522 t = &_sntp_timer2;
lolpcc 1:6877bb99aa17 523 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("DEBUG: IN sntp_sys_untimeout(), func=sntp_try_next_server\r\n"));
lolpcc 1:6877bb99aa17 524 }
lolpcc 1:6877bb99aa17 525 if (t) {
lolpcc 1:6877bb99aa17 526 t->detach();
lolpcc 1:6877bb99aa17 527 }
lolpcc 1:6877bb99aa17 528 }
lolpcc 1:6877bb99aa17 529
lolpcc 1:6877bb99aa17 530 #else // NO_SYS
lolpcc 1:6877bb99aa17 531 #error "I don't know how to compile LWIP/SNTP with NO_SYS=0"
lolpcc 1:6877bb99aa17 532 #endif // NO_SYS
lolpcc 1:6877bb99aa17 533
lolpcc 1:6877bb99aa17 534 // Can be called when already running
lolpcc 1:6877bb99aa17 535 void SNTPSetDstZone(tDST_ZONE zone) {
lolpcc 1:6877bb99aa17 536 if (zone >= DST_ZONE_DESCR_CNT)
lolpcc 1:6877bb99aa17 537 return; // ERR_INVALID_ARG
lolpcc 1:6877bb99aa17 538 gSntpDstZone = zone;
lolpcc 1:6877bb99aa17 539
lolpcc 1:6877bb99aa17 540 if (gSntpRunning) {
lolpcc 1:6877bb99aa17 541 // DST scheduler
lolpcc 1:6877bb99aa17 542 _sntp_dst_now();
lolpcc 1:6877bb99aa17 543 _sntp_dst_schedule();
lolpcc 1:6877bb99aa17 544 }
lolpcc 1:6877bb99aa17 545 }
lolpcc 1:6877bb99aa17 546
lolpcc 1:6877bb99aa17 547
lolpcc 1:6877bb99aa17 548 void SNTPSetRecvTimeout(unsigned int val_s) { gSntpRecvTimeout_s = val_s; }
lolpcc 1:6877bb99aa17 549 void SNTPSetUpdateDelay(unsigned int val_s) { gSntpUpdateDelay_s = val_s; }
lolpcc 1:6877bb99aa17 550 void SNTPSetTimezone(float hours_from_utc, bool adjust_clock) {
lolpcc 1:6877bb99aa17 551 if (adjust_clock && !gSntpRtcUtc) {
lolpcc 1:6877bb99aa17 552 time_t seconds = time(NULL);
lolpcc 1:6877bb99aa17 553 seconds -= gSntpTimezone; // Convert from old local time
lolpcc 1:6877bb99aa17 554 seconds += hours_from_utc * 3600; // Convert to new local time
lolpcc 1:6877bb99aa17 555 set_time(seconds);
lolpcc 1:6877bb99aa17 556 if (gSntpRtcTCR) {
lolpcc 1:6877bb99aa17 557 // Adjust our alarm clock
lolpcc 1:6877bb99aa17 558 gSntpRtcTCR -= gSntpTimezone;
lolpcc 1:6877bb99aa17 559 gSntpRtcTCR += hours_from_utc * 3600;
lolpcc 1:6877bb99aa17 560 }
lolpcc 1:6877bb99aa17 561 }
lolpcc 1:6877bb99aa17 562 gSntpTimezone = hours_from_utc * 3600;
lolpcc 1:6877bb99aa17 563 }
lolpcc 1:6877bb99aa17 564
lolpcc 1:6877bb99aa17 565 void SNTPSetDST(float hours_from_utc, bool adjust_clock) {
lolpcc 1:6877bb99aa17 566 SNTPSetDSTEx(hours_from_utc * 3600, adjust_clock);
lolpcc 1:6877bb99aa17 567 }
lolpcc 1:6877bb99aa17 568
lolpcc 1:6877bb99aa17 569 static int sntp_num_servers_alloc = 0;
lolpcc 1:6877bb99aa17 570
lolpcc 1:6877bb99aa17 571 static void _SNTPClrAddresses(void) {
lolpcc 1:6877bb99aa17 572 if (!sntp_num_servers_alloc) sntp_num_servers_alloc = sntp_num_servers;
lolpcc 1:6877bb99aa17 573 // Here we save the original size of the sntp_server_addresses[] array.
lolpcc 1:6877bb99aa17 574
lolpcc 1:6877bb99aa17 575 if (sntp_addresses_free) {
lolpcc 1:6877bb99aa17 576 for (int i=0; i<sntp_num_servers; i++) {
lolpcc 1:6877bb99aa17 577 sntp_addresses_free(sntp_server_addresses[i]);
lolpcc 1:6877bb99aa17 578 }
lolpcc 1:6877bb99aa17 579 }
lolpcc 1:6877bb99aa17 580 sntp_current_server = 0;
lolpcc 1:6877bb99aa17 581 sntp_num_servers = 0;
lolpcc 1:6877bb99aa17 582 sntp_addresses_free = NULL;
lolpcc 1:6877bb99aa17 583 }
lolpcc 1:6877bb99aa17 584
lolpcc 1:6877bb99aa17 585 static int _SNTPAddAddress(const char* server_address) {
lolpcc 1:6877bb99aa17 586 if (sntp_num_servers+1 > sntp_num_servers_alloc)
lolpcc 1:6877bb99aa17 587 return -1;
lolpcc 1:6877bb99aa17 588 sntp_server_addresses[sntp_num_servers] = (char*)malloc(strlen(server_address)+1);
lolpcc 1:6877bb99aa17 589 if (sntp_server_addresses[sntp_num_servers] == NULL) return -1; // Out of memory
lolpcc 1:6877bb99aa17 590 strcpy(sntp_server_addresses[sntp_num_servers], server_address);
lolpcc 1:6877bb99aa17 591 sntp_num_servers++;
lolpcc 1:6877bb99aa17 592 return 0;
lolpcc 1:6877bb99aa17 593 }
lolpcc 1:6877bb99aa17 594
lolpcc 1:6877bb99aa17 595 // Override default servers list.
lolpcc 1:6877bb99aa17 596 // For no-copy, pass pointer to free() in p_free.
lolpcc 1:6877bb99aa17 597 // Returns: actual number of servers set (limited by allocated buffer size)
lolpcc 1:6877bb99aa17 598 // WARNING! There is no interlock to ensure that SNTP service does not read its data while we are updating it.
lolpcc 1:6877bb99aa17 599 // This function is intended to be called only before SNTPClientInit().
lolpcc 1:6877bb99aa17 600
lolpcc 1:6877bb99aa17 601 int SNTPSetAddresses(const char* server_addresses[], int count, void (*p_free)(void*)) {
lolpcc 1:6877bb99aa17 602 // In order to use sntp.c as-is, we hack into its static variables.
lolpcc 1:6877bb99aa17 603 // Not all compilers/linkers will support that.
lolpcc 1:6877bb99aa17 604
lolpcc 1:6877bb99aa17 605 _SNTPClrAddresses();
lolpcc 1:6877bb99aa17 606 if (count > sntp_num_servers_alloc)
lolpcc 1:6877bb99aa17 607 count = sntp_num_servers_alloc;
lolpcc 1:6877bb99aa17 608 for (int i=0; i<count; i++) {
lolpcc 1:6877bb99aa17 609 if (p_free) {
lolpcc 1:6877bb99aa17 610 sntp_server_addresses[i] = (char *)server_addresses[i];
lolpcc 1:6877bb99aa17 611 } else {
lolpcc 1:6877bb99aa17 612 _SNTPAddAddress(server_addresses[i]);
lolpcc 1:6877bb99aa17 613 }
lolpcc 1:6877bb99aa17 614 }
lolpcc 1:6877bb99aa17 615 sntp_num_servers = count;
lolpcc 1:6877bb99aa17 616 sntp_current_server = 0;
lolpcc 1:6877bb99aa17 617 sntp_addresses_free = p_free ? p_free : &free;
lolpcc 1:6877bb99aa17 618 return count;
lolpcc 1:6877bb99aa17 619 }
lolpcc 1:6877bb99aa17 620
lolpcc 1:6877bb99aa17 621
lolpcc 1:6877bb99aa17 622 // Trim whitespace/CRLFs from both ends of a given string
lolpcc 1:6877bb99aa17 623 char * str_cleanup(char *in) {
lolpcc 1:6877bb99aa17 624 char * out = in;
lolpcc 1:6877bb99aa17 625 // Trim leading spaces and CR/LF
lolpcc 1:6877bb99aa17 626 while (*out == ' ' || *out == '\t' || *out == '\r' || *out == '\n')
lolpcc 1:6877bb99aa17 627 out ++;
lolpcc 1:6877bb99aa17 628 // Trim trailing spaces and CR/LF
lolpcc 1:6877bb99aa17 629 int len = strlen(out)-1;
lolpcc 1:6877bb99aa17 630 while (out[len] == ' ' || out[len] == '\t' || out[len] == '\r' || out[len] == '\n') {
lolpcc 1:6877bb99aa17 631 out[len] = '\0';
lolpcc 1:6877bb99aa17 632 len--;
lolpcc 1:6877bb99aa17 633 }
lolpcc 1:6877bb99aa17 634 return out;
lolpcc 1:6877bb99aa17 635 }
lolpcc 1:6877bb99aa17 636
lolpcc 1:6877bb99aa17 637
lolpcc 1:6877bb99aa17 638
lolpcc 1:6877bb99aa17 639 #ifndef CRLF
lolpcc 1:6877bb99aa17 640 #define CRLF "\r\n"
lolpcc 1:6877bb99aa17 641 #endif
lolpcc 1:6877bb99aa17 642
lolpcc 1:6877bb99aa17 643 void SNTPWriteIniFile(FILE * f) {
lolpcc 1:6877bb99aa17 644
lolpcc 1:6877bb99aa17 645 fprintf(f, "# SNTP Configuration file" CRLF);
lolpcc 1:6877bb99aa17 646 fprintf(f, CRLF "[Servers]" CRLF);
lolpcc 1:6877bb99aa17 647 for (int i=0; i<sntp_num_servers; i++) {
lolpcc 1:6877bb99aa17 648 fprintf(f, "%s" CRLF, sntp_server_addresses[i]);
lolpcc 1:6877bb99aa17 649 }
lolpcc 1:6877bb99aa17 650 fprintf(f, CRLF "[Global]" CRLF);
lolpcc 1:6877bb99aa17 651 fprintf(f, "RtcUtc=%d" CRLF, (int)gSntpRtcUtc);
lolpcc 1:6877bb99aa17 652 fprintf(f, "Timezone=%0.1f" CRLF, gSntpTimezone / 3600.0);
lolpcc 1:6877bb99aa17 653 fprintf(f, "DstZone=%d" CRLF, gSntpDstZone);
lolpcc 1:6877bb99aa17 654 fprintf(f, "# %s" CRLF, SNTPDstZoneName(gSntpDstZone));
lolpcc 1:6877bb99aa17 655 fprintf(f, "UpdateDelay=%d" CRLF, gSntpUpdateDelay_s);
lolpcc 1:6877bb99aa17 656 fprintf(f, "RecvTimeout=%d" CRLF, gSntpRecvTimeout_s);
lolpcc 1:6877bb99aa17 657 fprintf(f, CRLF "##END" CRLF);
lolpcc 1:6877bb99aa17 658 }
lolpcc 1:6877bb99aa17 659
lolpcc 1:6877bb99aa17 660 // Simple ini file parser for SNTP configuration (Case-sensitive!)
lolpcc 1:6877bb99aa17 661 // This function is intended to be called only before SNTPClientInit().
lolpcc 1:6877bb99aa17 662 // Returns: 0 if OK, errno otherwise
lolpcc 1:6877bb99aa17 663 enum {
lolpcc 1:6877bb99aa17 664 SECT_NONE,
lolpcc 1:6877bb99aa17 665 SECT_SERVERS,
lolpcc 1:6877bb99aa17 666 SECT_GLOBAL,
lolpcc 1:6877bb99aa17 667 };
lolpcc 1:6877bb99aa17 668
lolpcc 1:6877bb99aa17 669 int SNTPReadIniFile(const char* filename) {
lolpcc 1:6877bb99aa17 670 FILE *f;
lolpcc 1:6877bb99aa17 671 char buf[512];
lolpcc 1:6877bb99aa17 672 bool addresses_cleared = false;
lolpcc 1:6877bb99aa17 673
lolpcc 1:6877bb99aa17 674 f = fopen(filename, "r");
lolpcc 1:6877bb99aa17 675 if (!f)
lolpcc 1:6877bb99aa17 676 return -1; // errno not used?
lolpcc 1:6877bb99aa17 677
lolpcc 1:6877bb99aa17 678 char *buf1, *buf2;
lolpcc 1:6877bb99aa17 679 int section=SECT_NONE;
lolpcc 1:6877bb99aa17 680 int line = 0;
lolpcc 1:6877bb99aa17 681 while (fgets(buf, sizeof(buf)/sizeof(buf[0]), f)) {
lolpcc 1:6877bb99aa17 682 line++;
lolpcc 1:6877bb99aa17 683 buf1 = str_cleanup(buf);
lolpcc 1:6877bb99aa17 684 if (*buf1 == '#' || *buf1 == '\0')
lolpcc 1:6877bb99aa17 685 continue; // Comment line or empty line - skip
lolpcc 1:6877bb99aa17 686 if (*buf1 == '[') {
lolpcc 1:6877bb99aa17 687 // New section
lolpcc 1:6877bb99aa17 688 if (0 == strncmp(buf1,"[Servers]", sizeof("[Servers]")-1)) {
lolpcc 1:6877bb99aa17 689 section=SECT_SERVERS;
lolpcc 1:6877bb99aa17 690 if (!addresses_cleared) {
lolpcc 1:6877bb99aa17 691 // Clear addresses only once.
lolpcc 1:6877bb99aa17 692 _SNTPClrAddresses();
lolpcc 1:6877bb99aa17 693 addresses_cleared = true;
lolpcc 1:6877bb99aa17 694 }
lolpcc 1:6877bb99aa17 695 } else if (0 == strncmp(buf1,"[Global]", sizeof("[Global]")-1)) {
lolpcc 1:6877bb99aa17 696 section=SECT_GLOBAL;
lolpcc 1:6877bb99aa17 697 } else {
lolpcc 1:6877bb99aa17 698 section=SECT_NONE;
lolpcc 1:6877bb99aa17 699 fprintf(stderr, "File \"%s\", line %d - section \"%s\" is not understood.\r\n", filename, line, buf1);
lolpcc 1:6877bb99aa17 700 }
lolpcc 1:6877bb99aa17 701 } else {
lolpcc 1:6877bb99aa17 702 // Section values
lolpcc 1:6877bb99aa17 703 switch (section) {
lolpcc 1:6877bb99aa17 704 case SECT_SERVERS:
lolpcc 1:6877bb99aa17 705 if (_SNTPAddAddress(buf1)) {
lolpcc 1:6877bb99aa17 706 fprintf(stderr, "File \"%s\", line %d - cannot add server \"%s\" - exceeded allocated slots.\r\n", filename, line, buf1);
lolpcc 1:6877bb99aa17 707 }
lolpcc 1:6877bb99aa17 708 break;
lolpcc 1:6877bb99aa17 709 case SECT_GLOBAL:
lolpcc 1:6877bb99aa17 710 buf2 = strchr(buf1, '=');
lolpcc 1:6877bb99aa17 711 if (buf2) {
lolpcc 1:6877bb99aa17 712 *buf2++ = '\0'; // Now buf1 has variable name, buf2 has value
lolpcc 1:6877bb99aa17 713 buf2 = str_cleanup(buf2);
lolpcc 1:6877bb99aa17 714 if (0 == strncmp(buf1, "Timezone", sizeof("Timezone")-1)) {
lolpcc 1:6877bb99aa17 715 gSntpTimezone = strtod(buf2, &buf2) * 3600;
lolpcc 1:6877bb99aa17 716 } else if (0 == strncmp(buf1, "UpdateDelay", sizeof("UpdateDelay")-1)) {
lolpcc 1:6877bb99aa17 717 gSntpUpdateDelay_s = strtoul(buf2, &buf2, 10);
lolpcc 1:6877bb99aa17 718 } else if (0 == strncmp(buf1, "RecvTimeout", sizeof("RecvTimeout")-1)) {
lolpcc 1:6877bb99aa17 719 gSntpRecvTimeout_s = strtoul(buf2, &buf2, 10);
lolpcc 1:6877bb99aa17 720 } else if (0 == strncmp(buf1, "RtcUtc", sizeof("RtcUtc")-1)) {
lolpcc 1:6877bb99aa17 721 gSntpRtcUtc = (bool)strtol(buf2, &buf2, 10);
lolpcc 1:6877bb99aa17 722 } else if (0 == strncmp(buf1, "DstZone", sizeof("DstZone")-1)) {
lolpcc 1:6877bb99aa17 723 // FIXME: It would be nice to allow human-readable string here.
lolpcc 1:6877bb99aa17 724 gSntpDstZone = (tDST_ZONE)strtol(buf2, &buf2, 10);
lolpcc 1:6877bb99aa17 725 } else {
lolpcc 1:6877bb99aa17 726 fprintf(stderr, "File \"%s\", line %d - unrecognized variable \"%s\" in section [Global]\r\n", filename, line, buf1);
lolpcc 1:6877bb99aa17 727 }
lolpcc 1:6877bb99aa17 728 } else {
lolpcc 1:6877bb99aa17 729 fprintf(stderr, "File \"%s\", line %d - unrecognized statement in section [Global]: %s\r\n", filename, line, buf1);
lolpcc 1:6877bb99aa17 730 }
lolpcc 1:6877bb99aa17 731 break;
lolpcc 1:6877bb99aa17 732 default:
lolpcc 1:6877bb99aa17 733 fprintf(stderr, "File \"%s\", line %d - unrecognized statement / no section: %s\r\n", filename, line, buf1);
lolpcc 1:6877bb99aa17 734 }
lolpcc 1:6877bb99aa17 735 }
lolpcc 1:6877bb99aa17 736 }
lolpcc 1:6877bb99aa17 737 fclose(f);
lolpcc 1:6877bb99aa17 738 lprintf("SNTP configuration read from file \"%s\", %d lines.\r\n", filename, line);
lolpcc 1:6877bb99aa17 739 return 0;
lolpcc 1:6877bb99aa17 740 }
lolpcc 1:6877bb99aa17 741 // Start the SNTP client
lolpcc 1:6877bb99aa17 742 void SNTPClientInit(void) {
lolpcc 1:6877bb99aa17 743 #ifdef SNTP_DST_TESTS
lolpcc 1:6877bb99aa17 744 // Test our DST algorithms
lolpcc 1:6877bb99aa17 745 test_sntp_dst_calc(gSntpTimezone, gSntpDstZone);
lolpcc 1:6877bb99aa17 746 test_sntp_dst_point(-2);
lolpcc 1:6877bb99aa17 747 test_sntp_dst_point(-1);
lolpcc 1:6877bb99aa17 748 test_sntp_dst_point(0);
lolpcc 1:6877bb99aa17 749 test_sntp_dst_point(1);
lolpcc 1:6877bb99aa17 750 test_sntp_dst_point(2);
lolpcc 1:6877bb99aa17 751 #endif
lolpcc 1:6877bb99aa17 752 // SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds
lolpcc 1:6877bb99aa17 753 if (gSntpUpdateDelay_s < 15) {
lolpcc 1:6877bb99aa17 754 gSntpUpdateDelay_s = 15;
lolpcc 1:6877bb99aa17 755 }
lolpcc 1:6877bb99aa17 756 gSntpRunning = true;
lolpcc 1:6877bb99aa17 757
lolpcc 1:6877bb99aa17 758 // Just call this to start SNTP client:
lolpcc 1:6877bb99aa17 759 sntp_init();
lolpcc 1:6877bb99aa17 760 // // Enable RTC ISR
lolpcc 1:6877bb99aa17 761 // gSntpTicker.attach(_sntp_isr, 1);
lolpcc 1:6877bb99aa17 762 // We do it from first NTP response
lolpcc 1:6877bb99aa17 763 }
lolpcc 1:6877bb99aa17 764
lolpcc 1:6877bb99aa17 765 // Use instead of system time()
lolpcc 1:6877bb99aa17 766 // Returns local time
lolpcc 1:6877bb99aa17 767 time_t SNTPTime(void) {
lolpcc 1:6877bb99aa17 768 time_t seconds = time(NULL);
lolpcc 1:6877bb99aa17 769 if (gSntpRtcUtc) {
lolpcc 1:6877bb99aa17 770 seconds += gSntpTimezone + gSntpDST; // Convert to local time
lolpcc 1:6877bb99aa17 771 }
lolpcc 1:6877bb99aa17 772 return seconds;
lolpcc 1:6877bb99aa17 773 }
lolpcc 1:6877bb99aa17 774
lolpcc 1:6877bb99aa17 775 // Use instead of system set_time()
lolpcc 1:6877bb99aa17 776 // seconds - local time
lolpcc 1:6877bb99aa17 777 void SNTPSetTime(time_t seconds) {
lolpcc 1:6877bb99aa17 778 if (gSntpRtcUtc) {
lolpcc 1:6877bb99aa17 779 seconds -= gSntpTimezone + gSntpDST; // Convert from local time
lolpcc 1:6877bb99aa17 780 }
lolpcc 1:6877bb99aa17 781 set_time(seconds);
lolpcc 1:6877bb99aa17 782 }
lolpcc 1:6877bb99aa17 783
lolpcc 1:6877bb99aa17 784 // Use instead of system time()
lolpcc 1:6877bb99aa17 785 // Returns UTC time
lolpcc 1:6877bb99aa17 786 time_t SNTPTimeUTC(void) {
lolpcc 1:6877bb99aa17 787 time_t seconds = time(NULL);
lolpcc 1:6877bb99aa17 788 if (!gSntpRtcUtc) {
lolpcc 1:6877bb99aa17 789 seconds -= gSntpTimezone + gSntpDST; // Convert from local time
lolpcc 1:6877bb99aa17 790 }
lolpcc 1:6877bb99aa17 791 return seconds;
lolpcc 1:6877bb99aa17 792 }
lolpcc 1:6877bb99aa17 793 // Use instead of system set_time()
lolpcc 1:6877bb99aa17 794 // seconds - UTC time
lolpcc 1:6877bb99aa17 795 void SNTPSetTimeUTC(time_t seconds)
lolpcc 1:6877bb99aa17 796 {
lolpcc 1:6877bb99aa17 797 if (!gSntpRtcUtc) {
lolpcc 1:6877bb99aa17 798 seconds += gSntpTimezone + gSntpDST; // Convert to local time
lolpcc 1:6877bb99aa17 799 }
lolpcc 1:6877bb99aa17 800 set_time(seconds);
lolpcc 1:6877bb99aa17 801 }
lolpcc 1:6877bb99aa17 802 //END