#include <stdio.h>

#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#include "setupWifi.h"
#include "hardware/rtc.h"
#include "time.h"
#include "lwip/dns.h"

bool getDateNow(struct tm *t)
{
    datetime_t rtc;
    bool state = rtc_get_datetime(&rtc);
    if (state)
    {

        t->tm_sec = rtc.sec;
        t->tm_min = rtc.min;
        t->tm_hour = rtc.hour;
        t->tm_mday = rtc.day;
        t->tm_mon = rtc.month - 1;
        t->tm_year = rtc.year - 1900;
        t->tm_wday = rtc.dotw;
        t->tm_yday = 0;
        t->tm_isdst = -1;
    }
    return state;
}

void setRTC(struct tm *datetime)
{
    datetime_t t;
    t.year = datetime->tm_year + 1900;
    t.month = datetime->tm_mon + 1;
    t.day = datetime->tm_mday;
    t.dotw = datetime->tm_wday;
    t.hour = datetime->tm_hour;
    t.min = datetime->tm_min;
    t.sec = datetime->tm_sec;
    rtc_init();
    rtc_set_datetime(&t);
}
struct timeStatus
{
    bool ready;
    struct udp_pcb *pcb;
};

void recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
    struct timeStatus *tstatus = (struct timeStatus *)arg;
    printf("SNTP responded\n");
    if (p != NULL)
    {
        uint8_t seconds_buf[4];
        pbuf_copy_partial(p, seconds_buf, sizeof(seconds_buf), 40);
        uint32_t seconds_since_1900 = seconds_buf[0] << 24 | seconds_buf[1] << 16 | seconds_buf[2] << 8 | seconds_buf[3];
        time_t seconds_since_1970 = seconds_since_1900 - 2208988800;
        struct tm *datetime = gmtime(&seconds_since_1970);
        setRTC(datetime);
        pbuf_free(p);
        udp_remove(pcb);
        tstatus->pcb=NULL;
        tstatus->ready = true;
    }
}

bool pollSNTP(struct timeStatus *tstatus)
{
    if (tstatus == NULL)
        return true;
    if (tstatus->ready)
    {
        free(tstatus);
        tstatus = NULL;
        return true;
    }
    return false;
}

void dns_found(const char *name, const ip_addr_t *ip, void *arg)
{
    struct timeStatus *tstatus = (struct timeStatus *)arg;
    printf("DNS %s\n", ipaddr_ntoa(ip));
    struct udp_pcb *pcb = udp_new();
    tstatus->pcb = pcb;
    udp_recv(pcb, recv, arg);
    udp_bind(pcb, IP_ADDR_ANY, 123);
    udp_connect(pcb, ip, 123);
    struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 48, PBUF_RAM);
    uint8_t *payload = (uint8_t *)p->payload;
    memset(payload, 0, 48);
    *payload = 0x1b;
    err_t er = udp_send(pcb, p);
    pbuf_free(p);
}

struct timeStatus *getSNTP()
{
    struct timeStatus *tstatus = malloc(sizeof(struct timeStatus));
    tstatus->ready = false;
    tstatus->pcb=NULL;
    ip_addr_t ip;
    cyw43_arch_lwip_begin();
    err_t err = dns_gethostbyname("time.nist.gov", &ip, dns_found, tstatus);
    cyw43_arch_lwip_end();
    if (err == ERR_OK)
    {
        printf("DNS cache %s\n", ipaddr_ntoa(&ip));
        dns_found("", &ip, tstatus);
    }
    return tstatus;
}

void cancelSNTP(struct timeStatus *tstatus)
{
    if (tstatus != NULL)
    {
        udp_remove(tstatus->pcb);
        free(tstatus);
        tstatus = NULL;
        printf("canceled\n");
    }
}

int main()
{
    stdio_init_all();
    connect();

    while (true)
    {
        struct timeStatus *tstatus = getSNTP();
        sleep_ms(500);
        if (pollSNTP(tstatus))
            break;
        cancelSNTP(tstatus);
    }

    while (true)
    {
        struct tm t;
        getDateNow(&t);
        char Date[100];
        strftime(Date, sizeof(Date), "Date: %a, %d %b %Y %k:%M:%S %Z\r\n", &t);
        printf("%s\n", Date);
        sleep_ms(5000);
    }
}

Page 182 SNTP RTC App main program

#include <stdio.h>

#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "setupWifi.h"
#include "hardware/rtc.h"
#include <time.h>
#include "lwip/apps/sntp.h"

void SNTPSetRTC(u32_t t, u32_t us)
{
    printf("updating RTC\n");
    time_t seconds_since_1970 = t - 2208988800;
    struct tm *datetime = gmtime(&seconds_since_1970);
    datetime_t dt;
    dt.year = datetime->tm_year + 1900;
    dt.month = datetime->tm_mon + 1;
    dt.day = datetime->tm_mday;
    dt.dotw = datetime->tm_wday;
    dt.hour = datetime->tm_hour;
    dt.min = datetime->tm_min;
    dt.sec = datetime->tm_sec;
    rtc_init();
    rtc_set_datetime(&dt);
}

bool getDateNow(struct tm *t)
{
    datetime_t rtc;
    bool state = rtc_get_datetime(&rtc);
    if (state)
    {
        t->tm_sec = rtc.sec;
        t->tm_min = rtc.min;
        t->tm_hour = rtc.hour;
        t->tm_mday = rtc.day;
        t->tm_mon = rtc.month - 1;
        t->tm_year = rtc.year - 1900;
        t->tm_wday = rtc.dotw;
        t->tm_yday = 0;
        t->tm_isdst = -1;
    }
    return state;
}

int main()
{
    stdio_init_all();
    connect();

    sntp_setoperatingmode(SNTP_OPMODE_POLL);
    sntp_setservername(0, "pool.ntp.org");
    sntp_init();

    while (true)
    {
        struct tm t;
        if (getDateNow(&t))        {
            char Date[100];
            strftime(Date, sizeof(Date), "Date: %a, %d %b %Y %k:%M:%S %Z\r\n", &t);
            printf("%s\n", Date);
        }
        sleep_ms(5000);
    }
}

Page 183 Full listing not in book

SNTP RTC app lwipopts.h

#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H
#define _LWIPOPTS_EXAMPLE_COMMONH_H


// Common settings used in most of the pico_w examples
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)

// allow override in some examples
#ifndef NO_SYS
#define NO_SYS                      1
#endif
// allow override in some examples
#ifndef LWIP_SOCKET
#define LWIP_SOCKET                 0
#endif
#if PICO_CYW43_ARCH_POLL
#define MEM_LIBC_MALLOC             1
#else
// MEM_LIBC_MALLOC is incompatible with non polling versions
#define MEM_LIBC_MALLOC             0
#endif
#define MEM_ALIGNMENT               4
#define MEM_SIZE                    4000
#define MEMP_NUM_TCP_SEG            32
#define MEMP_NUM_ARP_QUEUE          10
#define PBUF_POOL_SIZE              24
#define LWIP_ARP                    1
#define LWIP_ETHERNET               1
#define LWIP_ICMP                   1
#define LWIP_RAW                    1
#define TCP_WND                     (8 * TCP_MSS)
#define TCP_MSS                     1460
#define TCP_SND_BUF                 (8 * TCP_MSS)
#define TCP_SND_QUEUELEN            ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK  1
#define LWIP_NETIF_LINK_CALLBACK    1
#define LWIP_NETIF_HOSTNAME         1
#define LWIP_NETCONN                0
#define MEM_STATS                   0
#define SYS_STATS                   0
#define MEMP_STATS                  0
#define LINK_STATS                  0
// #define ETH_PAD_SIZE                2
#define LWIP_CHKSUM_ALGORITHM       3
#define LWIP_DHCP                   1
#define LWIP_IPV4                   1
#define LWIP_TCP                    1
#define LWIP_UDP                    1
#define LWIP_DNS                    1
#define LWIP_TCP_KEEPALIVE          1
#define LWIP_NETIF_TX_SINGLE_PBUF   1
#define DHCP_DOES_ARP_CHECK         0
#define LWIP_DHCP_DOES_ACD_CHECK    0

#ifndef NDEBUG
#define LWIP_DEBUG                  1
#define LWIP_STATS                  1
#define LWIP_STATS_DISPLAY          1
#endif

#define ETHARP_DEBUG                LWIP_DBG_OFF
#define NETIF_DEBUG                 LWIP_DBG_OFF
#define PBUF_DEBUG                  LWIP_DBG_OFF
#define API_LIB_DEBUG               LWIP_DBG_OFF
#define API_MSG_DEBUG               LWIP_DBG_OFF
#define SOCKETS_DEBUG               LWIP_DBG_OFF
#define ICMP_DEBUG                  LWIP_DBG_OFF
#define INET_DEBUG                  LWIP_DBG_OFF
#define IP_DEBUG                    LWIP_DBG_OFF
#define IP_REASS_DEBUG              LWIP_DBG_OFF
#define RAW_DEBUG                   LWIP_DBG_OFF
#define MEM_DEBUG                   LWIP_DBG_OFF
#define MEMP_DEBUG                  LWIP_DBG_OFF
#define SYS_DEBUG                   LWIP_DBG_OFF
#define TCP_DEBUG                   LWIP_DBG_OFF
#define TCP_INPUT_DEBUG             LWIP_DBG_OFF
#define TCP_OUTPUT_DEBUG            LWIP_DBG_OFF
#define TCP_RTO_DEBUG               LWIP_DBG_OFF
#define TCP_CWND_DEBUG              LWIP_DBG_OFF
#define TCP_WND_DEBUG               LWIP_DBG_OFF
#define TCP_FR_DEBUG                LWIP_DBG_OFF
#define TCP_QLEN_DEBUG              LWIP_DBG_OFF
#define TCP_RST_DEBUG               LWIP_DBG_OFF
#define UDP_DEBUG                   LWIP_DBG_OFF
#define TCPIP_DEBUG                 LWIP_DBG_OFF
#define PPP_DEBUG                   LWIP_DBG_OFF
#define SLIP_DEBUG                  LWIP_DBG_OFF
#define DHCP_DEBUG                  LWIP_DBG_OFF

#undef TCP_WND
#define TCP_WND  16384

#define SNTP_SERVER_DNS              1
#define SNTP_SUPPORT                 1
#define SNTP_UPDATE_DELAY       60*1000

#define SNTP_SET_SYSTEM_TIME_NTP(sec, us) \
 void SNTPSetRTC(u32_t, u32_t); \
  SNTPSetRTC(sec, us)

#define LWIP_DEBUG 1
#endif /* __LWIPOPTS_H__ */

Page 184 Full listing not in book

SNTP RTC app CMakeLists.txt

cmake_minimum_required(VERSION 3.13)
set(PICO_BOARD pico_w)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

include(pico_sdk_import.cmake)
project(PicoW C CXX ASM)
pico_sdk_init()

add_executable(main
 main.c
)

target_include_directories(main PRIVATE ${CMAKE_CURRENT_LIST_DIR})

target_link_libraries(main pico_stdlib pico_cyw43_arch_lwip_threadsafe_background pico_lwip_sntp hardware_rtc)
pico_add_extra_outputs(main)