Skip to content

Commit 9f2b0a6

Browse files
committed
Improve NTP example
Use async context NTP requests, rather than keeping track of time in the main loop. Detect a key press to exit the example.
1 parent a8a1696 commit 9f2b0a6

File tree

1 file changed

+38
-43
lines changed

1 file changed

+38
-43
lines changed

pico_w/wifi/ntp_client/picow_ntp_client.c

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,17 @@
1616

1717
typedef struct NTP_T_ {
1818
ip_addr_t ntp_server_address;
19-
bool dns_request_sent;
2019
struct udp_pcb *ntp_pcb;
21-
absolute_time_t ntp_test_time;
22-
alarm_id_t ntp_resend_alarm;
20+
async_at_time_worker_t request_worker;
21+
async_at_time_worker_t resend_worker;
2322
} NTP_T;
2423

2524
#define NTP_SERVER "pool.ntp.org"
2625
#define NTP_MSG_LEN 48
2726
#define NTP_PORT 123
2827
#define NTP_DELTA 2208988800 // seconds between 1 Jan 1900 and 1 Jan 1970
29-
#define NTP_TEST_TIME (30 * 1000)
30-
#define NTP_RESEND_TIME (10 * 1000)
28+
#define NTP_TEST_TIME_MS (30 * 1000)
29+
#define NTP_RESEND_TIME_MS (10 * 1000)
3130

3231
// Called with results of operation
3332
static void ntp_result(NTP_T* state, int status, time_t *result) {
@@ -36,17 +35,11 @@ static void ntp_result(NTP_T* state, int status, time_t *result) {
3635
printf("got ntp response: %02d/%02d/%04d %02d:%02d:%02d\n", utc->tm_mday, utc->tm_mon + 1, utc->tm_year + 1900,
3736
utc->tm_hour, utc->tm_min, utc->tm_sec);
3837
}
39-
40-
if (state->ntp_resend_alarm > 0) {
41-
cancel_alarm(state->ntp_resend_alarm);
42-
state->ntp_resend_alarm = 0;
43-
}
44-
state->ntp_test_time = make_timeout_time_ms(NTP_TEST_TIME);
45-
state->dns_request_sent = false;
38+
async_context_remove_at_time_worker(cyw43_arch_async_context(), &state->resend_worker);
39+
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &state->request_worker, NTP_TEST_TIME_MS)); // repeat the request in future
40+
printf("Next request in %ds\n", NTP_TEST_TIME_MS / 1000);
4641
}
4742

48-
static int64_t ntp_failed_handler(alarm_id_t id, void *user_data);
49-
5043
// Make an NTP request
5144
static void ntp_request(NTP_T *state) {
5245
// cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking.
@@ -63,14 +56,6 @@ static void ntp_request(NTP_T *state) {
6356
cyw43_arch_lwip_end();
6457
}
6558

66-
static int64_t ntp_failed_handler(alarm_id_t id, void *user_data)
67-
{
68-
NTP_T* state = (NTP_T*)user_data;
69-
printf("ntp request failed\n");
70-
ntp_result(state, -1, NULL);
71-
return 0;
72-
}
73-
7459
// Call back with a DNS result
7560
static void ntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg) {
7661
NTP_T *state = (NTP_T*)arg;
@@ -106,6 +91,26 @@ static void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_ad
10691
pbuf_free(p);
10792
}
10893

94+
// Called to make a NTP request
95+
static void request_worker_fn(__unused async_context_t *context, async_at_time_worker_t *worker) {
96+
NTP_T* state = (NTP_T*)worker->user_data;
97+
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &state->resend_worker, NTP_RESEND_TIME_MS)); // in case UDP request is lost
98+
int err = dns_gethostbyname(NTP_SERVER, &state->ntp_server_address, ntp_dns_found, state);
99+
if (err == ERR_OK) {
100+
ntp_request(state); // Cached DNS result, make NTP request
101+
} else if (err != ERR_INPROGRESS) { // ERR_INPROGRESS means expect a callback
102+
printf("dns request failed\n");
103+
ntp_result(state, -1, NULL);
104+
}
105+
}
106+
107+
// Called to resend an NTP request if it appears to get lost
108+
static void resend_worker_fn(__unused async_context_t *context, async_at_time_worker_t *worker) {
109+
NTP_T* state = (NTP_T*)worker->user_data;
110+
printf("ntp request failed\n");
111+
ntp_result(state, -1, NULL);
112+
}
113+
109114
// Perform initialisation
110115
static NTP_T* ntp_init(void) {
111116
NTP_T *state = (NTP_T*)calloc(1, sizeof(NTP_T));
@@ -120,6 +125,10 @@ static NTP_T* ntp_init(void) {
120125
return NULL;
121126
}
122127
udp_recv(state->ntp_pcb, ntp_recv, state);
128+
state->request_worker.do_work = request_worker_fn;
129+
state->request_worker.user_data = state;
130+
state->resend_worker.do_work = resend_worker_fn;
131+
state->resend_worker.user_data = state;
123132
return state;
124133
}
125134

@@ -128,34 +137,20 @@ void run_ntp_test(void) {
128137
NTP_T *state = ntp_init();
129138
if (!state)
130139
return;
140+
printf("Press 'q' to quit\n");
141+
hard_assert(async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &state->request_worker, 0)); // make the first request
131142
while(true) {
132-
if (absolute_time_diff_us(get_absolute_time(), state->ntp_test_time) < 0 && !state->dns_request_sent) {
133-
// Set alarm in case udp requests are lost
134-
state->ntp_resend_alarm = add_alarm_in_ms(NTP_RESEND_TIME, ntp_failed_handler, state, true);
135-
136-
// cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking.
137-
// You can omit them if you are in a callback from lwIP. Note that when using pico_cyw_arch_poll
138-
// these calls are a no-op and can be omitted, but it is a good practice to use them in
139-
// case you switch the cyw43_arch type later.
140-
cyw43_arch_lwip_begin();
141-
int err = dns_gethostbyname(NTP_SERVER, &state->ntp_server_address, ntp_dns_found, state);
142-
cyw43_arch_lwip_end();
143-
144-
state->dns_request_sent = true;
145-
if (err == ERR_OK) {
146-
ntp_request(state); // Cached result
147-
} else if (err != ERR_INPROGRESS) { // ERR_INPROGRESS means expect a callback
148-
printf("dns request failed\n");
149-
ntp_result(state, -1, NULL);
150-
}
143+
int key = getchar_timeout_us(0);
144+
if (key == 'q' || key == 'Q') {
145+
break;
151146
}
152147
#if PICO_CYW43_ARCH_POLL
153148
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
154149
// main loop (not from a timer interrupt) to check for Wi-Fi driver or lwIP work that needs to be done.
155150
cyw43_arch_poll();
156151
// you can poll as often as you like, however if you have nothing else to do you can
157152
// choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
158-
cyw43_arch_wait_for_work_until(state->dns_request_sent ? at_the_end_of_time : state->ntp_test_time);
153+
cyw43_arch_wait_for_work_until(at_the_end_of_time);
159154
#else
160155
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
161156
// is done via interrupt in the background. This sleep is just an example of some (blocking)
@@ -176,7 +171,7 @@ int main() {
176171

177172
cyw43_arch_enable_sta_mode();
178173

179-
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
174+
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
180175
printf("failed to connect\n");
181176
return 1;
182177
}

0 commit comments

Comments
 (0)