#include #include #include #include #include #include #include #include "ntp.h" #include "lwip/def.h" #include "user_config.h" #include "driver/uart.h" //#include "utils.h" #define OFFSET 2208988800ULL static ip_addr_t ntp_server_ip = { 0 }; static os_timer_t ntp_timeout; static struct espconn *pCon, pConDNS; static struct timeval t_tv = { 0, 0 }; static uint64_t t_offset = 0; static int16_t ntp_timezone = 0; void ICACHE_FLASH_ATTR get_cur_time(struct timeval *tv) { uint64_t t_curr = get_long_systime() - t_offset + t_tv.tv_usec; tv->tv_sec = t_tv.tv_sec + t_curr / 1000000; tv->tv_usec = t_curr % 1000000; } void ICACHE_FLASH_ATTR set_timezone(int16_t timezone) { ntp_timezone = timezone; } uint8_t *ICACHE_FLASH_ATTR get_timestr() { struct timeval tv; static uint8_t buf[10]; get_cur_time(&tv); tv.tv_sec += ntp_timezone * 3600; os_sprintf(buf, "%02d:%02d:%02d", (tv.tv_sec / 3600) % 24, (tv.tv_sec / 60) % 60, tv.tv_sec % 60); return buf; } static uint8_t *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; uint8_t *ICACHE_FLASH_ATTR get_weekday() { struct timeval tv; get_cur_time(&tv); tv.tv_sec += ntp_timezone * 3600; return days[((tv.tv_sec / (3600 * 24)) + 3) % 7]; } void ICACHE_FLASH_ATTR ntp_to_tv(uint8_t ntp[8], struct timeval *tv) { uint64_t aux = 0; tv->tv_sec = ntohl(*(uint32_t *) ntp) - OFFSET; aux = ntohl(*(uint32_t *) & ntp[4]); // aux is the NTP fraction (0..2^32-1) aux *= 1000000; // multiply by 1e6 aux >>= 32; // and divide by 2^32 tv->tv_usec = (uint32_t) aux; } LOCAL void ICACHE_FLASH_ATTR ntp_dns_found(const char *name, ip_addr_t * ipaddr, void *arg) { struct espconn *pespconn = (struct espconn *)arg; if (ipaddr != NULL) { os_printf("Got NTP server: %d.%d.%d.%d\r\n", IP2STR(ipaddr)); // Call the NTP update ntp_server_ip.addr = ipaddr->addr; ntp_get_time(); } } static void ICACHE_FLASH_ATTR ntp_udp_timeout(void *arg) { os_timer_disarm(&ntp_timeout); os_printf("NTP timout\r\n"); // clean up connection if (pCon) { espconn_delete(pCon); os_free(pCon->proto.udp); os_free(pCon); pCon = 0; } } static void ICACHE_FLASH_ATTR ntp_udp_recv(void *arg, char *pdata, unsigned short len) { ntp_t *ntp; struct timeval tv; int32_t hh, mm, ss; if (!ntp_sync_done()) os_printf("NTP synced\r\n"); get_cur_time(&tv); // get the according sys_time; t_offset = get_long_systime(); os_timer_disarm(&ntp_timeout); // extract ntp time ntp = (ntp_t *) pdata; ntp_to_tv(ntp->trans_time, &t_tv); // os_printf("NTP re-sync - diff: %d usecs\r\n", t_tv.tv_usec-tv.tv_usec); /* ss = t_tv.tv_sec%60; mm = (t_tv.tv_sec/60)%60; hh = (t_tv.tv_sec/3600)%24; os_printf("time: %2d:%02d:%02d\r\n", hh, mm, ss); os_printf("Day: %s\r\n", get_weekday()); */ // clean up connection if (pCon) { espconn_delete(pCon); os_free(pCon->proto.udp); os_free(pCon); pCon = 0; } } void ICACHE_FLASH_ATTR ntp_set_server(uint8_t * ntp_server) { ntp_server_ip.addr = 0; // invalid arg? if (ntp_server == NULL) return; // ip or DNS name? if (UTILS_IsIPV4(ntp_server)) { // read address UTILS_StrToIP(ntp_server, &ntp_server_ip); ntp_get_time(); } else { // call DNS and wait for callback espconn_gethostbyname(&pConDNS, ntp_server, &ntp_server_ip, ntp_dns_found); } } bool ICACHE_FLASH_ATTR ntp_sync_done() { return t_offset != 0; } void ICACHE_FLASH_ATTR ntp_get_time() { ntp_t ntp; // either ongoing request or invalid ip? if (pCon != 0 || ntp_server_ip.addr == 0) return; // set up the udp "connection" pCon = (struct espconn *)os_zalloc(sizeof(struct espconn)); pCon->type = ESPCONN_UDP; pCon->state = ESPCONN_NONE; pCon->proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp)); pCon->proto.udp->local_port = espconn_port(); pCon->proto.udp->remote_port = 123; os_memcpy(pCon->proto.udp->remote_ip, &ntp_server_ip, 4); // create a really simple ntp request packet os_memset(&ntp, 0, sizeof(ntp_t)); ntp.options = 0b00011011; // leap = 0, version = 3, mode = 3 (client) // set timeout timer os_timer_disarm(&ntp_timeout); os_timer_setfn(&ntp_timeout, (os_timer_func_t *) ntp_udp_timeout, pCon); os_timer_arm(&ntp_timeout, NTP_TIMEOUT_MS, 0); // send the ntp request espconn_create(pCon); espconn_regist_recvcb(pCon, ntp_udp_recv); espconn_sent(pCon, (uint8 *) & ntp, sizeof(ntp_t)); } void ICACHE_FLASH_ATTR set_time_local(uint16_t h, uint16_t m, uint16_t s) { // get the according sys_time; t_offset = get_long_systime(); t_tv.tv_sec -= t_tv.tv_sec % (3600 * 24); t_tv.tv_sec += (h%24)*3600 + (m%60)*60 + s%60; t_tv.tv_usec = 0; } bool ICACHE_FLASH_ATTR set_weekday_local(char *day) { int i; for (i = 0; i<7; i++) { if (os_strcmp(day, days[i]) == 0) break; } if (i>=7) return false; t_tv.tv_sec = t_tv.tv_sec % (3600 * 24); t_tv.tv_sec += (7 + i-3) * (3600 * 24); return true; }