Synchronize system time through sntp

Posted by 00tank on Thu, 08 Aug 2019 05:49:13 +0200

Synchronize system time through sntp

For small Internet of Things devices, few interfaces provide users with data interaction, so the system time of our devices can only be updated locally after obtaining the network time.Then, you need to use the sntp protocol.
ntp protocol: The NTP(Network Time Protocol) network time protocol is based on UDP, a protocol used for network time synchronization, which synchronizes computer clocks in the network to UTC (Universal Coordination can be understood as 0 time zone, 8 hours ahead of Eastern Eight), and precise synchronization pairs can be achieved by adjusting the offset of each time zone.Time function.
sntp protocol: Simple Network Time Protocol, adapted from NTP, used to synchronize computer clocks over the Internet.Defined in RFC2030.Mainly used for small devices with small memory footprint.

Note: NTP timestamps count seconds since 1900, while UNIX timestamps count seconds since 1970

1. Introduction of Common Time Functions

First, the common api in time.h are introduced.

1.time();

Function prototype: time_t time(time_t *t)
Introduction: C library function time_t time(time_t *seconds) returns the time elapsed since Epoch (1970-01-01 00:00:00 UTC) in seconds.If seconds are not empty, the return value is also stored in the variable seconds.
Return value: time elapsed since 1970-01 00:00:00, in unit seconds

2.ctime()

Function prototype: char *ctime(const time_t *timer)
Introduction: The C library function char *ctime(const time_t *timer) returns a string representing the local time, which is based on the parameter timer.
The string format returned is as follows: Www (week) Mmm (month) dd (day) hh:mm:ss (hours and seconds) YYY (year)
Return value: Time string after timer time elapsed from 1970-01-01 00:00:00, based on parameter timer

3.localtime()

Function prototype: struct tm *localtime(const time_t *timer)
Introduction: The C library function struct tm *localtime(const time_t *timer) uses the value of timer to populate the tm structure.The value of timer is decomposed into tm structures and expressed in the local time zone.
Return value: Fill tm structure to represent time structure after time elapsed from 1970-01 00:00:00
Note: year output needs +1900, month output needs +1 to get accurate utc time
tm structure:

struct tm {
   int tm_sec;         /* Seconds, from 0 to 59                */
   int tm_min;         /* Score, from 0 to 59                */
   int tm_hour;        /* Hours ranging from 0 to 23                */
   int tm_mday;        /* The day of the month, ranging from 1 to 31                    */
   int tm_mon;         /* Month, from 0 to 11                */
   int tm_year;        /* Years since 1900                */  
   int tm_wday;        /* The day of the week, from 0 to 6                */
   int tm_yday;        /* Days of the year, ranging from 0 to 365                    */
   int tm_isdst;       /* Daylight saving time                        */    
};

4.mktime()

Function prototype: time_t mktime (struct tm * timeptr)
Introduction: The C library function time_t mktime (struct tm * timeptr) converts the structure pointed to by timeptr to a time_t value based on the local time zone.
Parameter: tm structure, same as above.
Return value: The number of seconds taken to convert the tm structure data referred to by the timeptr parameter into UTC time since 0:0 minutes and 0 seconds on January 1, 1970 A.D.

2. Functional Realization

The following is an analysis of a project's process of updating network time to local locations. Platforms may differ and implementation processes are roughly the same.
Source Code Analysis
Create an sntp client to get time and updates from the network.

static void sntp_client(void)
{
    /** Set this to 1 to allow config of SNTP server(s) by DNS name */
#if (!SNTP_SERVER_DNS)
    struct ip4_addr test_addr;
#endif
    hal_rtc_time_t r_time = {6,6,6,1,1,6,0};
    hal_rtc_status_t ret = HAL_RTC_STATUS_OK;

    //Set RTC to a incorrect time.
    
    //Set default system time
    ret = hal_rtc_set_time(&r_time);
    // LOG_I(sntp_client_main, "[%d]cur_time[%d:%d:%d]", ret, r_time.rtc_hour, r_time.rtc_min, r_time.rtc_sec);

	// Set the sntp server ip address or DNS (destination address) from which server to get the time
    /** Set this to 1 to allow config of SNTP server(s) by DNS name */
#if SNTP_SERVER_DNS
    sntp_setservername(0, "1.cn.pool.ntp.org");
    sntp_setservername(1, "1.hk.pool.ntp.org");
#else
    IP4_ADDR(&test_addr, 213, 161, 194, 93);
    sntp_setserver(0, (const ip_addr_t *)(&test_addr));
    IP4_ADDR(&test_addr, 129, 6, 15, 29);
    sntp_setserver(1, (const ip_addr_t *)(&test_addr));
#endif

	//Initialization Settings
    sntp_init();

   // LOG_I(sntp_client_main, "SNTP init done");
}
/**
 * Initialize this module.
 * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
 */
void
sntp_init(void)
{
#ifdef SNTP_SERVER_ADDRESS
#if SNTP_SERVER_DNS
  sntp_setservername(0, SNTP_SERVER_ADDRESS);
#else
#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
#endif
#endif /* SNTP_SERVER_ADDRESS */

  if (sntp_pcb == NULL) {
    SNTP_RESET_RETRY_TIMEOUT();
    
    //Create udp to receive udp packages, time data
    sntp_pcb = udp_new();
    LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
    if (sntp_pcb != NULL) {
    
    //Has data, processes received data, synchronizes to local, and is processed by sntp_recv.
      udp_recv(sntp_pcb, sntp_recv, NULL);
#if SNTP_STARTUP_DELAY
      sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
#else
      sntp_request(NULL);
#endif
    }
  }
}

The above program executes successfully and gets the local time again, which will be updated.

uint32_t get_rtc_stamp_time(char * cur_time)
{
	hal_rtc_time_t r_time;
    hal_rtc_status_t ret = HAL_RTC_STATUS_OK;
	
	time_t timep = 0;    
	struct tm p;
	struct tm *tp;
	
	//Get local time, utc time
	ret = hal_rtc_get_time(&r_time);
	if (ret == HAL_RTC_STATUS_OK)
	{
		// printf("cur_time[%d,%d,%d,%d]\r\n", r_time.rtc_year, r_time.rtc_mon, r_time.rtc_day, r_time.rtc_week);
		// printf("[%d]cur_time[%d:%d:%d]\r\n", ret, r_time.rtc_hour, r_time.rtc_min, r_time.rtc_sec);
	#if 1
		p.tm_year = r_time.rtc_year + 2000 - 1900;//DATA%100 + 2000 -1900;
		p.tm_mon = r_time.rtc_mon-1;//(DATA/100) %100 -1;
		p.tm_mday = r_time.rtc_day;//DATA/10000;
		
		p.tm_hour= r_time.rtc_hour;//(UTCTime / 10000);
		p.tm_min= r_time.rtc_min;//(UTCTime / 100)%100;
		p.tm_sec= r_time.rtc_sec;//UTCTime % 100;
		
		//Conversion from utc time to Eastern Eight
		timep=mktime(&p);
		timep = timep+28800;
		tp = localtime(&timep);  //0 time zone 8 hours from Eastern Eight
		//printf("%d %d %d %d %d %d\n",(tp->tm_year+1900), (tp->tm_mon+1), tp->tm_mday,tp->tm_hour, tp->tm_min, tp->tm_sec);
		sprintf(cur_time,"%02d-%02d-%02d %02d:%02d:%02d",(tp->tm_year+1900), (tp->tm_mon+1), tp->tm_mday,tp->tm_hour, tp->tm_min, tp->tm_sec);
		
		//Figure log below
		printf("%02d-%02d-%02d %02d:%02d:%02d",(tp->tm_year+1900), (tp->tm_mon+1), tp->tm_mday,tp->tm_hour, tp->tm_min, tp->tm_sec);
	#endif
		//sprintf(cur_time,"%d-%02d-%02d %d %02d:%02d:%02d",r_time.rtc_year, r_time.rtc_mon, r_time.rtc_day, r_time.rtc_week,r_time.rtc_hour, r_time.rtc_min, r_time.rtc_sec);

		
	}else{
		printf("get_rtc_stamp_time fail\r\n");
	}
	return timep;
}

The test log is shown below

Topics: network DNS Unix