1616
1717typedef 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
3332static 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
5144static 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
7560static 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
110115static 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