2 * Copyright 2017 Jonathan McDowell <noodles@earth.li>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * NTP code based on https://github.com/raburton/esp8266/tree/master/ntp
18 * Those portions MIT licensed:
20 * Copyright (c) 2015 Richard A Burton (richardaburton@gmail.com)
22 * Permission is hereby granted, free of charge, to any person obtaining a copy
23 * of this software and associated documentation files (the "Software"), to deal
24 * in the Software without restriction, including without limitation the rights
25 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26 * copies of the Software, and to permit persons to whom the Software is
27 * furnished to do so, subject to the following conditions:
29 * The above copyright notice and this permission notice shall be included in
30 * all copies or substantial portions of the Software.
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42 #include <user_interface.h>
47 #include "espmissingincludes.h"
51 #define NTP_SERVER "uk.pool.ntp.org"
52 #define NTP_TIMEOUT_MS 5000
54 static uint32_t sys_last_ticks;
55 static uint32_t sys_delta;
56 static os_timer_t ntp_timeout;
58 static ip_addr_t ntp_server_ip;
74 void ICACHE_FLASH_ATTR set_time(uint32_t now)
76 sys_last_ticks = system_get_time();
77 sys_delta = now - (sys_last_ticks / 1000000);
80 uint32_t ICACHE_FLASH_ATTR get_time(void)
84 sys_ticks = system_get_time();
85 if (sys_ticks < sys_last_ticks) {
86 sys_delta += (1ULL << 32ULL) / 1000000;
88 sys_last_ticks = sys_ticks;
90 return sys_ticks / 1000000 + sys_delta;
93 void ICACHE_FLASH_ATTR breakdown_time(uint32_t time, struct tm *result)
95 result->tm_sec = time % 60;
97 result->tm_min = time % 60;
99 result->tm_hour = time % 24;
102 result->tm_year = time / (365 * 4 + 1) * 4 + 70;
106 static void ICACHE_FLASH_ATTR ntp_udp_timeout(void *arg)
108 struct espconn *pCon = (struct espconn *) arg;
110 os_timer_disarm(&ntp_timeout);
111 os_printf("NTP timeout.\n");
113 // clean up connection
115 espconn_delete(pCon);
116 os_free(pCon->proto.udp);
122 static void ICACHE_FLASH_ATTR ntp_udp_recv(void *arg, char *pdata,
125 struct espconn *pCon = (struct espconn *) arg;
130 os_printf("Got NTP response.\n");
132 os_timer_disarm(&ntp_timeout);
135 ntp = (ntp_t *) pdata;
136 timestamp = ntp->trans_time[0] << 24 | ntp->trans_time[1] << 16 |
137 ntp->trans_time[2] << 8 | ntp->trans_time[3];
138 // Convert to Unix time ms
139 timestamp -= 2208988800ULL;
145 breakdown_time(timestamp, &dt);
146 os_printf("%04d %02d:%02d:%02d (%u)\r\n", dt.tm_year, dt.tm_hour,
147 dt.tm_min, dt.tm_sec, timestamp);
149 // clean up connection
151 espconn_delete(pCon);
152 os_free(pCon->proto.udp);
158 void ICACHE_FLASH_ATTR ntp_got_dns(const char *name, ip_addr_t *ip, void *arg)
161 struct espconn *pCon = (struct espconn *) arg;
164 os_printf("NTP DNS request failed.\n");
169 os_printf("Sending NTP request.\n");
171 // Set up the UDP "connection"
172 pCon->type = ESPCONN_UDP;
173 pCon->state = ESPCONN_NONE;
174 pCon->proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp));
175 pCon->proto.udp->local_port = espconn_port();
176 pCon->proto.udp->remote_port = 123;
177 os_memcpy(pCon->proto.udp->remote_ip, &ip->addr, 4);
179 // Create a really simple NTP request packet
180 os_memset(&ntp, 0, sizeof(ntp_t));
181 ntp.options = 0b00100011; // leap = 0, version = 4, mode = 3 (client)
184 os_timer_disarm(&ntp_timeout);
185 os_timer_setfn(&ntp_timeout, (os_timer_func_t*) ntp_udp_timeout, pCon);
186 os_timer_arm(&ntp_timeout, NTP_TIMEOUT_MS, 0);
188 // Send the NTP request
189 espconn_create(pCon);
190 espconn_regist_recvcb(pCon, ntp_udp_recv);
191 espconn_sent(pCon, (uint8_t *) &ntp, sizeof(ntp_t));
194 void ICACHE_FLASH_ATTR ntp_get_time(void)
196 struct espconn *pCon = NULL;
198 os_printf("Sending DNS request for NTP server.\n");
199 pCon = (struct espconn *) os_zalloc(sizeof(struct espconn));
200 espconn_gethostbyname(pCon, NTP_SERVER, &ntp_server_ip, ntp_got_dns);
203 void ICACHE_FLASH_ATTR rtc_init(void)
205 sys_last_ticks = system_get_time();