-
Notifications
You must be signed in to change notification settings - Fork 0
/
sntp_rtc_sync.cpp
106 lines (92 loc) · 2.78 KB
/
sntp_rtc_sync.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "sntp_rtc_sync.h"
#include "pico/stdlib.h"
#include <stdio.h>
#include "hardware/rtc.h"
#include "lwip/apps/sntp.h"
#include "lwip/dns.h"
#include "lwip/err.h"
#include "lwip/ip_addr.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include "lwip/timeouts.h"
#include "pico/cyw43_arch.h"
#include <string.h>
SyncState synchronization_state = RTC_SYNC_NONE;
int tz_off_s = 0;
/// The LWIP SNTP implementation calls set_system_time when it recieves the time from
/// an SNTP server. We ordinarily have this halt further synchronization and run off
/// the RTC once synchronization has been achieved.
extern "C" {
void set_system_time(u32_t secs, u32_t frac);
}
#define UNIX_EPOCH 2208988800UL
#define EPOCH_2000 946684800UL
#define DAYS_PER_YEAR 365
#define DAYS_PER_4_YEARS (4 * DAYS_PER_YEAR + 1)
// It's everybody's favorite code to implement and test: date handling!
void set_system_time(u32_t secs, u32_t frac)
{
static int month_len[12] = {
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
};
time_t t = secs + tz_off_s - (UNIX_EPOCH + EPOCH_2000); // seconds since NYD 2000
datetime_t dt;
uint32_t time_of_day = t % (60 * 60 * 24);
uint32_t day_number = t / (60 * 60 * 24);
dt.sec = time_of_day % 60;
dt.min = (time_of_day / 60) % 60;
dt.hour = time_of_day / 3600;
dt.dotw = (day_number + 6) % 7; // 2020 started on a Saturday
// We are going to ignore 100-year leap day skips. This code will have
// a Y2.1K problem.
int y4s = day_number / DAYS_PER_4_YEARS;
day_number -= y4s * DAYS_PER_4_YEARS;
dt.year = 2000 + 4 * y4s;
if (day_number > DAYS_PER_YEAR) { // handle leap year
day_number -= DAYS_PER_YEAR + 1;
dt.year++;
}
int ys = day_number / DAYS_PER_YEAR;
dt.year += ys; // this completes the year computation
day_number -= ys * DAYS_PER_YEAR;
int month = 0;
while (day_number >= month_len[month]) {
if (month == 1 && day_number == 28 && (dt.year % 4) == 0)
break; // leap year
day_number -= month_len[month];
month++;
}
// Correct for expected 1-indexing
dt.month = month + 1;
dt.day = day_number + 1;
rtc_init();
rtc_set_datetime(&dt);
synchronization_state = RTC_SYNC_GOOD;
}
// Retrieve and set time from an NTP server; returns true on success.
void start_synchronization(int tz_off, bool blocking)
{
tz_off_s = tz_off * 60 * 60;
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_init();
synchronization_state = RTC_SYNC_TRYING;
if (blocking) {
while (synchronization_state == RTC_SYNC_TRYING) {
// TODO: time out eventually
sleep_ms(1);
}
sntp_stop();
}
}