|
@@ -0,0 +1,249 @@
|
|
|
+#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();
|
|
|
+}
|