first request works
This commit is contained in:
parent
ed366c9638
commit
fc24139f5d
@ -28,10 +28,11 @@ pico_sdk_init()
|
|||||||
|
|
||||||
# Add executable. Default name is the project name, version 0.1
|
# Add executable. Default name is the project name, version 0.1
|
||||||
|
|
||||||
add_executable(smart_alarm smart_alarm.cpp http_client_util.c)
|
add_executable(smart_alarm smart_alarm.cpp
|
||||||
|
net_utils.cpp)
|
||||||
|
|
||||||
pico_set_program_name(smart_alarm "smart_alarm")
|
pico_set_program_name(smart_alarm "smart_alarm")
|
||||||
pico_set_program_version(smart_alarm "0.1")
|
pico_set_program_version(smart_alarm "0.2")
|
||||||
|
|
||||||
pico_enable_stdio_uart(smart_alarm 1)
|
pico_enable_stdio_uart(smart_alarm 1)
|
||||||
pico_enable_stdio_usb(smart_alarm 1)
|
pico_enable_stdio_usb(smart_alarm 1)
|
||||||
@ -55,7 +56,6 @@ target_link_libraries(smart_alarm
|
|||||||
pico_cyw43_arch_lwip_threadsafe_background
|
pico_cyw43_arch_lwip_threadsafe_background
|
||||||
pico_lwip_sntp
|
pico_lwip_sntp
|
||||||
hardware_rtc
|
hardware_rtc
|
||||||
pico_lwip_http
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(smart_alarm PRIVATE
|
target_compile_definitions(smart_alarm PRIVATE
|
||||||
|
|||||||
@ -1,141 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "pico/async_context.h"
|
|
||||||
#include "lwip/altcp.h"
|
|
||||||
#include "lwip/altcp_tls.h"
|
|
||||||
#include "example_http_client_util.h"
|
|
||||||
|
|
||||||
#ifndef HTTP_INFO
|
|
||||||
#define HTTP_INFO printf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HTTP_INFOC
|
|
||||||
#define HTTP_INFOC putchar
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HTTP_INFOC
|
|
||||||
#define HTTP_INFOC putchar
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HTTP_DEBUG
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define HTTP_DEBUG
|
|
||||||
#else
|
|
||||||
#define HTTP_DEBUG printf
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HTTP_ERROR
|
|
||||||
#define HTTP_ERROR printf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Print headers to stdout
|
|
||||||
err_t http_client_header_print_fn(__unused httpc_state_t *connection, __unused void *arg, struct pbuf *hdr, u16_t hdr_len, __unused u32_t content_len) {
|
|
||||||
HTTP_INFO("\nheaders %u\n", hdr_len);
|
|
||||||
u16_t offset = 0;
|
|
||||||
while (offset < hdr->tot_len && offset < hdr_len) {
|
|
||||||
char c = (char)pbuf_get_at(hdr, offset++);
|
|
||||||
HTTP_INFOC(c);
|
|
||||||
}
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print body to stdout
|
|
||||||
err_t http_client_receive_print_fn(__unused void *arg, __unused struct altcp_pcb *conn, struct pbuf *p, err_t err) {
|
|
||||||
HTTP_INFO("\ncontent err %d\n", err);
|
|
||||||
u16_t offset = 0;
|
|
||||||
while (offset < p->tot_len) {
|
|
||||||
char c = (char)pbuf_get_at(p, offset++);
|
|
||||||
HTTP_INFOC(c);
|
|
||||||
}
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static err_t internal_header_fn(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len) {
|
|
||||||
assert(arg);
|
|
||||||
EXAMPLE_HTTP_REQUEST_T *req = (EXAMPLE_HTTP_REQUEST_T*)arg;
|
|
||||||
if (req->headers_fn) {
|
|
||||||
return req->headers_fn(connection, req->callback_arg, hdr, hdr_len, content_len);
|
|
||||||
}
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static err_t internal_recv_fn(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err) {
|
|
||||||
assert(arg);
|
|
||||||
EXAMPLE_HTTP_REQUEST_T *req = (EXAMPLE_HTTP_REQUEST_T*)arg;
|
|
||||||
if (req->recv_fn) {
|
|
||||||
return req->recv_fn(req->callback_arg, conn, p, err);
|
|
||||||
}
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void internal_result_fn(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err) {
|
|
||||||
assert(arg);
|
|
||||||
EXAMPLE_HTTP_REQUEST_T *req = (EXAMPLE_HTTP_REQUEST_T*)arg;
|
|
||||||
HTTP_DEBUG("result %d len %u server_response %u err %d\n", httpc_result, rx_content_len, srv_res, err);
|
|
||||||
req->complete = true;
|
|
||||||
req->result = httpc_result;
|
|
||||||
if (req->result_fn) {
|
|
||||||
req->result_fn(req->callback_arg, httpc_result, rx_content_len, srv_res, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override altcp_tls_alloc to set sni
|
|
||||||
static struct altcp_pcb *altcp_tls_alloc_sni(void *arg, u8_t ip_type) {
|
|
||||||
assert(arg);
|
|
||||||
EXAMPLE_HTTP_REQUEST_T *req = (EXAMPLE_HTTP_REQUEST_T*)arg;
|
|
||||||
struct altcp_pcb *pcb = altcp_tls_alloc(req->tls_config, ip_type);
|
|
||||||
if (!pcb) {
|
|
||||||
HTTP_ERROR("Failed to allocate PCB\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
mbedtls_ssl_set_hostname(altcp_tls_context(pcb), req->hostname);
|
|
||||||
return pcb;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a http request, complete when req->complete returns true
|
|
||||||
int http_client_request_async(async_context_t *context, EXAMPLE_HTTP_REQUEST_T *req) {
|
|
||||||
#if LWIP_ALTCP
|
|
||||||
const uint16_t default_port = req->tls_config ? 443 : 80;
|
|
||||||
if (req->tls_config) {
|
|
||||||
if (!req->tls_allocator.alloc) {
|
|
||||||
req->tls_allocator.alloc = altcp_tls_alloc_sni;
|
|
||||||
req->tls_allocator.arg = req;
|
|
||||||
}
|
|
||||||
req->settings.altcp_allocator = &req->tls_allocator;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
const uint16_t default_port = 80;
|
|
||||||
#endif
|
|
||||||
req->complete = false;
|
|
||||||
req->settings.headers_done_fn = req->headers_fn ? internal_header_fn : NULL;
|
|
||||||
req->settings.result_fn = internal_result_fn;
|
|
||||||
async_context_acquire_lock_blocking(context);
|
|
||||||
err_t ret = httpc_get_file_dns(req->hostname, req->port ? req->port : default_port, req->url, &req->settings, internal_recv_fn, req, NULL);
|
|
||||||
async_context_release_lock(context);
|
|
||||||
if (ret != ERR_OK) {
|
|
||||||
HTTP_ERROR("http request failed: %d", ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a http request and only return when it has completed. Returns true on success
|
|
||||||
int http_client_request_sync(async_context_t *context, EXAMPLE_HTTP_REQUEST_T *req) {
|
|
||||||
assert(req);
|
|
||||||
int ret = http_client_request_async(context, req);
|
|
||||||
if (ret != 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
while(!req->complete) {
|
|
||||||
async_context_poll(context);
|
|
||||||
async_context_wait_for_work_ms(context, 1000);
|
|
||||||
}
|
|
||||||
return req->result;
|
|
||||||
}
|
|
||||||
@ -1,126 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef EXAMPLE_HTTP_CLIENT_UTIL_H
|
|
||||||
#define EXAMPLE_HTTP_CLIENT_UTIL_H
|
|
||||||
|
|
||||||
#include "lwip/apps/http_client.h"
|
|
||||||
|
|
||||||
/*! \brief Parameters used to make HTTP request
|
|
||||||
* \ingroup pico_lwip
|
|
||||||
*/
|
|
||||||
typedef struct HTTP_REQUEST {
|
|
||||||
/*!
|
|
||||||
* The name of the host, e.g. www.raspberrypi.com
|
|
||||||
*/
|
|
||||||
const char *hostname;
|
|
||||||
/*!
|
|
||||||
* The url to request, e.g. /favicon.ico
|
|
||||||
*/
|
|
||||||
const char *url;
|
|
||||||
/*!
|
|
||||||
* Function to callback with headers, can be null
|
|
||||||
* @see httpc_headers_done_fn
|
|
||||||
*/
|
|
||||||
httpc_headers_done_fn headers_fn;
|
|
||||||
/*!
|
|
||||||
* Function to callback with results from the server, can be null
|
|
||||||
* @see altcp_recv_fn
|
|
||||||
*/
|
|
||||||
altcp_recv_fn recv_fn;
|
|
||||||
/*!
|
|
||||||
* Function to callback with final results of the request, can be null
|
|
||||||
* @see httpc_result_fn
|
|
||||||
*/
|
|
||||||
httpc_result_fn result_fn;
|
|
||||||
/*!
|
|
||||||
* Callback to pass to calback functions
|
|
||||||
*/
|
|
||||||
void *callback_arg;
|
|
||||||
/*!
|
|
||||||
* The port to use. A default port is chosen if this is set to zero
|
|
||||||
*/
|
|
||||||
uint16_t port;
|
|
||||||
#if LWIP_ALTCP && LWIP_ALTCP_TLS
|
|
||||||
/*!
|
|
||||||
* TLS configuration, can be null or set to a correctly configured tls configuration.
|
|
||||||
* e.g altcp_tls_create_config_client(NULL, 0) would use https without a certificate
|
|
||||||
*/
|
|
||||||
struct altcp_tls_config *tls_config;
|
|
||||||
/*!
|
|
||||||
* TLS allocator, used internall for setting TLS server name indication
|
|
||||||
*/
|
|
||||||
altcp_allocator_t tls_allocator;
|
|
||||||
#endif
|
|
||||||
/*!
|
|
||||||
* LwIP HTTP client settings
|
|
||||||
*/
|
|
||||||
httpc_connection_t settings;
|
|
||||||
/*!
|
|
||||||
* Flag to indicate when the request is complete
|
|
||||||
*/
|
|
||||||
int complete;
|
|
||||||
/*!
|
|
||||||
* Overall result of http request, only valid when complete is set
|
|
||||||
*/
|
|
||||||
httpc_result_t result;
|
|
||||||
|
|
||||||
} HTTP_REQUEST_T;
|
|
||||||
|
|
||||||
struct async_context;
|
|
||||||
|
|
||||||
/*! \brief Perform a http request asynchronously
|
|
||||||
* \ingroup pico_lwip
|
|
||||||
*
|
|
||||||
* Perform the http request asynchronously
|
|
||||||
*
|
|
||||||
* @param context async context
|
|
||||||
* @param req HTTP request parameters. As a minimum this should be initialised to zero with hostname and url set to valid values
|
|
||||||
* @return If zero is returned the request has been made and is complete when \em req->complete is true or the result callback has been called.
|
|
||||||
* A non-zero return value indicates an error.
|
|
||||||
*
|
|
||||||
* @see async_context
|
|
||||||
*/
|
|
||||||
int http_client_request_async(struct async_context *context, HTTP_REQUEST_T *req);
|
|
||||||
|
|
||||||
/*! \brief Perform a http request synchronously
|
|
||||||
* \ingroup pico_lwip
|
|
||||||
*
|
|
||||||
* Perform the http request synchronously
|
|
||||||
*
|
|
||||||
* @param context async context
|
|
||||||
* @param req HTTP request parameters. As a minimum this should be initialised to zero with hostname and url set to valid values
|
|
||||||
* @param result Returns the overall result of the http request when complete. Zero indicates success.
|
|
||||||
*/
|
|
||||||
int http_client_request_sync(struct async_context *context, HTTP_REQUEST_T *req);
|
|
||||||
|
|
||||||
/*! \brief A http header callback that can be passed to \em http_client_init or \em http_client_init_secure
|
|
||||||
* \ingroup pico_http_client
|
|
||||||
*
|
|
||||||
* An implementation of the http header callback which just prints headers to stdout
|
|
||||||
*
|
|
||||||
* @param arg argument specified on initialisation
|
|
||||||
* @param hdr header pbuf(s) (may contain data also)
|
|
||||||
* @param hdr_len length of the headers in 'hdr'
|
|
||||||
* @param content_len content length as received in the headers (-1 if not received)
|
|
||||||
* @return if != zero is returned, the connection is aborted
|
|
||||||
*/
|
|
||||||
err_t http_client_header_print_fn(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len);
|
|
||||||
|
|
||||||
/*! \brief A http recv callback that can be passed to http_client_init or http_client_init_secure
|
|
||||||
* \ingroup pico_http_client
|
|
||||||
*
|
|
||||||
* An implementation of the http recv callback which just prints the http body to stdout
|
|
||||||
*
|
|
||||||
* @param arg argument specified on initialisation
|
|
||||||
* @param conn http client connection
|
|
||||||
* @param p body pbuf(s)
|
|
||||||
* @param err Error code in the case of an error
|
|
||||||
* @return if != zero is returned, the connection is aborted
|
|
||||||
*/
|
|
||||||
err_t http_client_receive_print_fn(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
12
lwipopts.h
12
lwipopts.h
@ -237,11 +237,19 @@ hardware:
|
|||||||
#define SZT_F "u"
|
#define SZT_F "u"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define LWIP_DNS 1
|
||||||
|
|
||||||
#if (LWIP_DNS || LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND)
|
#if (LWIP_DNS || LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND)
|
||||||
/* When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function
|
/* When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function
|
||||||
* returning an u32_t random value*/
|
* returning an u32_t random value*/
|
||||||
#include "lwip/arch.h"
|
#include "lwip/arch.h"
|
||||||
u32_t lwip_rand(void);
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
u32_t lwip_rand(void);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#define LWIP_RAND() lwip_rand()
|
#define LWIP_RAND() lwip_rand()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -255,6 +263,8 @@ void sync_system_time(unsigned int sec, unsigned int usec);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __LWIPOPTS_H__ */
|
#endif /* __LWIPOPTS_H__ */
|
||||||
|
|
||||||
/*****END OF FILE****/
|
/*****END OF FILE****/
|
||||||
|
|||||||
67
net_utils.cpp
Normal file
67
net_utils.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include "hardware/clocks.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
|
#include "pico/cyw43_arch.h"
|
||||||
|
#include "pico/util/datetime.h"
|
||||||
|
#include <lwip/arch.h>
|
||||||
|
#include "lwipopts.h"
|
||||||
|
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
#include "lwip/err.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "lwip/timeouts.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
volatile bool done;
|
||||||
|
ip_addr_t addr;
|
||||||
|
bool success;
|
||||||
|
} dns_blocking_result_t;
|
||||||
|
|
||||||
|
static void blocking_dns_callback(const char *name, const ip_addr_t *ipaddr, void *arg) {
|
||||||
|
dns_blocking_result_t *result = (dns_blocking_result_t *)arg;
|
||||||
|
if (ipaddr != NULL) {
|
||||||
|
result->addr = *ipaddr;
|
||||||
|
result->success = true;
|
||||||
|
} else {
|
||||||
|
result->success = false;
|
||||||
|
}
|
||||||
|
result->done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to synchronously resolve DNS hostname to IP
|
||||||
|
// Returns true if resolved, false otherwise
|
||||||
|
bool dns_resolve_sync(const char *hostname, ip_addr_t *resolved_ip, uint32_t timeout_ms) {
|
||||||
|
dns_blocking_result_t result = {0};
|
||||||
|
uint32_t start_time = sys_now();
|
||||||
|
|
||||||
|
err_t err = dns_gethostbyname(hostname, &result.addr, blocking_dns_callback, &result);
|
||||||
|
|
||||||
|
if (err == ERR_OK) {
|
||||||
|
// Already resolved from cache
|
||||||
|
*resolved_ip = result.addr;
|
||||||
|
return true;
|
||||||
|
} else if (err == ERR_INPROGRESS) {
|
||||||
|
// Wait for resolution with timeout
|
||||||
|
while (!result.done) {
|
||||||
|
if (timeout_ms > 0 && (sys_now() - start_time) > timeout_ms) {
|
||||||
|
return false; // Timeout
|
||||||
|
}
|
||||||
|
sys_check_timeouts();
|
||||||
|
// Sleep or delay depends on your platform
|
||||||
|
sys_msleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
*resolved_ip = result.addr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Failed
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" u32_t lwip_rand(void) {
|
||||||
|
return get_rand_32();
|
||||||
|
}
|
||||||
6
net_utils.h
Normal file
6
net_utils.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef SMART_ALARM_NET_UTILS_H
|
||||||
|
#define SMART_ALARM_NET_UTILS_H
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
|
||||||
|
bool dns_resolve_sync(const char *hostname, ip_addr_t *resolved_ip, uint32_t timeout_ms);
|
||||||
|
#endif //SMART_ALARM_NET_UTILS_H
|
||||||
162
smart_alarm.cpp
162
smart_alarm.cpp
@ -2,20 +2,22 @@
|
|||||||
#include "hardware/rtc.h"
|
#include "hardware/rtc.h"
|
||||||
#include "hardware/spi.h"
|
#include "hardware/spi.h"
|
||||||
#include "hardware/timer.h"
|
#include "hardware/timer.h"
|
||||||
#include "lwip/apps/http_client.h"
|
|
||||||
#include "lwip/apps/sntp.h"
|
#include "lwip/apps/sntp.h"
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
#include "pico/async_context.h"
|
|
||||||
#include "pico/cyw43_arch.h"
|
#include "pico/cyw43_arch.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "pico/util/datetime.h"
|
#include "pico/util/datetime.h"
|
||||||
#include "wifi_conf.h"
|
#include "wifi_conf.h"
|
||||||
#include <lwip/arch.h>
|
#include <lwip/arch.h>
|
||||||
#include <pico/stdio.h>
|
#include <pico/stdio.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
#include "net_utils.h"
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
|
||||||
|
using nlohmann::json;
|
||||||
|
|
||||||
// SPI Defines
|
// SPI Defines
|
||||||
// We are going to use SPI 0, and allocate it to the following GPIO pins
|
// We are going to use SPI 0, and allocate it to the following GPIO pins
|
||||||
@ -27,17 +29,153 @@
|
|||||||
#define PIN_SCK 18
|
#define PIN_SCK 18
|
||||||
#define PIN_MOSI 19
|
#define PIN_MOSI 19
|
||||||
|
|
||||||
err_t get_timezone_offset() {
|
//constexpr char* timezone_api_host = "worldtimeapi.org";
|
||||||
|
//constexpr char* timezone_request = "GET /api/ip HTTP/1.1\r\nHost: worldtimeapi.org\r\nUser-Agent: smart_clock/0.1.0\r\nAccept: */*\r\n\r\n";
|
||||||
|
constexpr char* timezone_api_host = "example.org";
|
||||||
|
constexpr char* timezone_request = "GET / HTTP/1.1\r\nHost: example.org\r\nUser-Agent: curl/8.15.0\r\nAccept: */*\r\n\r\n";
|
||||||
|
static volatile bool request_complete = false;
|
||||||
|
static volatile bool request_error = false;
|
||||||
|
|
||||||
|
static char buffer[1024];
|
||||||
|
|
||||||
|
static err_t connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err) {
|
||||||
|
if (err == ERR_OK) {
|
||||||
|
printf("Connected to server successfully!\n");
|
||||||
|
} else {
|
||||||
|
printf("Connection failed with error: %d\n", err);
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TIMEZONE_OFFSET_SEC 7200
|
|
||||||
|
err_t set_timezone_offset(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err) {
|
||||||
|
printf("\ncontent err %d\n", err);
|
||||||
|
|
||||||
|
if (err != ERR_OK || p == NULL) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16_t offset = 0;
|
||||||
|
while (offset < p->tot_len) {
|
||||||
|
char c = (char)pbuf_get_at(p, offset++);
|
||||||
|
putchar(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf_free(p); // Important: Free the pbuf
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_t timezone_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
|
||||||
|
extern volatile bool request_complete, request_error;
|
||||||
|
u16_t *offset = static_cast<u16_t*>(arg);
|
||||||
|
|
||||||
|
if (p == NULL) {
|
||||||
|
printf("Connection closed by remote host\n");
|
||||||
|
request_complete = true;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == ERR_OK) {
|
||||||
|
printf("Received %u bytes: ", p->tot_len);
|
||||||
|
pbuf_copy_partial(p, buffer, p->tot_len, 0);
|
||||||
|
buffer[p->tot_len] = '\0';
|
||||||
|
|
||||||
|
try {
|
||||||
|
json response = json::parse(buffer);
|
||||||
|
*offset = response["raw_offset"].get<int>() + response["dst_offset"].get<int>();
|
||||||
|
request_complete = true;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
printf("JSON parse error: %s\n", e.what());
|
||||||
|
request_error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_recved(tpcb, p->tot_len);
|
||||||
|
} else {
|
||||||
|
request_error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timezone_err(void *arg, const err_t err) {
|
||||||
|
extern volatile bool request_error;
|
||||||
|
printf("timezone_err: %d:%s\n", err, lwip_strerr(err));
|
||||||
|
request_error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::tuple<u16_t, err_t> get_timezone_offset() {
|
||||||
|
printf("getting timezone offset\n");
|
||||||
|
tcp_pcb *pcb = tcp_new();
|
||||||
|
tcp_recv(pcb, timezone_recv);
|
||||||
|
tcp_err(pcb, timezone_err);
|
||||||
|
static u16_t offset = 0;
|
||||||
|
|
||||||
|
// Reset flags for new request
|
||||||
|
request_complete = false;
|
||||||
|
request_error = false;
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
tcp_arg(pcb, &offset);
|
||||||
|
ip_addr_t server_ip;
|
||||||
|
dns_resolve_sync(timezone_api_host, &server_ip, 5000);
|
||||||
|
|
||||||
|
if (tcp_connect(pcb, &server_ip, 80, connected_callback) == ERR_OK) {
|
||||||
|
tcp_write(pcb, timezone_request, strlen(timezone_request), TCP_WRITE_FLAG_COPY);
|
||||||
|
tcp_output(pcb);
|
||||||
|
|
||||||
|
// Wait until request completes or errors out
|
||||||
|
uint32_t timeout_ms = 10000; // 10 second timeout
|
||||||
|
uint32_t elapsed_ms = 0;
|
||||||
|
const uint32_t poll_interval = 100; // Check every 100ms
|
||||||
|
|
||||||
|
while (!request_complete && !request_error && elapsed_ms < timeout_ms) {
|
||||||
|
sleep_ms(poll_interval);
|
||||||
|
elapsed_ms += poll_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_close(pcb);
|
||||||
|
|
||||||
|
if (request_error) {
|
||||||
|
printf("Request failed due to error\n");
|
||||||
|
return {0,ERR_ABRT};
|
||||||
|
} else if (elapsed_ms >= timeout_ms) {
|
||||||
|
printf("Request timed out\n");
|
||||||
|
return {0,ERR_TIMEOUT};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Failed to connect\n");
|
||||||
|
tcp_close(pcb);
|
||||||
|
return {0,ERR_ABRT};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {offset,ERR_OK};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern "C" void sync_system_time(unsigned int sec, unsigned int usec) {
|
extern "C" void sync_system_time(unsigned int sec, unsigned int usec) {
|
||||||
printf("SNTP callback received: %lu\n", (unsigned long)sec);
|
printf("SNTP callback received: %lu\n", (unsigned long)sec);
|
||||||
time_t unix_time = (time_t)sec;
|
time_t unix_time = (time_t)sec;
|
||||||
|
|
||||||
|
u16_t timezone_offset_sec = []()->u16_t
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto [offset,err] = get_timezone_offset();
|
||||||
|
if (err == ERR_OK)
|
||||||
|
{
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
printf("failed to get timezone offset, retrying\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
||||||
|
|
||||||
// Apply timezone offset for local time
|
// Apply timezone offset for local time
|
||||||
unix_time += TIMEZONE_OFFSET_SEC;
|
unix_time += timezone_offset_sec;
|
||||||
|
|
||||||
struct tm *time_info = gmtime(&unix_time);
|
struct tm *time_info = gmtime(&unix_time);
|
||||||
if (time_info == NULL) {
|
if (time_info == NULL) {
|
||||||
@ -64,7 +202,7 @@ extern "C" void sync_system_time(unsigned int sec, unsigned int usec) {
|
|||||||
if (rtc_set_datetime(&dt)) {
|
if (rtc_set_datetime(&dt)) {
|
||||||
printf("SNTP: Time set to %04d-%02d-%02d %02d:%02d:%02d %s\n", dt.year,
|
printf("SNTP: Time set to %04d-%02d-%02d %02d:%02d:%02d %s\n", dt.year,
|
||||||
dt.month, dt.day, dt.hour, dt.min, dt.sec,
|
dt.month, dt.day, dt.hour, dt.min, dt.sec,
|
||||||
(TIMEZONE_OFFSET_SEC == 0) ? "UTC" : "Local");
|
(timezone_offset_sec == 0) ? "UTC" : "Local");
|
||||||
} else {
|
} else {
|
||||||
printf("SNTP: Failed to set RTC\n");
|
printf("SNTP: Failed to set RTC\n");
|
||||||
}
|
}
|
||||||
@ -103,6 +241,13 @@ int main() {
|
|||||||
printf("Mask: %s\n", ip4addr_ntoa(netif_ip_netmask4(netif_default)));
|
printf("Mask: %s\n", ip4addr_ntoa(netif_ip_netmask4(netif_default)));
|
||||||
printf("Gateway: %s\n", ip4addr_ntoa(netif_ip_gw4(netif_default)));
|
printf("Gateway: %s\n", ip4addr_ntoa(netif_ip_gw4(netif_default)));
|
||||||
|
|
||||||
|
ip_addr_t dns_server;
|
||||||
|
IP_ADDR4(&dns_server, 1, 1, 1, 1);
|
||||||
|
dns_setserver(0, &dns_server);
|
||||||
|
|
||||||
|
IP_ADDR4(&dns_server, 8, 8, 8, 8);
|
||||||
|
dns_setserver(1, &dns_server);
|
||||||
|
|
||||||
printf("Initializing SNTP\n");
|
printf("Initializing SNTP\n");
|
||||||
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||||
sntp_init();
|
sntp_init();
|
||||||
@ -134,5 +279,6 @@ get_timezone_offset();
|
|||||||
printf("failed to get rtc\n");
|
printf("failed to get rtc\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cyw43_arch_lwip_end();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user