this will take a image from C328 serial camera and store those images in mbed flash as html and this html page is uploaded into the server at ip:192.168.1.2
lwip/SNTPClient/SNTPClient.cpp
- Committer:
- mitesh2patel
- Date:
- 2010-12-15
- Revision:
- 0:e1a0471e5ffb
File content as of revision 0:e1a0471e5ffb:
/* * SNTPClient.cpp * SNTP (Simple NTP) client * Written by iva2k * * Wrapper around LWIP/sntp for MBED, with DST rules. * This implementation relies on: * 1. LWIP (http://www.sics.se/~adam/lwip/) adopted for MBED * http://mbed.org/projects/cookbook/svn/EMAC/lwip/trunk * 2. LWIP's contributed SNTP client (sntp.c and sntp.h) from * http://cvs.savannah.gnu.org/viewvc/contrib/apps/sntp/?root=lwip * (used version 1.8) * * Changes needed in LWIP/sntp: * - pointer typecast (line 594) - fixes mbed compiler problem * - #include "sntp.h" moved after lwip/opt.h et.al - for re-defines. * - pbuf_free(p) in sntp_send_request() (line 602) - fixes memory leak BUG. * - changing sntp_dns_found() to delayed sntp_try_next_server() - to unblock if network is disconnected. * * Changes in MBED's LWIP: * - modified lwipopts.h (this file is automatically included into sntp.c) * * Requirements: * + direct RTC update from receiving the NTP time packet * + optionally support more than one NTP server * + the IP address of the NTP server(s) stored in a local file * + timeout error recovery should the NTP server(s) not be available. No RTC update should the NTP access fail * + allow for a UTC offset, also stored in the local file * + DST correction * + use DNS for NTP servers IP address resolution * + periodic updates at specified time intervals * * TODO: * . DST correction * - record metrics (count of updates, failed tries?, correction more than epsilon, etc.?) */ #include "mbed.h" #include "lwip/opt.h" #include "SNTPClient.h" #define SNTP_EPSILON 10 // time difference noticed as big update (in seconds). //#define SNTP_DST_TESTS // Define this to run DST algorithms tests typedef struct DST_ZONE_DESCR { tDST_ZONE zone; const char *name; int gmt; int dst; int hr1; int wk1; int wday1; int mon1; int hr2; int wk2; int wday2; int mon2; pFncDstCalc fnc; } tDST_ZONE_DESR; static tDST_ZONE_DESR gSntpDstZones[] = { #define _(z, fnc, gmt, dst, hr1,wk1,wday1,mon1, hr2,wk2,wday2,mon2) \ { z, #z, gmt, dst, hr1,wk1,wday1,mon1, hr2,wk2,wday2,mon2, fnc }, #include "DstZones.h" }; #define DST_ZONE_DESCR_CNT (sizeof(gSntpDstZones)/sizeof(gSntpDstZones[0])) const char *SNTPDstZoneName(tDST_ZONE zone) { if (zone >= DST_ZONE_DESCR_CNT) return ""; return gSntpDstZones[zone].name; } #ifdef __cplusplus extern "C" { #endif tDST_ZONE gSntpDstZone = DST_NONE; // DST zone - rule selector unsigned int gSntpRecvTimeout_s = 3; // 3 sec; SNTP_RECV_TIMEOUT unsigned int gSntpUpdateDelay_s = 3600; // 1 hour; SNTP_UPDATE_DELAY signed int gSntpTimezone = 0*3600; // seconds from UTC to local time signed int gSntpDST = 0*3600; // seconds from UTC to local time bool gSntpRtcUtc = false; // true to keep RTC in UTC, false to keep in local time unsigned int gSntpUpdates = 0; // Track number of all clock NTP updates unsigned int gSntpUpdatesBig = 0; // Track number of significant clock NTP updates bool gSntpRunning = false; // true if SNTP service is running Timeout gSntpDelay; // For async calls. Ticker gSntpTicker; // There is no RTC interrupt on MBED (yet). Use (more wastefull) timer. time_t gSntpRtcTCR = 0; // Timer Capture Register equivalent (in RTC time - either local or UTC depending on gSntpRtcUtc) signed int gSntpRtcTCRDST = 0; // New DST value for when RTC crosses gSntpRtcTCR static void SNTPSetDSTEx(unsigned int dst, bool adjust_clock) { if (adjust_clock && !gSntpRtcUtc && gSntpDST != dst) { time_t seconds = time(NULL); seconds -= gSntpDST; // Convert from old local time seconds += dst; // Convert to new local time set_time(seconds); if (gSntpRtcTCR) { // Adjust our alarm clock gSntpRtcTCR -= gSntpDST; gSntpRtcTCR += dst; } } gSntpDST = dst; } #if 0 // Custom DST zone function example // USA (since 2007) // Calculate start or stop DST point for given year based on rules // tz - Timezone // year - current year. DST changes well away from year end, so does not matter what timezone. // start - DST_START for start, DST_STOP for stop // Returns DST point (in local time). DST_STOP time is in DST static tDstPoint _sntp_dst_calc_custom(int tz, int year, tDST_START start) { tDstPoint ret; struct tm t; // USA: 3600; 2, Second SUN, March; 2, First SUN, November int dst = 3600; // DST shift (seconds) int hour; // Hour of the change int N; // Week in the month int wday; // Day of the week int month; if (start == DST_START) { hour = 2; // (0-23) Hour of the change N = 2-1; // 2nd in the month wday = 0; // Sunday month = 2; // March } else { // DST_STOP hour = 2; // (0-23) Hour of the change N = 1-1; // 1st in the month wday = 0; // Sunday month = 10; // November } t.tm_sec = 0; // 0-59 t.tm_min = 0; // 0-59 t.tm_hour = hour; // 0-23 t.tm_year = year - 1900; // t.tm_mon = month; // 0-11 t.tm_mday = 1+N*7; // 1-31, first possible date for Nth given weekday mktime(&t); // Calculate tm_wday t.tm_mday += (wday-t.tm_wday+14)%7; // Shift to wday ret.t = mktime(&t); ret.dst = (start == DST_START) ? dst : 0; ret.dstshift = dst; return ret; } #endif // Calculate start or stop DST point for given year based on rules for the DST zone // tz - Timezone // zone - DST zone // year - current year. DST changes well away from year end, so does not matter timezone. // start - DST_START for start, DST_STOP for stop // Returns DST point (in standard local time). DST_STOP time is in NOT IN DST static tDstPoint _sntp_dst_calc(int tz, tDST_ZONE zone, int year, tDST_START start) { tDstPoint ret; ret.t = 0; ret.dst = 0; ret.dstshift = 0; if (zone == DST_NONE || zone >= DST_ZONE_DESCR_CNT) return ret; tDST_ZONE_DESR *descr = &gSntpDstZones[zone]; if (descr->fnc) { // Use custom function ret = descr->fnc(tz, year, start); } else { // Use rules struct tm t; t.tm_sec = 0; // 0-59 t.tm_min = 0; // 0-59 t.tm_hour = (start == DST_START) ? descr->hr1 : descr->hr2; t.tm_year = year - 1900; // t.tm_mon = (start == DST_START) ? descr->mon1 : descr->mon2; // 0-11 int wk =((start == DST_START) ? descr->wk1 : descr->wk2) -1; int wday = (start == DST_START) ? descr->wday1: descr->wday2; if (wk < 0) { // For "Last in the month" - we go to next month, then move back by one week t.tm_mon += 1; // 0-11 if (t.tm_mon > 11) { t.tm_mon -= 12; t.tm_year += 1; } t.tm_mday = 1+0*7; // 1-31, first possible date for Nth given weekday } else { t.tm_mday = 1+wk*7; // 1-31, first possible date for Nth given weekday } mktime(&t); // Calculate tm_wday t.tm_mday += (wday-t.tm_wday+14)%7; // Shift to wday ret.t = mktime(&t); if (wk < 0) { ret.t -= 7 * 24 * 3600; } if (descr->gmt) { ret.t += tz; } ret.dst = (start == DST_START) ? descr->dst : 0; ret.dstshift = descr->dst; } if (start == DST_STOP) { ret.t -= ret.dstshift; // this correction is due to the fact that rules are given in local time with DST, // but calculations are made in standard local time (without DST adjustment) } return ret; } // Calculate desired DST point relative to now based on rules for the DST zone // tz - timezone // zone - DST zone // now - current time (standard local time = excluding DST). // index - 0 for immediate next, +1 for second next, -1 for immediate previous // Returns DST point (in standard local time) static tDstPoint _sntp_dst_point(int tz, tDST_ZONE zone, time_t now, int index) { tDstPoint ret; int year; tDST_START type; struct tm *pt = localtime(&now); ret.t = 0; ret.dst = 0; ret.dstshift = 0; if (zone == DST_NONE || zone >= DST_ZONE_DESCR_CNT) return ret; // Algorithm // 1. Determine where now is in respect to current year DST points (find for index=0) // 2. Use index to shift year and type // 3. return the point // This algorithm relies on DST start date being before DST stop date in the year. year = pt->tm_year + 1900; type = DST_START; ret = _sntp_dst_calc(tz, zone, year, type); if (now > ret.t) { type = DST_STOP; ret = _sntp_dst_calc(tz, zone, year, type); if (now > ret.t) { // It is next year's start point type = DST_START; year += 1; } } // Now year and type are right for index=0 // Calculate where index points to - shift year and type int norm = (index > 0) ? (int)(index/2) : (int)((index-1)/2); year += norm; index -= norm*2; // Now index is (0,1) if (index) { // Flip the type type = (type == DST_START) ? DST_STOP : DST_START; } ret = _sntp_dst_calc(tz, zone, year, type); return ret; // struct tm t; // t.tm_sec = 0; // 0-59 // t.tm_min = 0; // 0-59 // t.tm_hour = 0; // 0-23 // t.tm_mday = 0; // 1-31 // t.tm_mon = 0; // 0-11 // t.tm_year = 2005-1900; // year since 1900 // t.tm_wday = 0; // 0-6 Day of week (Sunday = 0) // t.tm_yday = 0; // Day of year (0 - 365) // t.tm_isdst = -1; // Nonzero = Daylight saving time } #if defined(LWIP_DEBUG) // Print DST dates report static void _sntp_dst_dates(int tz, tDST_ZONE zone, int year) { char _buffer[64]; tDstPoint r; printf("\r\nDST DATES for zone %d/%s:\r\n", (int)zone, SNTPDstZoneName(zone)); r = _sntp_dst_calc(tz, zone, year, DST_START); strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t)); printf(" %d DST BEGINS (+%04d sec) %s\r\n", year, r.dst, _buffer); r = _sntp_dst_calc(tz, zone, year, DST_STOP); strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t)); printf(" %d DST ENDS (+%04d sec) %s\r\n", year, r.dst, _buffer); } #endif #ifdef SNTP_DST_TESTS static void test_sntp_dst_calc(int tz, tDST_ZONE zone) { char _buffer[64]; tDstPoint r; int year; printf("\r\nTEST: _sntp_dst_calc(tz=%d, zone=%d/%s)\r\n", tz, (int)zone, SNTPDstZoneName(zone)); for (year = 1999; year < 2016; year++) { r = _sntp_dst_calc(tz, zone, year, DST_START); strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t)); printf(" (0,%d,start) %s %d\r\n", year, _buffer, r.dst); r = _sntp_dst_calc(tz, zone, year, DST_STOP); strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t)); printf(" (0,%d,stop ) %s %d\r\n", year, _buffer, r.dst); } } static void test_sntp_dst_point(int index) { char _buffer[64]; struct tm t; tDstPoint r; int tz=gSntpTimezone; tDST_ZONE zone=gSntpDstZone; int year = 2009, day, month; int norm = (index > 0) ? (int)(index/2) : (int)((index-1)/2); printf("\r\nTEST: _sntp_dst_point(%d) norm=%d\r\n", index, norm); t.tm_sec = 0; // 0-59 t.tm_min = 0; // 0-59 t.tm_hour = 9; // 0-23 t.tm_year = year-1900; day = 1; for (month = 0; month < 2; month++) { t.tm_mon = month; t.tm_mday = day; t.tm_year = year-1900; r = _sntp_dst_point(tz, zone, mktime(&t), index); strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t)); printf(" (0,%02d/%02d/%d,%d) %s %d\r\n", month+1, day, year, index, _buffer, r.dst); } for (day = 1; day < 32; day++) { t.tm_mon = month; t.tm_mday = day; t.tm_year = year-1900; r = _sntp_dst_point(tz, zone, mktime(&t), index); strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t)); printf(" (0,%02d/%02d/%d,%d) %s %d\r\n", month+1, day, year, index, _buffer, r.dst); } day = 30; for (; month < 10; month++) { t.tm_mon = month; t.tm_mday = day; t.tm_year = year-1900; r = _sntp_dst_point(tz, zone, mktime(&t), index); strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t)); printf(" (0,%02d/%02d/%d,%d) %s %d\r\n", month+1, day, year, index, _buffer, r.dst); } for (day = 1; day < 32; day++) { t.tm_mon = month; t.tm_mday = day; t.tm_year = year-1900; r = _sntp_dst_point(tz, zone, mktime(&t), index); strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&r.t)); printf(" (0,%02d/%02d/%d,%d) %s %d\r\n", month+1, day, year, index, _buffer, r.dst); } } #endif // SNTP_DST_TESTS // Set current DST static void _sntp_dst_now(void) { time_t now = time(NULL); // Convert to standart local time (no DST) now = gSntpRtcUtc ? (now + gSntpTimezone) : (now - gSntpDST); // Check DST setting for now tDstPoint dst = _sntp_dst_point(gSntpTimezone, gSntpDstZone, now, -1); #ifdef LWIP_DEBUG char _buffer[64]; strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&dst.t)); LWIP_DEBUGF(SNTP_DEBUG_STATE, ( "DEBUG: _sntp_dst_now(%d) based on last DST change on (%d) %s to (+%04d sec)\r\n", now, dst.t, _buffer, dst.dst)); #endif // Change RTC SNTPSetDSTEx(dst.dst, true); } // Plan for next DST change static void _sntp_dst_schedule(void) { time_t now = time(NULL); // Convert to standart local time (no DST) now = gSntpRtcUtc ? (now + gSntpTimezone) : (now - gSntpDST); // Check next DST change point tDstPoint dst = _sntp_dst_point(gSntpTimezone, gSntpDstZone, now, 0); if (dst.t) { #ifdef LWIP_DEBUG char _buffer[64]; strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&dst.t)); #endif // Set our alarm clock // Convert from standard local to UTC time or local time dst.t = gSntpRtcUtc ? (dst.t - gSntpTimezone) : (dst.t + gSntpDST); #ifdef LWIP_DEBUG if (time(NULL) > dst.t) { LWIP_DEBUGF(SNTP_DEBUG_STATE, ( "DEBUG: _sntp_dst_schedule() ASSERTION FAILED !(%d<%d) trying to schedule for the past: %s (+%04d sec)\r\n", time(NULL), dst.t, _buffer, dst.dst)); } else { LWIP_DEBUGF(SNTP_DEBUG_STATE, ( "DEBUG: _sntp_dst_schedule() scheduled in %d seconds, set for %s (+%04d sec)\r\n", dst.t-time(NULL), _buffer, dst.dst)); } #endif } gSntpRtcTCR = dst.t; gSntpRtcTCRDST = dst.dst; } // RTC ISR - called upon each RTC tick static void _sntp_isr(void) { time_t seconds = time(NULL); if (gSntpRtcTCR && seconds > gSntpRtcTCR ) { // DST change has arrived gSntpRtcTCR = 0; // Disable ISR and avoid extra calcs in SNTPSetDSTEx() //if (gSntpRtcTCRDST != gSntpDST) { // Change to/from DST SNTPSetDSTEx(gSntpRtcTCRDST, true); gSntpRtcTCRDST = 0; // Schedule callback to plan for next DST change (take it out of ISR context) gSntpDelay.attach(_sntp_dst_schedule, 1.0); #ifdef LWIP_DEBUG char _buffer[64]; if (gSntpRtcUtc) { seconds += gSntpTimezone + gSntpDST; // Convert to local time } strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&seconds)); LWIP_DEBUGF(SNTP_DEBUG_STATE, ( "DEBUG: _sntp_isr() changed DST. datetime=%s\r\n", _buffer)); #endif //} } } // NTP Callback - timestamp from NTP server arrives here void SntpClientSet(time_t seconds) { time_t old_seconds = time(NULL); if (!gSntpRtcUtc) { seconds += gSntpTimezone + gSntpDST; // Convert to local time } set_time(seconds); // Special tasks for the very first NTP updates if (!gSntpUpdates) { #if defined(LWIP_DEBUG) // Report DST dates for the zone struct tm *pt = localtime(&seconds); _sntp_dst_dates(gSntpTimezone, gSntpDstZone, pt->tm_year+1900); #endif // DST scheduler _sntp_dst_now(); _sntp_dst_schedule(); // Enable RTC ISR gSntpTicker.attach(_sntp_isr, 1.0); } if (gSntpUpdates && abs((int)(old_seconds - seconds)) > SNTP_EPSILON) { printf("SNTP settime() corrected big difference: (%d) seconds, more than %d. Big updates count=%d.\r\n", old_seconds-seconds, SNTP_EPSILON, gSntpUpdatesBig); gSntpUpdatesBig ++; } gSntpUpdates++; if (1) { char _buffer[64]; if (gSntpRtcUtc) { seconds += gSntpTimezone + gSntpDST; // Convert to local time } strftime(_buffer, sizeof(_buffer), "%A %m/%d/%Y %H:%M:%S", localtime(&seconds)); printf("SNTP settime() #%d seconds=%d TZ=%0.1f datetime=%s\r\n", gSntpUpdates, seconds, gSntpTimezone/3600.0, _buffer); } } #ifdef __cplusplus }; #endif #ifdef __cplusplus extern "C" { #endif #include "lwip/def.h" #include "lwip/pbuf.h" #include "lwip/sys.h" #include "lwip/stats.h" #include "netif/etharp.h" #include "string.h" #ifdef __cplusplus }; #endif // Accomodating sntp timeout functions #if NO_SYS #include "sntp.h" extern void sntp_request(void *arg); // this is dirty hack around "static" function. Some linkers may revolt! extern void sntp_try_next_server(void *arg); extern char* sntp_server_addresses[]; extern u8_t sntp_current_server; extern u8_t sntp_num_servers; static void (*sntp_addresses_free)(void*) = NULL; static Timeout _sntp_timer1; static Timeout _sntp_timer2; void sntp_sys_timeout(u32_t timeout_s, void (*func)(void *arg), void *arg) { // all we really need to track is only 2 functions: sntp_request, sntp_try_next_server Timeout *t = NULL; if (func == &sntp_request) { t = &_sntp_timer1; LWIP_DEBUGF(SNTP_DEBUG_STATE, ("DEBUG: IN sntp_sys_timeout(), func=sntp_request\r\n")); } else if (func == &sntp_try_next_server) { t = &_sntp_timer2; LWIP_DEBUGF(SNTP_DEBUG_STATE, ("DEBUG: IN sntp_sys_timeout(), func=sntp_try_next_server\r\n")); } if (t) { t->detach(); t->attach((void(*)(void))func, 1.0*timeout_s); // Another shortcut - we have no arg to pass, so just typecast the func. } } void sntp_sys_untimeout(void (*func)(void *arg), void *arg) { Timeout *t = NULL; if (func == &sntp_request) { t = &_sntp_timer1; LWIP_DEBUGF(SNTP_DEBUG_STATE, ("DEBUG: IN sntp_sys_untimeout(), func=sntp_request\r\n")); } else if (func == &sntp_try_next_server) { t = &_sntp_timer2; LWIP_DEBUGF(SNTP_DEBUG_STATE, ("DEBUG: IN sntp_sys_untimeout(), func=sntp_try_next_server\r\n")); } if (t) { t->detach(); } } #else // NO_SYS #error "I don't know how to compile LWIP/SNTP with NO_SYS=0" #endif // NO_SYS // Can be called when already running void SNTPSetDstZone(tDST_ZONE zone) { if (zone >= DST_ZONE_DESCR_CNT) return; // ERR_INVALID_ARG gSntpDstZone = zone; if (gSntpRunning) { // DST scheduler _sntp_dst_now(); _sntp_dst_schedule(); } } void SNTPSetRecvTimeout(unsigned int val_s) { gSntpRecvTimeout_s = val_s; } void SNTPSetUpdateDelay(unsigned int val_s) { gSntpUpdateDelay_s = val_s; } void SNTPSetTimezone(float hours_from_utc, bool adjust_clock) { if (adjust_clock && !gSntpRtcUtc) { time_t seconds = time(NULL); seconds -= gSntpTimezone; // Convert from old local time seconds += hours_from_utc * 3600; // Convert to new local time set_time(seconds); if (gSntpRtcTCR) { // Adjust our alarm clock gSntpRtcTCR -= gSntpTimezone; gSntpRtcTCR += hours_from_utc * 3600; } } gSntpTimezone = hours_from_utc * 3600; } void SNTPSetDST(float hours_from_utc, bool adjust_clock) { SNTPSetDSTEx(hours_from_utc * 3600, adjust_clock); } static int sntp_num_servers_alloc = 0; static void _SNTPClrAddresses(void) { if (!sntp_num_servers_alloc) sntp_num_servers_alloc = sntp_num_servers; // Here we save the original size of the sntp_server_addresses[] array. if (sntp_addresses_free) { for (int i=0; i<sntp_num_servers; i++) { sntp_addresses_free(sntp_server_addresses[i]); } } sntp_current_server = 0; sntp_num_servers = 0; sntp_addresses_free = NULL; } static int _SNTPAddAddress(const char* server_address) { if (sntp_num_servers+1 > sntp_num_servers_alloc) return -1; sntp_server_addresses[sntp_num_servers] = (char*)malloc(strlen(server_address)+1); if (sntp_server_addresses[sntp_num_servers] == NULL) return -1; // Out of memory strcpy(sntp_server_addresses[sntp_num_servers], server_address); sntp_num_servers++; return 0; } // Override default servers list. // For no-copy, pass pointer to free() in p_free. // Returns: actual number of servers set (limited by allocated buffer size) // WARNING! There is no interlock to ensure that SNTP service does not read its data while we are updating it. // This function is intended to be called only before SNTPClientInit(). int SNTPSetAddresses(const char* server_addresses[], int count, void (*p_free)(void*)) { // In order to use sntp.c as-is, we hack into its static variables. // Not all compilers/linkers will support that. _SNTPClrAddresses(); if (count > sntp_num_servers_alloc) count = sntp_num_servers_alloc; for (int i=0; i<count; i++) { if (p_free) { sntp_server_addresses[i] = (char *)server_addresses[i]; } else { _SNTPAddAddress(server_addresses[i]); } } sntp_num_servers = count; sntp_current_server = 0; sntp_addresses_free = p_free ? p_free : &free; return count; } // Trim whitespace/CRLFs from both ends of a given string char * str_cleanup(char *in) { char * out = in; // Trim leading spaces and CR/LF while (*out == ' ' || *out == '\t' || *out == '\r' || *out == '\n') out ++; // Trim trailing spaces and CR/LF int len = strlen(out)-1; while (out[len] == ' ' || out[len] == '\t' || out[len] == '\r' || out[len] == '\n') { out[len] = '\0'; len--; } return out; } #ifndef CRLF #define CRLF "\r\n" #endif void SNTPWriteIniFile(FILE * f) { fprintf(f, "# SNTP Configuration file" CRLF); fprintf(f, CRLF "[Servers]" CRLF); for (int i=0; i<sntp_num_servers; i++) { fprintf(f, "%s" CRLF, sntp_server_addresses[i]); } fprintf(f, CRLF "[Global]" CRLF); fprintf(f, "RtcUtc=%d" CRLF, (int)gSntpRtcUtc); fprintf(f, "Timezone=%0.1f" CRLF, gSntpTimezone / 3600.0); fprintf(f, "DstZone=%d" CRLF, gSntpDstZone); fprintf(f, "# %s" CRLF, SNTPDstZoneName(gSntpDstZone)); fprintf(f, "UpdateDelay=%d" CRLF, gSntpUpdateDelay_s); fprintf(f, "RecvTimeout=%d" CRLF, gSntpRecvTimeout_s); fprintf(f, CRLF "##END" CRLF); } // Simple ini file parser for SNTP configuration (Case-sensitive!) // This function is intended to be called only before SNTPClientInit(). // Returns: 0 if OK, errno otherwise enum { SECT_NONE, SECT_SERVERS, SECT_GLOBAL, }; int SNTPReadIniFile(const char* filename) { FILE *f; char buf[512]; bool addresses_cleared = false; f = fopen(filename, "r"); if (!f) return -1; // errno not used? char *buf1, *buf2; int section=SECT_NONE; int line = 0; while (fgets(buf, sizeof(buf)/sizeof(buf[0]), f)) { line++; buf1 = str_cleanup(buf); if (*buf1 == '#' || *buf1 == '\0') continue; // Comment line or empty line - skip if (*buf1 == '[') { // New section if (0 == strncmp(buf1,"[Servers]", sizeof("[Servers]")-1)) { section=SECT_SERVERS; if (!addresses_cleared) { // Clear addresses only once. _SNTPClrAddresses(); addresses_cleared = true; } } else if (0 == strncmp(buf1,"[Global]", sizeof("[Global]")-1)) { section=SECT_GLOBAL; } else { section=SECT_NONE; fprintf(stderr, "File \"%s\", line %d - section \"%s\" is not understood.\r\n", filename, line, buf1); } } else { // Section values switch (section) { case SECT_SERVERS: if (_SNTPAddAddress(buf1)) { fprintf(stderr, "File \"%s\", line %d - cannot add server \"%s\" - exceeded allocated slots.\r\n", filename, line, buf1); } break; case SECT_GLOBAL: buf2 = strchr(buf1, '='); if (buf2) { *buf2++ = '\0'; // Now buf1 has variable name, buf2 has value buf2 = str_cleanup(buf2); if (0 == strncmp(buf1, "Timezone", sizeof("Timezone")-1)) { gSntpTimezone = strtod(buf2, &buf2) * 3600; } else if (0 == strncmp(buf1, "UpdateDelay", sizeof("UpdateDelay")-1)) { gSntpUpdateDelay_s = strtoul(buf2, &buf2, 10); } else if (0 == strncmp(buf1, "RecvTimeout", sizeof("RecvTimeout")-1)) { gSntpRecvTimeout_s = strtoul(buf2, &buf2, 10); } else if (0 == strncmp(buf1, "RtcUtc", sizeof("RtcUtc")-1)) { gSntpRtcUtc = (bool)strtol(buf2, &buf2, 10); } else if (0 == strncmp(buf1, "DstZone", sizeof("DstZone")-1)) { // FIXME: It would be nice to allow human-readable string here. gSntpDstZone = (tDST_ZONE)strtol(buf2, &buf2, 10); } else { fprintf(stderr, "File \"%s\", line %d - unrecognized variable \"%s\" in section [Global]\r\n", filename, line, buf1); } } else { fprintf(stderr, "File \"%s\", line %d - unrecognized statement in section [Global]: %s\r\n", filename, line, buf1); } break; default: fprintf(stderr, "File \"%s\", line %d - unrecognized statement / no section: %s\r\n", filename, line, buf1); } } } fclose(f); printf("SNTP configuration read from file \"%s\", %d lines.\r\n", filename, line); return 0; } // Start the SNTP client void SNTPClientInit(void) { #ifdef SNTP_DST_TESTS // Test our DST algorithms test_sntp_dst_calc(gSntpTimezone, gSntpDstZone); test_sntp_dst_point(-2); test_sntp_dst_point(-1); test_sntp_dst_point(0); test_sntp_dst_point(1); test_sntp_dst_point(2); #endif // SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds if (gSntpUpdateDelay_s < 15) { gSntpUpdateDelay_s = 15; } gSntpRunning = true; // Just call this to start SNTP client: sntp_init(); // // Enable RTC ISR // gSntpTicker.attach(_sntp_isr, 1); // We do it from first NTP response } // Use instead of system time() // Returns local time time_t SNTPTime(void) { time_t seconds = time(NULL); if (gSntpRtcUtc) { seconds += gSntpTimezone + gSntpDST; // Convert to local time } return seconds; } // Use instead of system set_time() // seconds - local time void SNTPSetTime(time_t seconds) { if (gSntpRtcUtc) { seconds -= gSntpTimezone + gSntpDST; // Convert from local time } set_time(seconds); } // Use instead of system time() // Returns UTC time time_t SNTPTimeUTC(void) { time_t seconds = time(NULL); if (!gSntpRtcUtc) { seconds -= gSntpTimezone + gSntpDST; // Convert from local time } return seconds; } // Use instead of system set_time() // seconds - UTC time void SNTPSetTimeUTC(time_t seconds) { if (!gSntpRtcUtc) { seconds += gSntpTimezone + gSntpDST; // Convert to local time } set_time(seconds); } //END