Pico Led Controller 1.0.3
A project to control LEDs using Raspberry Pi Pico W
Loading...
Searching...
No Matches
ntp.c
Go to the documentation of this file.
1#include "ntp.h"
2
3#include <string.h>
4#include <time.h>
5
6#include "pico/stdlib.h"
7#include "pico/cyw43_arch.h"
8
9#include "lwip/dns.h"
10#include "lwip/pbuf.h"
11#include "lwip/udp.h"
12
13volatile struct tm *utc = NULL;
14volatile struct tm *current_utc = NULL;
15
16static void ntp_result(NTP_T* state, int status, time_t *result)
17{
18 if (status == 0 && result)
19 {
20 // *result += TIMEZONE_OFFSET;
21 if (!utc)
22 utc = gmtime(result);
23 current_utc = gmtime(result);
24 printf("Got NTP response: %02d/%02d/%04d %02d:%02d:%02d\n", current_utc->tm_mday, current_utc->tm_mon + 1, current_utc->tm_year + 1900, current_utc->tm_hour, current_utc->tm_min, current_utc->tm_sec);
25 }
26
27 if (state->ntp_resend_alarm > 0)
28 {
29 cancel_alarm(state->ntp_resend_alarm);
30 state->ntp_resend_alarm = 0;
31 }
32 state->ntp_test_time = make_timeout_time_ms(NTP_TEST_TIME);
33 state->dns_request_sent = false;
34}
35
36static void ntp_request(NTP_T *state)
37{
38 cyw43_arch_lwip_begin();
39 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, NTP_MSG_LEN, PBUF_RAM);
40 uint8_t *req = (uint8_t *) p->payload;
41 memset(req, 0, NTP_MSG_LEN);
42 req[0] = 0x1b;
43 udp_sendto(state->ntp_pcb, p, &state->ntp_server_address, NTP_PORT);
44 pbuf_free(p);
45 cyw43_arch_lwip_end();
46}
47
48static int64_t ntp_failed_handler(alarm_id_t id, void *user_data)
49{
50 NTP_T* state = (NTP_T*)user_data;
51 printf("NTP request failed\n");
52 ntp_result(state, -1, NULL);
53 return 0;
54}
55
56static void ntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg)
57{
58 NTP_T *state = (NTP_T*)arg;
59 if (ipaddr)
60 {
61 state->ntp_server_address = *ipaddr;
62 printf("NTP address %s\n", ipaddr_ntoa(ipaddr));
63 ntp_request(state);
64 }
65 else
66 {
67 printf("NTP DNS request failed\n");
68 ntp_result(state, -1, NULL);
69 }
70}
71
72static void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
73{
74 NTP_T *state = (NTP_T*)arg;
75 uint8_t mode = pbuf_get_at(p, 0) & 0x7;
76 uint8_t stratum = pbuf_get_at(p, 1);
77
78 if (ip_addr_cmp(addr, &state->ntp_server_address) && port == NTP_PORT && p->tot_len == NTP_MSG_LEN &&mode == 0x4 && stratum != 0)
79 {
80 uint8_t seconds_buf[4] = {0};
81 pbuf_copy_partial(p, seconds_buf, sizeof(seconds_buf), 40);
82 uint32_t seconds_since_1900 = seconds_buf[0] << 24 | seconds_buf[1] << 16 | seconds_buf[2] << 8 | seconds_buf[3];
83 uint32_t seconds_since_1970 = seconds_since_1900 - NTP_DELTA;
84 time_t epoch = seconds_since_1970;
85 ntp_result(state, 0, &epoch);
86 }
87 else
88 {
89 printf("Invalid NTP response\n");
90 ntp_result(state, -1, NULL);
91 }
92 pbuf_free(p);
93}
94
95static NTP_T* ntp_init(void)
96{
97 NTP_T *state = (NTP_T*)calloc(1, sizeof(NTP_T));
98 if (!state)
99 {
100 printf("Failed to allocate state\n");
101 return NULL;
102 }
103 state->ntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
104 if (!state->ntp_pcb)
105 {
106 printf("Failed to create PCB\n");
107 free(state);
108 return NULL;
109 }
110 udp_recv(state->ntp_pcb, ntp_recv, state);
111 return state;
112}
113
114void ntp_deinit(void)
115{
116 if (utc)
117 {
118 free((void*)utc);
119 utc = NULL;
120 }
121}
122
124{
125 NTP_T *state = ntp_init();
126 if (!state)
127 return;
128 if (absolute_time_diff_us(get_absolute_time(), state->ntp_test_time) < 0 && !state->dns_request_sent)
129 {
130 state->ntp_resend_alarm = add_alarm_in_ms(NTP_RESEND_TIME, ntp_failed_handler, state, true);
131 cyw43_arch_lwip_begin();
132 int err = dns_gethostbyname(NTP_SERVER, &state->ntp_server_address, ntp_dns_found, state);
133 cyw43_arch_lwip_end();
134
135 state->dns_request_sent = true;
136 if (err == ERR_OK)
137 ntp_request(state);
138 else if (err != ERR_INPROGRESS)
139 {
140 printf("DNS request failed\n");
141 ntp_result(state, -1, NULL);
142 }
143 }
144 free(state);
145}
static void ntp_result(NTP_T *state, int status, time_t *result)
Definition ntp.c:16
static int64_t ntp_failed_handler(alarm_id_t id, void *user_data)
Definition ntp.c:48
static void ntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg)
Definition ntp.c:56
void ntp_deinit(void)
NTP deinit.
Definition ntp.c:114
static void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
Definition ntp.c:72
volatile struct tm * current_utc
UTC time struct.
Definition ntp.c:14
volatile struct tm * utc
UTC time struct.
Definition ntp.c:13
static void ntp_request(NTP_T *state)
Definition ntp.c:36
void ntp_update_time(void)
NTP update time.
Definition ntp.c:123
static NTP_T * ntp_init(void)
Definition ntp.c:95
#define NTP_PORT
Definition ntp.h:16
#define NTP_TEST_TIME
Definition ntp.h:18
#define NTP_DELTA
Definition ntp.h:17
#define NTP_SERVER
Definition ntp.h:14
#define NTP_RESEND_TIME
Definition ntp.h:19
#define NTP_MSG_LEN
Definition ntp.h:15
NTP struct.
Definition ntp.h:35
ip_addr_t ntp_server_address
Definition ntp.h:36
absolute_time_t ntp_test_time
Definition ntp.h:39
bool dns_request_sent
Definition ntp.h:37
struct udp_pcb * ntp_pcb
Definition ntp.h:38
alarm_id_t ntp_resend_alarm
Definition ntp.h:40