3232
3333#include <cyw43.h>
3434#include <dhserver.h>
35+ #include <hardware/rtc.h>
36+ #include <lwip/apps/sntp.h>
3537#include <pico/cyw43_arch.h>
3638
3739#pragma GCC diagnostic pop
@@ -42,7 +44,10 @@ static const char *const ap_atom = ATOM_STR("\x2", "ap");
4244static const char * const ap_sta_connected_atom = ATOM_STR ("\x10" , "ap_sta_connected" );
4345static const char * const ap_sta_disconnected_atom = ATOM_STR ("\x13" , "ap_sta_disconnected" );
4446static const char * const ap_started_atom = ATOM_STR ("\xA" , "ap_started" );
47+ static const char * const host_atom = ATOM_STR ("\x4" , "host" );
4548static const char * const psk_atom = ATOM_STR ("\x3" , "psk" );
49+ static const char * const sntp_atom = ATOM_STR ("\x4" , "sntp" );
50+ static const char * const sntp_sync_atom = ATOM_STR ("\x9" , "sntp_sync" );
4651static const char * const ssid_atom = ATOM_STR ("\x4" , "ssid" );
4752static const char * const sta_atom = ATOM_STR ("\x3" , "sta" );
4853static const char * const sta_connected_atom = ATOM_STR ("\xD" , "sta_connected" );
@@ -67,6 +72,7 @@ struct NetworkDriverData
6772 uint32_t owner_process_id ;
6873 uint64_t ref_ticks ;
6974 int link_status ;
75+ char * sntp_hostname ;
7076 int stas_count ;
7177 uint8_t * stas_mac ;
7278 struct dhcp_config * dhcp_config ;
@@ -169,6 +175,18 @@ static void send_ap_sta_disconnected(uint8_t *mac)
169175 send_atom_mac (globalcontext_make_atom (driver_data -> global , ap_sta_disconnected_atom ), mac );
170176}
171177
178+ static void send_sntp_sync (struct timeval * tv )
179+ {
180+ // {Ref, {sntp_sync, {TVSec, TVUsec}}}
181+ BEGIN_WITH_STACK_HEAP (PORT_REPLY_SIZE + TUPLE_SIZE (2 ) * 2 + BOXED_INT64_SIZE * 2 , heap );
182+ {
183+ term tv_tuple = port_heap_create_tuple2 (& heap , term_make_maybe_boxed_int64 (tv -> tv_sec , & heap ), term_make_maybe_boxed_int64 (tv -> tv_usec , & heap ));
184+ term reply = port_heap_create_tuple2 (& heap , globalcontext_make_atom (driver_data -> global , sntp_sync_atom ), tv_tuple );
185+ send_term (& heap , reply );
186+ }
187+ END_WITH_STACK_HEAP (heap , driver_data -> global );
188+ }
189+
172190static term start_sta (term sta_config , GlobalContext * global )
173191{
174192 term ssid_term = interop_kv_get_value (sta_config , ssid_atom , global );
@@ -374,6 +392,52 @@ static term start_ap(term ap_config, GlobalContext *global)
374392 return setup_dhcp_server ();
375393}
376394
395+ void sntp_set_system_time_us (unsigned long sec , unsigned long usec )
396+ {
397+ struct timeval tv ;
398+ tv .tv_sec = sec ;
399+ tv .tv_usec = usec ;
400+ settimeofday (& tv , NULL );
401+
402+ send_sntp_sync (& tv );
403+
404+ // We also set RTC time.
405+ if (UNLIKELY (!rtc_running ())) {
406+ rtc_init ();
407+ }
408+ gettimeofday (& tv , NULL );
409+ struct tm utc ;
410+ gmtime_r (& tv .tv_sec , & utc );
411+ datetime_t pico_datetime ;
412+ pico_datetime .year = utc .tm_year + 1900 ;
413+ pico_datetime .month = utc .tm_mon + 1 ;
414+ pico_datetime .day = utc .tm_mday ;
415+ pico_datetime .dotw = 0 ;
416+ pico_datetime .hour = utc .tm_hour ;
417+ pico_datetime .min = utc .tm_min ;
418+ pico_datetime .sec = utc .tm_sec ;
419+ rtc_set_datetime (& pico_datetime );
420+ }
421+
422+ static void setup_sntp (term sntp_config , GlobalContext * global )
423+ {
424+ if (!term_is_invalid_term (interop_kv_get_value (sntp_config , host_atom , global ))) {
425+ int ok ;
426+ driver_data -> sntp_hostname = interop_term_to_string (interop_kv_get_value (sntp_config , host_atom , global ), & ok );
427+ if (LIKELY (ok )) {
428+ sntp_setoperatingmode (SNTP_OPMODE_POLL );
429+ sntp_setservername (0 , driver_data -> sntp_hostname );
430+ sntp_init ();
431+ } else {
432+ free (driver_data -> sntp_hostname );
433+ }
434+ } else {
435+ sntp_setoperatingmode (SNTP_OPMODE_POLL );
436+ sntp_servermode_dhcp (1 );
437+ sntp_init ();
438+ }
439+ }
440+
377441static void network_driver_netif_status_cb (struct netif * netif )
378442{
379443 // We don't really need to lock to call cyw43_tcpip_link_status
@@ -404,13 +468,16 @@ static void start_network(Context *ctx, term pid, term ref, term config)
404468
405469 if (driver_data == NULL ) {
406470 driver_data = malloc (sizeof (struct NetworkDriverData ));
471+ driver_data -> sntp_hostname = NULL ;
407472 driver_data -> stas_mac = NULL ;
408473 driver_data -> dhcp_config = NULL ;
409474 }
410475 driver_data -> global = ctx -> global ;
411476 driver_data -> owner_process_id = term_to_local_process_id (pid );
412477 driver_data -> ref_ticks = term_to_ref_ticks (ref );
413478 driver_data -> link_status = CYW43_LINK_DOWN ;
479+ free (driver_data -> sntp_hostname );
480+ driver_data -> sntp_hostname = NULL ;
414481 free (driver_data -> stas_mac );
415482 free (driver_data -> dhcp_config );
416483 driver_data -> stas_count = 0 ;
@@ -427,7 +494,7 @@ static void start_network(Context *ctx, term pid, term ref, term config)
427494 return ;
428495 }
429496
430- if (sta_config ) {
497+ if (! term_is_invalid_term ( sta_config ) ) {
431498 term result_atom = start_sta (sta_config , ctx -> global );
432499 if (result_atom != OK_ATOM ) {
433500 term error = port_create_error_tuple (ctx , result_atom );
@@ -440,7 +507,7 @@ static void start_network(Context *ctx, term pid, term ref, term config)
440507 cyw43_arch_enable_sta_mode ();
441508 }
442509
443- if (ap_config ) {
510+ if (! term_is_invalid_term ( ap_config ) ) {
444511 term result_atom = start_ap (ap_config , ctx -> global );
445512 if (result_atom != OK_ATOM ) {
446513 term error = port_create_error_tuple (ctx , result_atom );
@@ -455,6 +522,11 @@ static void start_network(Context *ctx, term pid, term ref, term config)
455522 cyw43_arch_disable_ap_mode ();
456523 }
457524
525+ term sntp_config = interop_kv_get_value_default (config , sntp_atom , term_invalid_term (), ctx -> global );
526+ if (!term_is_invalid_term (sntp_config )) {
527+ setup_sntp (sntp_config , ctx -> global );
528+ }
529+
458530 //
459531 // Done -- send an ok so the FSM can proceed
460532 //
@@ -524,6 +596,7 @@ void network_driver_destroy(GlobalContext *global)
524596 UNUSED (global );
525597
526598 if (driver_data ) {
599+ free (driver_data -> sntp_hostname );
527600 free (driver_data -> stas_mac );
528601 if (driver_data -> dhcp_config ) {
529602 dhserv_free ();
0 commit comments