| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 | #include "sntp.h"#include "rtc.h"#include "settings_api.h"#include <string.h>#include <time.h>#ifdef PRINTF_STDLIB#include <stdio.h>#endif#ifdef PRINTF_CUSTOM#include "tinystdio.h"#endif#define SENDFAIL_TIMEOUT 5000 /* 5 seconds */#define SENT_TIMEOUT 60000 /* 1 minute */#define BADREPLY_TIMEOUT 60000 /* 1 minute */#define VALID_TIMEOUT (8 * 3600000) /* 8 hours *//* number of seconds between 1900 and 1970 */#define DIFF_SEC_1900_1970         (2208988800UL)struct sntp_packet{  uint8_t status;  uint8_t stratum;  uint8_t ppoll;  uint8_t precision;  uint32_t distance;  uint32_t dispersion;  uint32_t refid;  uint64_t reftime;  uint64_t org;  uint64_t rec;  uint64_t xmt;};static unsigned int timeout;static struct udp_pcb* upcb;static struct ip_addr server;static int port = 123;/**  * @brief  Общая структура настроек  */extern SETTINGS_t sSettings;/**  * @brief  Разовая синхронизация времени при старте контроллера  */extern TaskHandle_t xHandleSntpOnceSinhro;/**  * @brief  Синхронизация времени единоразово при включении контроллера  * @retval   */void vTaskOnceSynchro(void *arg){  for (;;)   {	if (sSettings.sSNTP.sntpEnable)	{        vTaskDelay(7000);  	  SNTP_Poll();	  //printf("Once time sinhro\n\r");	  vTaskDelete(xHandleSntpOnceSinhro);	}	else	  vTaskDelete(xHandleSntpOnceSinhro);  }}/**  * @brief  Периодическая синхронизация времени.  *         Выполняется раз в сутки с 0 часов.  * @retval   */void vTaskPeriodicSynchro(void *arg){  TM_RTC_t data;    static uint8_t fSinhro = 0;    for (;;)   {	vTaskDelay(10000);	if (sSettings.sSNTP.sntpEnable)	{	  TM_RTC_GetDateTime(&data, TM_RTC_Format_BIN);	  	  /* Если пришло время синхронизации */	  if ((data.hours == 0) && (fSinhro == 0))	  {		SNTP_Poll();	    fSinhro = 1;		//printf("Periodic time sinhro\n\r");	  }	  	  if (data.hours > 1)	    fSinhro = 0;	}   	  }}/**  * @brief  Отладочный таск. Выводим время в консоль.  * @retval   */void vTaskSntp(void *arg){  TM_RTC_t data;    for (;;)  {    vTaskDelay(1000);	TM_RTC_GetDateTime(&data, TM_RTC_Format_BIN);	printf("%d.%d.%d %d:%d:%d \n\r", data.date,data.month,data.year,data.hours,data.minutes,data.seconds);  }}/**  * @brief  Инициализация SNTP.  * @retval   */void SNTP_Init(void){      SNTP_SetServerAddr(sSettings.sSNTP.ip);  SNTP_Enable(sSettings.sSNTP.sntpEnable);}static void recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, 				 struct ip_addr *addr, u16_t port){  time_t t;  int utcSec = 0;  TM_RTC_t data;    if (p->len == sizeof(struct sntp_packet))  {    int i;    struct sntp_packet aligned;    //myassert(p->len == p->tot_len); /* don't accept chained pbuf */    memcpy(&aligned, p->payload, sizeof(aligned));    i = (aligned.status >> 3) & 7;    	if ((i < 1) || (i > 4)) /* SNTP version 1..4 */      goto out;    i = aligned.status & 7;	if ((i != 4) && (i != 5)) /* mode 4 or 5: server or broadcast */      goto out;	if (aligned.xmt == 0)      goto out;		utcSec = (int)(3600.0*sSettings.sSNTP.timeZone);	t = (ntohl(aligned.xmt) - 2208988800 + utcSec );		TM_RTC_SetDataTimeUnix((uint32_t)t);		/* Сохраним время последней синхронизации */	TM_RTC_GetDateTime(&data, TM_RTC_Format_BIN);			memset(sSettings.sSNTP.data, 0, sizeof(sSettings.sSNTP.data));		sprintf(sSettings.sSNTP.data, "%02d.%02d.%02d %02d:%02d:%02d", 			data.date, data.month, data.year,			data.hours, data.minutes, data.seconds);	    timeout = VALID_TIMEOUT;      }  out:    pbuf_free(p);}void SNTP_Enable(bool enable){  if (enable)  {    if (upcb == 0)    {      err_t ret;      upcb = udp_new();      if (upcb != 0)	  {		ret = udp_bind(upcb, IP_ADDR_ANY, port);	    if (ret != ERR_OK)        {          udp_remove(upcb);          upcb = 0;        }        else        {          udp_recv(upcb, recv, 0);        }        timeout = 0;	  }    }  }  else if (upcb != 0)  {    udp_remove(upcb);    upcb = 0;  }}bool SNTP_IsEnabled(void){  return upcb != 0;}void SNTP_SetServerAddr(char *addr){  server.addr = ipaddr_addr(addr);}int sntp_getserverport(void){  return port;}static void send_request(void){  struct sntp_packet packet;  struct pbuf* psend;  memset(&packet, 0, sizeof(packet));  packet.status = (3 << 3) /* SNTP vesion 3 */ | (3 << 0); /* Mode: client */  psend = pbuf_alloc(PBUF_RAW, sizeof(packet), PBUF_REF);    if (psend != 0)  {    psend->payload = &packet;    timeout = (udp_sendto(upcb, psend, &server, port) == ERR_OK) ? SENT_TIMEOUT : SENDFAIL_TIMEOUT;    pbuf_free(psend);  }}void SNTP_Poll(void){  if (upcb)    send_request();}
 |