Pico Led Controller 1.0.3
A project to control LEDs using Raspberry Pi Pico W
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 
13 volatile struct tm *utc = NULL;
14 volatile struct tm *current_utc = NULL;
15 
16 static 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 
36 static 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 
48 static 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 
56 static 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 
72 static 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 
95 static 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 
114 void ntp_deinit(void)
115 {
116  if (utc)
117  {
118  free((void*)utc);
119  utc = NULL;
120  }
121 }
122 
123 void ntp_update_time(void)
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
static NTP_T * ntp_init(void)
Definition: ntp.c:95
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
#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