#include <stdio.h>
#include <string.h>
#include <time.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
// #include "hardware/i2c.h"
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include "lwip/apps/http_client.h"
// #include "secret.h"
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASSWORD ""
#include "lwip/dns.h"
#include "lwip/apps/http_client.h"
#include "lwip/apps/sntp.h"
#define NTP_SERVER "pool.ntp.org"
#define NTP_MSG_LEN 48
#define NTP_PORT 123
char myBuff[1000];
bool fetched = false;
void result(void *arg, httpc_result_t httpc_result,
u32_t rx_content_len, u32_t srv_res, err_t err)
{
printf("transfer complete\n");
printf("local result=%d\n", httpc_result);
printf("http result=%d\n", srv_res);
}
err_t headers(httpc_state_t *connection, void *arg,
struct pbuf *hdr, u16_t hdr_len, u32_t content_len)
{
printf("headers recieved\n");
printf("content length=%d\n", content_len);
printf("header length %d\n", hdr_len);
return ERR_OK;
}
err_t body(void *arg, struct altcp_pcb *conn,
struct pbuf *p, err_t err)
{
printf("body\n");
pbuf_copy_partial(p, myBuff, p->tot_len, 0);
printf("%s", myBuff);
char *lines = strtok(myBuff, "\n");
// Print lines.
while (lines != NULL)
{
printf("LINE: %s\n", lines);
lines = strtok(NULL, "\n");
}
printf("\n");
return ERR_OK;
}
int wifi_setup()
{
cyw43_arch_init();
cyw43_arch_enable_sta_mode();
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 10000))
{
printf("Cannot find SSID.\n");
cyw43_arch_poll();
// cyw43_arch_disable_sta_mode();
cyw43_arch_deinit();
sleep_ms(1000);
wifi_setup();
}
}
struct NTP_sync
{
bool successful_sync;
ip_addr_t ntp_server_address;
absolute_time_t hw_sync_time;
uint32_t unix_sync; // seconds
};
// NTP data received
void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, uint16_t port)
{
struct NTP_sync *ntp_sync = (struct NTP_sync *)arg;
uint8_t mode = pbuf_get_at(p, 0) & 0x7;
uint8_t stratum = pbuf_get_at(p, 1);
printf("Stratum %d\n", stratum);
printf("mode %d\n", mode);
printf("port %d\n", port);
printf("len %d\n", p->tot_len);
printf("Response IP %s\n", ipaddr_ntoa(addr));
// Check response source, port, message length, mode, and stratum source.
if (ip_addr_cmp(addr, &ntp_sync->ntp_server_address) &&
port == NTP_PORT &&
p->tot_len == NTP_MSG_LEN &&
mode == 0x4 && //
stratum != 0) // should never hit stratum 0
{
// This doesn't account on wire duration. I'm assuming this should be fine,
// as expect this to be <= few seconds.
ntp_sync->hw_sync_time = get_absolute_time();
uint8_t seconds_buf[4] = {0};
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];
uint32_t seconds_since_1970 = seconds_since_1900 - 2208988800; // seconds between 1 Jan 1900 and 1 Jan 1970
ntp_sync->unix_sync = seconds_since_1970;
ntp_sync->successful_sync = true;
printf("Got NTP epoch\n");
}
else
{
printf("invalid ntp response\n");
}
pbuf_free(p);
return;
}
int get_ntp_time(int64_t *unix_ms, absolute_time_t *hw_time)
{
// Setup NTP struct.
struct NTP_sync ntp_sync;
ntp_sync.successful_sync = false;
// Convert DNS name to a specific IP address to query.
int err = -1;
while (err != ERR_OK)
{
err = dns_gethostbyname(NTP_SERVER, &ntp_sync.ntp_server_address, NULL, NULL);
cyw43_arch_poll();
printf("err %d\n", err);
sleep_ms(1000);
}
printf("Found DNS %s at IP address %s\n", NTP_SERVER, ipaddr_ntoa(&ntp_sync.ntp_server_address));
// Send NTP requests; await and parse response.
// cyw43_arch_lwip_begin(); // no-difference
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, NTP_MSG_LEN, PBUF_RAM);
uint8_t *req = (uint8_t *)p->payload; // pointer to payload
memset(req, 0, NTP_MSG_LEN); // fill with 0's
req[0] = 0x1b; // ntp request byte
struct udp_pcb ntp_pcb;
ntp_pcb = *udp_new_ip_type(IPADDR_TYPE_V4);
udp_recv(&ntp_pcb, ntp_recv, &ntp_sync);
while (ntp_sync.successful_sync == false)
{
udp_sendto(&ntp_pcb, p, &ntp_sync.ntp_server_address, NTP_PORT);
// Wait for a response.
for (uint8_t i = 0; i < 100; i++)
{
cyw43_arch_poll();
if (ntp_sync.successful_sync)
{
break;
}
sleep_ms(50);
}
}
// cyw43_arch_lwip_end(); // no-difference
// Cleanup.
// udp_disconnect(&ntp_pcb) // no-difference
udp_remove(&ntp_pcb);
pbuf_free(p);
cyw43_arch_poll();
printf("Cleaned\n");
*unix_ms = (int64_t)ntp_sync.unix_sync * 1000;
*hw_time = ntp_sync.hw_sync_time;
return 1;
}
int main()
{
stdio_init_all();
wifi_setup();
printf("WiFi connection established.\n");
// Synchronise to NTP time.
int64_t unix_sync_ms;
absolute_time_t hw_sync_time;
// get_ntp_time(&unix_sync_ms, &hw_sync_time);
// printf("unix ms: %lld\n", unix_sync_ms);
// Fetch TLE.
httpc_connection_t settings;
settings.result_fn = result;
settings.headers_done_fn = headers;
cyw43_arch_poll();
printf("Getting HTTP...\n");
// err_t err = httpc_get_file_dns(
// "celestrak.org",
// 80,
// "/NORAD/elements/gp.php?CATNR=25544&FORMAT=tle",
// &settings,
// body,
// NULL,
// NULL);
// -- NEVER REACHES BEYOND THIS POINT --
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
while(1) {
cyw43_arch_poll();
printf("Reached loop.\n");
sleep_ms(100);
}
}