Merge branch 'bugfix/lwip_core_locking' into 'master'

esp_netif/lwip: Fix core-locking config

Closes IDFGH-8445, IDFGH-9098, and IDFGH-9063

See merge request espressif/esp-idf!20840
This commit is contained in:
David Čermák
2023-01-18 20:31:25 +08:00
44 changed files with 1254 additions and 356 deletions

View File

@@ -8,6 +8,7 @@ endif()
set(srcs_lwip
"lwip/esp_netif_lwip.c"
"lwip/esp_netif_sntp.c"
"lwip/esp_netif_lwip_defaults.c"
"lwip/netif/wlanif.c"
"lwip/netif/ethernetif.c"
@@ -55,3 +56,4 @@ endif()
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_NETIF_COMPONENT_BUILD)

View File

@@ -306,6 +306,34 @@ esp_err_t esp_netif_bridge_fdb_add(esp_netif_t *esp_netif_br, uint8_t *addr, uin
esp_err_t esp_netif_bridge_fdb_remove(esp_netif_t *esp_netif_br, uint8_t *addr);
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
/**
* @brief Cause the TCP/IP stack to join a IPv6 multicast group
*
* @param[in] esp_netif Handle to esp-netif instance
* @param[in] addr The multicast group to join
*
* @return
* - ESP_OK
* - ESP_ERR_ESP_NETIF_INVALID_PARAMS
* - ESP_ERR_ESP_NETIF_MLD6_FAILED
* - ESP_ERR_NO_MEM
*/
esp_err_t esp_netif_join_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr);
/**
* @brief Cause the TCP/IP stack to leave a IPv6 multicast group
*
* @param[in] esp_netif Handle to esp-netif instance
* @param[in] addr The multicast group to leave
*
* @return
* - ESP_OK
* - ESP_ERR_ESP_NETIF_INVALID_PARAMS
* - ESP_ERR_ESP_NETIF_MLD6_FAILED
* - ESP_ERR_NO_MEM
*/
esp_err_t esp_netif_leave_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr);
/**
* @}
*/
@@ -940,6 +968,27 @@ void esp_netif_netstack_buf_ref(void *netstack_buf);
*/
void esp_netif_netstack_buf_free(void *netstack_buf);
/**
* @}
*/
/** @addtogroup ESP_NETIF_TCPIP_EXEC
* @{
*/
/**
* @brief TCPIP thread safe callback used with esp_netif_tcpip_exec()
*/
typedef esp_err_t (*esp_netif_callback_fn)(void *ctx);
/**
* @brief Utility to execute the supplied callback in TCP/IP context
* @param fn Pointer to the callback
* @param ctx Parameter to the callback
* @return The error code (esp_err_t) returned by the callback
*/
esp_err_t esp_netif_tcpip_exec(esp_netif_callback_fn fn, void *ctx);
/**
* @}
*/

View File

@@ -0,0 +1,116 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "freertos/FreeRTOS.h"
#include "esp_err.h"
#include "esp_netif_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup ESP_NETIF_SNTP_API ESP-NETIF SNTP API
* @brief SNTP API for underlying TCP/IP stack
*
*/
/** @addtogroup ESP_NETIF_SNTP_API
* @{
*/
/**
* @brief Time sync notification function
*/
typedef void (*esp_sntp_time_cb_t)(struct timeval *tv);
/**
* @brief Utility macro for providing multiple servers in parentheses
*/
#define ESP_SNTP_SERVER_LIST(...) { __VA_ARGS__ }
/**
* @brief Default configuration to init SNTP with multiple servers
* @param servers_in_list Number of servers in the list
* @param list_of_servers List of servers (use ESP_SNTP_SERVER_LIST(...))
*
*/
#define ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(servers_in_list, list_of_servers) { \
.smooth_sync = false, \
.server_from_dhcp = false, \
.wait_for_sync = true, \
.start = true, \
.sync_cb = NULL, \
.renew_servers_after_new_IP = false, \
.ip_event_to_renew = 0, \
.index_of_first_server = 0, \
.num_of_servers = (servers_in_list), \
.servers = list_of_servers, \
}
/**
* @brief Default configuration with a single server
*/
#define ESP_NETIF_SNTP_DEFAULT_CONFIG(server) \
ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(1, {server})
/**
* @brief SNTP configuration struct
*/
typedef struct esp_sntp_config {
bool smooth_sync; ///< set to true if smooth sync required
bool server_from_dhcp; ///< set to true to request NTP server config from DHCP
bool wait_for_sync; ///< if true, we create a semaphore to signal time sync event
bool start; ///< set to true to automatically start the SNTP service
esp_sntp_time_cb_t sync_cb; ///< optionally sets callback function on time sync event
bool renew_servers_after_new_IP; ///< this is used to refresh server list if NTP provided by DHCP (which cleans other pre-configured servers)
ip_event_t ip_event_to_renew; ///< set the IP event id on which we refresh server list (if renew_servers_after_new_IP=true)
size_t index_of_first_server; ///< refresh server list after this server (if renew_servers_after_new_IP=true)
size_t num_of_servers; ///< number of preconfigured NTP servers
const char* servers[CONFIG_LWIP_SNTP_MAX_SERVERS]; ///< list of servers
} esp_sntp_config_t;
/**
* @brief Initialize SNTP with supplied config struct
* @param config Config struct
* @return ESP_OK on success
*/
esp_err_t esp_netif_sntp_init(const esp_sntp_config_t * config);
/**
* @brief Start SNTP service
* if it wasn't started during init (config.start = false)
* or restart it if already started
* @return ESP_OK on success
*/
esp_err_t esp_netif_sntp_start(void);
/**
* @brief Deinitialize esp_netif SNTP module
*/
void esp_netif_sntp_deinit(void);
/**
* @brief Wait for time sync event
* @param tout Specified timeout in RTOS ticks
* @return ESP_TIMEOUT if sync event didn't came withing the timeout
* ESP_ERR_NOT_FINISHED if the sync event came, but we're in smooth update mode and still in progress (SNTP_SYNC_STATUS_IN_PROGRESS)
* ESP_OK if time sync'ed
*/
esp_err_t esp_netif_sntp_sync_wait(TickType_t tout);
/**
* @}
*/
#ifdef __cplusplus
}
#endif

View File

@@ -97,12 +97,8 @@ typedef enum esp_netif_action {
//
// Internal variables for this module
//
extern sys_thread_t g_lwip_task;
static const char *TAG = "esp_netif_lwip";
static bool tcpip_initialized = false;
#if LWIP_ESP_NETIF_DATA
static u8_t lwip_netif_client_id = 0xff;
#endif
@@ -131,17 +127,28 @@ static void netif_callback_fn(struct netif* netif, netif_nsc_reason_t reason, co
#endif /* #if LWIP_IPV6 */
}
static void set_lwip_netif_callback(void)
#if LWIP_ESP_NETIF_DATA
static esp_err_t alloc_client_data_id(esp_netif_api_msg_t *msg)
{
if (netif_callback.callback_fn == NULL ) {
netif_add_ext_callback(&netif_callback, netif_callback_fn);
}
uint8_t *client_data_id = msg->data;
*client_data_id = netif_alloc_client_data_id();
return ESP_OK;
}
#endif // LWIP_ESP_NETIF_DATA
static esp_err_t set_lwip_netif_callback(struct esp_netif_api_msg_s *msg)
{
(void)msg;
netif_add_ext_callback(&netif_callback, netif_callback_fn);
return ESP_OK;
}
static void remove_lwip_netif_callback(void)
static esp_err_t remove_lwip_netif_callback(struct esp_netif_api_msg_s *msg)
{
(void)msg;
netif_remove_ext_callback(&netif_callback);
memset(&netif_callback, 0, sizeof(netif_callback));
return ESP_OK;
}
static void dns_clear_servers(bool keep_fallback)
@@ -181,6 +188,7 @@ static void netif_unset_garp_flag(struct netif *netif)
#if !LWIP_TCPIP_CORE_LOCKING
static sys_sem_t api_sync_sem = NULL;
static sys_sem_t api_lock_sem = NULL;
#endif
/**
* @brief Api callback from tcpip thread used to call esp-netif
@@ -197,33 +205,59 @@ static void esp_netif_api_cb(void *api_msg)
msg->ret = msg->api_fn(msg);
ESP_LOGD(TAG, "call api in lwip: ret=0x%x, give sem", msg->ret);
#if !LWIP_TCPIP_CORE_LOCKING
sys_sem_signal(&api_sync_sem);
}
#endif
}
/**
* @brief Initiates a tcpip remote call if called from another task
* or calls the function directly if executed from lwip task
*/
static inline esp_err_t esp_netif_lwip_ipc_call(esp_netif_api_fn fn, esp_netif_t *netif, void *data)
static inline esp_err_t esp_netif_lwip_ipc_call_msg(esp_netif_api_msg_t *msg)
{
if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) {
ESP_LOGD(TAG, "check: remote, if=%p fn=%p\n", msg->esp_netif, msg->api_fn);
#if LWIP_TCPIP_CORE_LOCKING
tcpip_send_msg_wait_sem((tcpip_callback_fn)esp_netif_api_cb, msg, NULL);
#else
sys_arch_sem_wait(&api_lock_sem, 0);
tcpip_send_msg_wait_sem((tcpip_callback_fn)esp_netif_api_cb, msg, &api_sync_sem);
sys_sem_signal(&api_lock_sem);
#endif /* LWIP_TCPIP_CORE_LOCKING */
return msg->ret;
}
ESP_LOGD(TAG, "check: local, if=%p fn=%p\n", msg->esp_netif, msg->api_fn);
return msg->api_fn(msg);
}
static inline esp_err_t esp_netif_lwip_ipc_call(esp_netif_api_fn fn, esp_netif_t* netif, void *data)
{
esp_netif_api_msg_t msg = {
.esp_netif = netif,
.data = data,
.api_fn = fn
};
#if !LWIP_TCPIP_CORE_LOCKING
if (tcpip_initialized && g_lwip_task != xTaskGetCurrentTaskHandle()) {
ESP_LOGD(TAG, "check: remote, if=%p fn=%p\n", netif, fn);
sys_arch_sem_wait(&api_lock_sem, 0);
tcpip_send_msg_wait_sem((tcpip_callback_fn)esp_netif_api_cb, &msg, &api_sync_sem);
sys_sem_signal(&api_lock_sem);
return msg.ret;
}
#endif /* !LWIP_TCPIP_CORE_LOCKING */
ESP_LOGD(TAG, "check: local, if=%p fn=%p\n", netif, fn);
return fn(&msg);
return esp_netif_lwip_ipc_call_msg(&msg);
}
static inline esp_err_t esp_netif_lwip_ipc_call_fn(esp_netif_api_fn fn, esp_netif_callback_fn user_fn, void *ctx)
{
esp_netif_api_msg_t msg = {
.user_fn = user_fn,
.data = ctx,
.api_fn = fn
};
return esp_netif_lwip_ipc_call_msg(&msg);
}
static inline esp_err_t esp_netif_lwip_ipc_no_args(esp_netif_api_fn fn)
{
esp_netif_api_msg_t msg = {
.api_fn = fn
};
return esp_netif_lwip_ipc_call_msg(&msg);
}
/**
@@ -451,10 +485,15 @@ void* esp_netif_get_netif_impl(esp_netif_t *esp_netif)
return NULL;
}
static void tcpip_init_done(void *arg)
{
sys_sem_t *init_sem = arg;
sys_sem_signal(init_sem);
}
esp_err_t esp_netif_init(void)
{
if (tcpip_initialized == false) {
tcpip_initialized = true;
if (!sys_thread_tcpip(LWIP_CORE_IS_TCPIP_INITIALIZED)) {
#if CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT
uint8_t rand_buf[16];
/*
@@ -467,13 +506,21 @@ esp_err_t esp_netif_init(void)
esp_fill_random(rand_buf, sizeof(rand_buf));
lwip_init_tcp_isn(esp_log_timestamp(), rand_buf);
#endif
tcpip_init(NULL, NULL);
ESP_LOGD(TAG, "LwIP stack has been initialized");
#if LWIP_ESP_NETIF_DATA
if (lwip_netif_client_id == 0xFF) {
lwip_netif_client_id = netif_alloc_client_data_id();
sys_sem_t init_sem;
if (sys_sem_new(&init_sem, 0) != ERR_OK) {
ESP_LOGE(TAG, "esp netif cannot create tcpip_init semaphore");
return ESP_FAIL;
}
#if LWIP_TCPIP_CORE_LOCKING
/* TCPIP thread is not initialized yet,
* pretend that the calling thread is holder
* to correctly set up the TCPIP task */
sys_thread_tcpip(LWIP_CORE_LOCK_MARK_HOLDER);
#endif
tcpip_init(tcpip_init_done, &init_sem);
sys_sem_wait(&init_sem);
sys_sem_free(&init_sem);
ESP_LOGD(TAG, "LwIP stack has been initialized");
}
#if !LWIP_TCPIP_CORE_LOCKING
@@ -492,18 +539,22 @@ esp_err_t esp_netif_init(void)
}
#endif
#if LWIP_ESP_NETIF_DATA
if (lwip_netif_client_id == 0xFF) {
esp_netif_lwip_ipc_call(alloc_client_data_id, NULL, &lwip_netif_client_id);
}
#endif
ESP_LOGD(TAG, "esp-netif has been successfully initialized");
return ESP_OK;
}
esp_err_t esp_netif_deinit(void)
{
if (tcpip_initialized == true) {
if (sys_thread_tcpip(LWIP_CORE_IS_TCPIP_INITIALIZED)) {
/* deinit of LwIP not supported:
* do not deinit semaphores and states,
* so init could be called multiple times
*
tcpip_initialized = false;
sys_sem_free(&api_sync_sem);
sys_sem_free(&api_lock_sem);
*/
@@ -605,6 +656,16 @@ static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_
return ESP_OK;
}
static esp_err_t tcpip_exec_api(esp_netif_api_msg_t *msg)
{
return msg->user_fn(msg->data);
}
esp_err_t esp_netif_tcpip_exec(esp_netif_callback_fn fn, void*ctx)
{
return esp_netif_lwip_ipc_call_fn(tcpip_exec_api, fn, ctx);
}
esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config)
{
// mandatory configuration must be provided when creating esp_netif object
@@ -650,7 +711,7 @@ esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config)
// Optionally allocate netif client data for esp-netif ptr
// to allow for running esp_netif_new() before esp_netif_init()
if (lwip_netif_client_id == 0xFF) {
lwip_netif_client_id = netif_alloc_client_data_id();
esp_netif_lwip_ipc_call(alloc_client_data_id, NULL, &lwip_netif_client_id);
}
#endif
@@ -689,7 +750,9 @@ esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config)
}
lwip_set_esp_netif(lwip_netif, esp_netif);
set_lwip_netif_callback();
if (netif_callback.callback_fn == NULL ) {
esp_netif_lwip_ipc_no_args(set_lwip_netif_callback);
}
return esp_netif;
}
@@ -771,18 +834,24 @@ static void esp_netif_destroy_related(esp_netif_t *esp_netif)
}
}
static esp_err_t esp_netif_lwip_remove_api(esp_netif_api_msg_t *msg)
{
esp_netif_lwip_remove(msg->esp_netif);
return ESP_OK;
}
void esp_netif_destroy(esp_netif_t *esp_netif)
{
if (esp_netif) {
esp_netif_remove_from_list(esp_netif);
if (esp_netif_get_nr_of_ifs() == 0) {
remove_lwip_netif_callback();
esp_netif_lwip_ipc_no_args(remove_lwip_netif_callback);
}
free(esp_netif->ip_info);
free(esp_netif->ip_info_old);
free(esp_netif->if_key);
free(esp_netif->if_desc);
esp_netif_lwip_remove(esp_netif);
esp_netif_lwip_ipc_call(esp_netif_lwip_remove_api, esp_netif, NULL);
esp_netif_destroy_related(esp_netif);
free(esp_netif->lwip_netif);
free(esp_netif->hostname);
@@ -830,6 +899,15 @@ static esp_err_t esp_netif_reset_ip_info(esp_netif_t *esp_netif)
return ESP_OK;
}
esp_err_t esp_netif_set_mac_api(esp_netif_api_msg_t *msg)
{
uint8_t *mac = msg->data;
esp_netif_t* esp_netif = msg->esp_netif;
memcpy(esp_netif->mac, mac, NETIF_MAX_HWADDR_LEN);
memcpy(esp_netif->lwip_netif->hwaddr, mac, NETIF_MAX_HWADDR_LEN);
return ESP_OK;
}
esp_err_t esp_netif_set_mac(esp_netif_t *esp_netif, uint8_t mac[])
{
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
@@ -838,9 +916,7 @@ esp_err_t esp_netif_set_mac(esp_netif_t *esp_netif, uint8_t mac[])
if (_IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
return ESP_ERR_NOT_SUPPORTED;
}
memcpy(esp_netif->mac, mac, NETIF_MAX_HWADDR_LEN);
memcpy(esp_netif->lwip_netif->hwaddr, mac, NETIF_MAX_HWADDR_LEN);
return ESP_OK;
return esp_netif_lwip_ipc_call(esp_netif_set_mac_api, esp_netif, mac);
}
esp_err_t esp_netif_get_mac(esp_netif_t *esp_netif, uint8_t mac[])
@@ -1952,70 +2028,75 @@ int32_t esp_netif_get_event_id(esp_netif_t *esp_netif, esp_netif_ip_event_type_t
}
}
struct dhcp_params {
esp_netif_dhcp_option_mode_t op;
esp_netif_dhcp_option_id_t id;
void *val;
uint32_t len;
};
#if ESP_DHCPS
esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val,
uint32_t opt_len)
esp_err_t esp_netif_dhcps_option_api(esp_netif_api_msg_t *msg)
{
if (esp_netif == NULL || esp_netif->dhcps == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
void *opt_info = dhcps_option_info(esp_netif->dhcps, opt_id, opt_len);
esp_netif_t *esp_netif = msg->esp_netif;
struct dhcp_params *opt = msg->data;
void *opt_info = dhcps_option_info(esp_netif->dhcps, opt->id, opt->len);
esp_netif_dhcp_status_t dhcps_status = esp_netif->dhcps_status;
if (opt_info == NULL || opt_val == NULL) {
if (opt_info == NULL || opt->val == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (opt_op == ESP_NETIF_OP_GET) {
if (opt->op == ESP_NETIF_OP_GET) {
if (dhcps_status == ESP_NETIF_DHCP_STOPPED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED;
}
switch (opt_id) {
switch (opt->id) {
case IP_ADDRESS_LEASE_TIME: {
*(uint32_t *)opt_val = *(uint32_t *)opt_info;
*(uint32_t *)opt->val = *(uint32_t *)opt_info;
break;
}
case ESP_NETIF_SUBNET_MASK:
case REQUESTED_IP_ADDRESS: {
memcpy(opt_val, opt_info, opt_len);
memcpy(opt->val, opt_info, opt->len);
break;
}
case ROUTER_SOLICITATION_ADDRESS: {
if ((*(uint8_t *)opt_info) & OFFER_ROUTER) {
*(uint8_t *)opt_val = 1;
*(uint8_t *)opt->val = 1;
} else {
*(uint8_t *)opt_val = 0;
*(uint8_t *)opt->val = 0;
}
break;
}
case DOMAIN_NAME_SERVER: {
if ((*(uint8_t *)opt_info) & OFFER_DNS) {
*(uint8_t *)opt_val = 1;
*(uint8_t *)opt->val = 1;
} else {
*(uint8_t *)opt_val = 0;
*(uint8_t *)opt->val = 0;
}
break;
}
default:
break;
}
} else if (opt_op == ESP_NETIF_OP_SET) {
} else if (opt->op == ESP_NETIF_OP_SET) {
if (dhcps_status == ESP_NETIF_DHCP_STARTED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED;
}
switch (opt_id) {
switch (opt->id) {
case IP_ADDRESS_LEASE_TIME: {
if (*(uint32_t *)opt_val != 0) {
*(uint32_t *)opt_info = *(uint32_t *)opt_val;
if (*(uint32_t *)opt->val != 0) {
*(uint32_t *)opt_info = *(uint32_t *)opt->val;
} else {
*(uint32_t *)opt_info = DHCPS_LEASE_TIME_DEF;
}
break;
}
case ESP_NETIF_SUBNET_MASK: {
memcpy(opt_info, opt_val, opt_len);
memcpy(opt_info, opt->val, opt->len);
break;
}
case REQUESTED_IP_ADDRESS: {
@@ -2023,7 +2104,7 @@ esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_m
uint32_t softap_ip = 0;
uint32_t start_ip = 0;
uint32_t end_ip = 0;
dhcps_lease_t *poll = opt_val;
dhcps_lease_t *poll = opt->val;
if (poll->enable) {
memset(&info, 0x00, sizeof(esp_netif_ip_info_t));
@@ -2050,11 +2131,11 @@ esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_m
}
}
memcpy(opt_info, opt_val, opt_len);
memcpy(opt_info, opt->val, opt->len);
break;
}
case ROUTER_SOLICITATION_ADDRESS: {
if (*(uint8_t *)opt_val) {
if (*(uint8_t *)opt->val) {
*(uint8_t *)opt_info |= OFFER_ROUTER;
} else {
*(uint8_t *)opt_info &= ((~OFFER_ROUTER) & 0xFF);
@@ -2062,7 +2143,7 @@ esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_m
break;
}
case DOMAIN_NAME_SERVER: {
if (*(uint8_t *)opt_val) {
if (*(uint8_t *)opt->val) {
*(uint8_t *)opt_info |= OFFER_DNS;
} else {
*(uint8_t *)opt_info &= ((~OFFER_DNS) & 0xFF);
@@ -2073,63 +2154,82 @@ esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_m
default:
break;
}
dhcps_set_option_info(esp_netif->dhcps, opt_id, opt_info, opt_len);
dhcps_set_option_info(esp_netif->dhcps, opt->id, opt_info, opt->len);
} else {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
return ESP_OK;
}
esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val,
uint32_t opt_len)
{
if (esp_netif == NULL || esp_netif->dhcps == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
struct dhcp_params opts = { .op = opt_op, .id = opt_id, .len = opt_len, .val = opt_val };
return esp_netif_lwip_ipc_call(esp_netif_dhcps_option_api, esp_netif, &opts);
}
#endif
esp_err_t esp_netif_dhcpc_option_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
struct dhcp_params *opt = msg->data;
struct dhcp *dhcp = netif_dhcp_data(esp_netif->lwip_netif);
if (dhcp == NULL || opt->val == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (opt->op == ESP_NETIF_OP_GET) {
if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STOPPED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED;
}
switch (opt->id) {
case ESP_NETIF_IP_REQUEST_RETRY_TIME:
if (opt->len == sizeof(dhcp->tries)) {
*(uint8_t *)opt->val = dhcp->tries;
}
break;
#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER
case ESP_NETIF_VENDOR_SPECIFIC_INFO:
return dhcp_get_vendor_specific_information(opt->len, opt->val);
#endif
default:
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
} else if (opt->op == ESP_NETIF_OP_SET) {
if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STARTED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED;
}
switch (opt->id) {
case ESP_NETIF_IP_REQUEST_RETRY_TIME:
if (opt->len == sizeof(dhcp->tries)) {
dhcp->tries = *(uint8_t *)opt->val;
}
break;
#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER
case ESP_NETIF_VENDOR_CLASS_IDENTIFIER:
return dhcp_set_vendor_class_identifier(opt->len, opt->val);
#endif
default:
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
} else {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
return ESP_OK;
}
esp_err_t esp_netif_dhcpc_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val,
uint32_t opt_len)
{
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
struct dhcp *dhcp = netif_dhcp_data(esp_netif->lwip_netif);
if (dhcp == NULL || opt_val == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (opt_op == ESP_NETIF_OP_GET) {
if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STOPPED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED;
}
switch (opt_id) {
case ESP_NETIF_IP_REQUEST_RETRY_TIME:
if (opt_len == sizeof(dhcp->tries)) {
*(uint8_t *)opt_val = dhcp->tries;
}
break;
#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER
case ESP_NETIF_VENDOR_SPECIFIC_INFO:
return dhcp_get_vendor_specific_information(opt_len, opt_val);
#endif
default:
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
} else if (opt_op == ESP_NETIF_OP_SET) {
if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STARTED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED;
}
switch (opt_id) {
case ESP_NETIF_IP_REQUEST_RETRY_TIME:
if (opt_len == sizeof(dhcp->tries)) {
dhcp->tries = *(uint8_t *)opt_val;
}
break;
#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER
case ESP_NETIF_VENDOR_CLASS_IDENTIFIER:
return dhcp_set_vendor_class_identifier(opt_len, opt_val);
#endif
default:
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
} else {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
return ESP_OK;
struct dhcp_params opts = { .op = opt_op, .id = opt_id, .len = opt_len, .val = opt_val };
return esp_netif_lwip_ipc_call(esp_netif_dhcpc_option_api, esp_netif, &opts);
}
int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif)
@@ -2140,6 +2240,13 @@ int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif)
return netif_get_index(esp_netif->lwip_netif);
}
esp_err_t esp_netif_get_netif_impl_name_api(esp_netif_api_msg_t *msg)
{
struct netif* netif = msg->esp_netif->lwip_netif;
netif_index_to_name(netif_get_index(netif), msg->data);
return ESP_OK;
}
esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char* name)
{
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
@@ -2147,8 +2254,7 @@ esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char* name)
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
netif_index_to_name(netif_get_index(esp_netif->lwip_netif), name);
return ESP_OK;
return esp_netif_lwip_ipc_call(esp_netif_get_netif_impl_name_api, esp_netif, name);
}
#if MIB2_STATS

View File

@@ -19,7 +19,10 @@ typedef struct esp_netif_api_msg_s {
int type; /**< The first field MUST be int */
int ret;
esp_netif_api_fn api_fn;
esp_netif_t *esp_netif;
union {
esp_netif_t *esp_netif;
esp_netif_callback_fn user_fn;
};
void *data;
} esp_netif_api_msg_t;

View File

@@ -0,0 +1,179 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_netif.h"
#include "esp_netif_sntp.h"
#include "esp_sntp.h"
// Remove compat macro and include lwip API
#undef SNTP_OPMODE_POLL
#include "lwip/apps/sntp.h"
static const char *TAG = "esp_netif_sntp";
typedef struct sntp_storage {
esp_sntp_time_cb_t sync_cb;
SemaphoreHandle_t sync_sem;
ip_event_t ip_event_to_renew;
size_t index_of_first_server;
size_t num_of_servers;
char* servers[];
} sntp_storage_t;
static sntp_storage_t *s_storage = NULL;
static void sync_time_cb(struct timeval *tv)
{
if (s_storage && s_storage->sync_sem) {
xSemaphoreGive(s_storage->sync_sem);
}
if (s_storage && s_storage->sync_cb) {
s_storage->sync_cb(tv);
}
}
static esp_err_t sntp_init_api(void *ctx)
{
esp_err_t ret = ESP_OK;
esp_sntp_config_t * config = ctx;
ESP_GOTO_ON_FALSE(config->num_of_servers <= SNTP_MAX_SERVERS, ESP_ERR_INVALID_ARG, err, TAG, "Tried to configure more servers than enabled in lwip. Please update CONFIG_SNTP_MAX_SERVERS");
sntp_set_time_sync_notification_cb(sync_time_cb);
sntp_setoperatingmode(SNTP_OPMODE_POLL);
for (int i = 0; i < config->num_of_servers; ++i) {
sntp_setservername(i, config->servers[i]);
}
if (config->server_from_dhcp) {
#if LWIP_DHCP_GET_NTP_SRV
sntp_servermode_dhcp(1);
#else
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "Tried to configure SNTP server from DHCP, while disabled. Please enable CONFIG_LWIP_DHCP_GET_NTP_SRV");
#endif
}
if (config->smooth_sync) {
sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
}
if (config->start) {
sntp_init();
}
err:
return ret;
}
static esp_err_t renew_servers_api(void *ctx)
{
if (s_storage && s_storage->num_of_servers) {
for (int i = 0; i < s_storage->num_of_servers; ++i) {
sntp_setservername(i + s_storage->index_of_first_server, s_storage->servers[i]);
}
}
return ESP_OK;
}
void esp_netif_sntp_renew_servers(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
esp_netif_tcpip_exec(renew_servers_api, NULL);
}
esp_err_t esp_netif_sntp_init(const esp_sntp_config_t * config)
{
esp_err_t ret = ESP_OK;
s_storage = calloc(1, sizeof(sntp_storage_t) + // allocate space for servers only if we are supposed to refresh the settings
(config->renew_servers_after_new_IP ? config->num_of_servers * sizeof(char*) : 0));
ESP_GOTO_ON_FALSE(s_storage != NULL, ESP_ERR_NO_MEM, err, TAG, "Failed to allocate SNTP storage");
if (config->wait_for_sync) {
s_storage->sync_sem = xSemaphoreCreateBinary();
ESP_GOTO_ON_FALSE(s_storage->sync_sem != NULL, ESP_ERR_NO_MEM, err, TAG, "Failed to SNTP sync semaphore");
}
if (config->renew_servers_after_new_IP && config->num_of_servers > 0) {
s_storage->num_of_servers = config->num_of_servers;
s_storage->index_of_first_server = config->index_of_first_server;
// store the server names, as we'd have to refresh the config after IP event
for (int i = 0; i < config->num_of_servers; ++i) {
s_storage->servers[i] = strdup(config->servers[i]);
}
ESP_GOTO_ON_ERROR(esp_event_handler_register(IP_EVENT, config->ip_event_to_renew, esp_netif_sntp_renew_servers, NULL),
err, TAG, "Failed to register IP event");
s_storage->ip_event_to_renew = config->ip_event_to_renew;
}
if (config->sync_cb) {
s_storage->sync_cb = config->sync_cb;
}
ESP_GOTO_ON_ERROR(esp_netif_tcpip_exec(sntp_init_api, (void*)config), err, TAG, "Failed initialize SNTP service");
return ret;
err:
esp_netif_sntp_deinit();
return ret;
}
static esp_err_t sntp_stop_api(void *ctx)
{
sntp_stop();
return ESP_OK;
}
void esp_netif_sntp_deinit(void)
{
if (s_storage) {
sntp_storage_t *storage = s_storage;
s_storage = NULL;
sntp_set_time_sync_notification_cb(NULL);
esp_netif_tcpip_exec(sntp_stop_api, NULL);
if (storage->num_of_servers) {
for (int i = 0; i < storage->num_of_servers; ++i) {
free(storage->servers[i]);
}
esp_event_handler_unregister(IP_EVENT, storage->ip_event_to_renew, esp_netif_sntp_renew_servers);
}
if (storage->sync_sem) {
vSemaphoreDelete(storage->sync_sem);
}
free(storage);
}
}
esp_err_t esp_netif_sntp_sync_wait(TickType_t tout)
{
if (s_storage == NULL || s_storage->sync_sem == NULL) {
return ESP_ERR_INVALID_STATE;
}
if (xQueueSemaphoreTake(s_storage->sync_sem, tout) != pdTRUE) {
return ESP_ERR_TIMEOUT;
}
if (sntp_get_sync_mode() == SNTP_SYNC_MODE_SMOOTH &&
sntp_get_sync_status() == SNTP_SYNC_STATUS_IN_PROGRESS) {
return ESP_ERR_NOT_FINISHED;
}
return ESP_OK;
}
static esp_err_t sntp_start_api(void* ctx)
{
sntp_stop();
sntp_init();
return ESP_OK;
}
esp_err_t esp_netif_sntp_start(void)
{
return esp_netif_tcpip_exec(sntp_start_api, NULL);
}

View File

@@ -1,16 +1,8 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ESP_NETIF_PRIVATE_H_
#define _ESP_NETIF_PRIVATE_H_
@@ -145,34 +137,6 @@ void esp_netif_list_unlock(void);
*/
bool esp_netif_is_netif_listed(esp_netif_t *esp_netif);
/**
* @brief Cause the TCP/IP stack to join a multicast group
*
* @param[in] esp_netif Handle to esp-netif instance
* @param[in] addr The multicast group to join
*
* @return
* - ESP_OK
* - ESP_ERR_ESP_NETIF_INVALID_PARAMS
* - ESP_ERR_ESP_NETIF_MLD6_FAILED
* - ESP_ERR_NO_MEM
*/
esp_err_t esp_netif_join_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr);
/**
* @brief Cause the TCP/IP stack to leave a multicast group
*
* @param[in] esp_netif Handle to esp-netif instance
* @param[in] addr The multicast group to leave
*
* @return
* - ESP_OK
* - ESP_ERR_ESP_NETIF_INVALID_PARAMS
* - ESP_ERR_ESP_NETIF_MLD6_FAILED
* - ESP_ERR_NO_MEM
*/
esp_err_t esp_netif_leave_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr);
/**
* @brief Cause the TCP/IP stack to add an IPv6 address to the interface
*

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -8,21 +8,26 @@
#include "unity.h"
#include "unity_fixture.h"
#include "esp_netif.h"
#include "esp_netif_sntp.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "esp_wifi_netif.h"
#include "sdkconfig.h"
#include "lwip/sockets.h"
#include "test_utils.h"
#include "memory_checks.h"
TEST_GROUP(esp_netif);
TEST_SETUP(esp_netif)
{
test_utils_record_free_mem();
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
}
TEST_TEAR_DOWN(esp_netif)
{
test_utils_finish_and_evaluate_leaks(test_utils_get_leak_level(ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_ALL),
test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_ALL));
}
TEST(esp_netif, init_and_destroy)
@@ -37,6 +42,13 @@ TEST(esp_netif, init_and_destroy)
esp_netif_destroy(esp_netif);
}
TEST(esp_netif, init_and_destroy_sntp)
{
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("127.0.0.1");
config.start = false;
esp_netif_sntp_init(&config);
esp_netif_sntp_deinit();
}
TEST(esp_netif, get_from_if_key)
{
@@ -275,14 +287,22 @@ TEST(esp_netif, get_set_hostname)
TEST_GROUP_RUNNER(esp_netif)
{
/**
* Keep the tests that don't need to start TCP/IP stack first, when the leak checker
* is more strict with leak level set to 0
*/
RUN_TEST_CASE(esp_netif, init_and_destroy)
RUN_TEST_CASE(esp_netif, init_and_destroy_sntp)
RUN_TEST_CASE(esp_netif, get_from_if_key)
RUN_TEST_CASE(esp_netif, create_delete_multiple_netifs)
RUN_TEST_CASE(esp_netif, create_custom_wifi_interfaces)
/**
* After follow tests which start lwIP and thus expect some mem-leaks by TCP/IP stack
*/
RUN_TEST_CASE(esp_netif, get_set_hostname)
RUN_TEST_CASE(esp_netif, dhcp_client_state_transitions_wifi_sta)
RUN_TEST_CASE(esp_netif, dhcp_server_state_transitions_wifi_ap)
RUN_TEST_CASE(esp_netif, dhcp_server_state_transitions_mesh)
RUN_TEST_CASE(esp_netif, create_custom_wifi_interfaces)
RUN_TEST_CASE(esp_netif, get_set_hostname)
}
void app_main(void)

View File

@@ -2,3 +2,4 @@ CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_NETIF_L2_TAP=y
CONFIG_LWIP_CHECK_THREAD_SAFETY=y

View File

@@ -153,6 +153,7 @@ idf_component_register(SRCS "${srcs}"
# lots of LWIP source files evaluate macros that check address of stack variables
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address)
target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_LWIP_COMPONENT_BUILD)
set_source_files_properties(
lwip/src/netif/ppp/pppos.c

View File

@@ -19,12 +19,21 @@ menu "LWIP"
bool "Enable tcpip core locking"
default n
help
If Enable tcpip core locking,Creates a global mutex that is held
If Enable tcpip core locking,Creates a global mutex that is held
during TCPIP thread operations.Can be locked by client code to perform
lwIP operations without changing into TCPIP thread using callbacks.
See LOCK_TCPIP_CORE() and UNLOCK_TCPIP_CORE().
If disable tcpip core locking,TCP IP will perform tasks through context switching
If disable tcpip core locking,TCP IP will perform tasks through context switching
config LWIP_CHECK_THREAD_SAFETY
bool "Checks that lwip API runs in expected context"
default n
help
Enable to check that the project does not violate lwip thread safety.
If enabled, all lwip functions that require thread awareness run an assertion
to verify that the TCP/IP core functionality is either locked or accessed
from the correct thread.
config LWIP_DNS_SUPPORT_MDNS_QUERIES
bool "Enable mDNS queries in resolving host name"

View File

@@ -9,11 +9,18 @@
#include <unistd.h>
#include <sys/time.h>
#include "esp_log.h"
#include "sntp.h"
#include "esp_sntp.h"
// Remove compat macro and include lwip API
#undef SNTP_OPMODE_POLL
#include "lwip/apps/sntp.h"
#include "lwip/tcpip.h"
static const char *TAG = "sntp";
ESP_STATIC_ASSERT(SNTP_OPMODE_POLL == ESP_SNTP_OPMODE_POLL, "SNTP mode in lwip doesn't match the IDF enum. Please make sure lwIP version is correct");
ESP_STATIC_ASSERT(SNTP_OPMODE_LISTENONLY == ESP_SNTP_OPMODE_LISTENONLY, "SNTP mode in lwip doesn't match the IDF enum. Please make sure lwIP version is correct");
static volatile sntp_sync_mode_t sntp_sync_mode = SNTP_SYNC_MODE_IMMED;
static volatile sntp_sync_status_t sntp_sync_status = SNTP_SYNC_STATUS_RESET;
static sntp_sync_time_cb_t time_sync_notification_cb = NULL;
@@ -100,11 +107,17 @@ uint32_t sntp_get_sync_interval(void)
return s_sync_interval;
}
static void sntp_do_restart(void *ctx)
{
(void)ctx;
sntp_stop();
sntp_init();
}
bool sntp_restart(void)
{
if (sntp_enabled()) {
sntp_stop();
sntp_init();
tcpip_callback(sntp_do_restart, NULL);
return true;
}
return false;
@@ -138,3 +151,98 @@ void sntp_get_system_time(uint32_t *sec, uint32_t *us)
*(us) = tv.tv_usec;
sntp_set_sync_status(SNTP_SYNC_STATUS_RESET);
}
static void do_setoperatingmode(void *ctx)
{
esp_sntp_operatingmode_t operating_mode = (esp_sntp_operatingmode_t)ctx;
sntp_setoperatingmode(operating_mode);
}
void esp_sntp_setoperatingmode(esp_sntp_operatingmode_t operating_mode)
{
tcpip_callback(do_setoperatingmode, (void*)operating_mode);
}
static void do_init(void *ctx)
{
sntp_init();
}
void esp_sntp_init(void)
{
tcpip_callback(do_init, NULL);
}
static void do_stop(void *ctx)
{
sntp_stop();
}
void esp_sntp_stop(void)
{
tcpip_callback(do_stop, NULL);
}
struct do_setserver {
u8_t idx;
const ip_addr_t *addr;
};
static void do_setserver(void *ctx)
{
struct do_setserver *params = ctx;
sntp_setserver(params->idx, params->addr);
}
void esp_sntp_setserver(u8_t idx, const ip_addr_t *addr)
{
struct do_setserver params = {
.idx = idx,
.addr = addr
};
tcpip_callback(do_setserver, &params);
}
struct do_setservername {
u8_t idx;
const char *server;
};
static void do_setservername(void *ctx)
{
struct do_setservername *params = ctx;
sntp_setservername(params->idx, params->server);
}
void esp_sntp_setservername(u8_t idx, const char *server)
{
struct do_setservername params = {
.idx = idx,
.server = server
};
tcpip_callback(do_setservername, &params);
}
const char *esp_sntp_getservername(u8_t idx)
{
return sntp_getservername(idx);
}
const ip_addr_t* esp_sntp_getserver(u8_t idx)
{
return sntp_getserver(idx);
}
#if LWIP_DHCP_GET_NTP_SRV
static void do_servermode_dhcp(void* ctx)
{
u8_t servermode = (bool)ctx ? 1 : 0;
sntp_servermode_dhcp(servermode);
}
void esp_sntp_servermode_dhcp(bool enable)
{
tcpip_callback(do_servermode_dhcp, (void*)enable);
}
#endif /* LWIP_DHCP_GET_NTP_SRV */

View File

@@ -8,7 +8,7 @@
#define __ESP_SNTP_H__
#include "lwip/err.h"
#include "lwip/apps/sntp.h"
#include "lwip/ip.h"
#ifdef __cplusplus
@@ -38,6 +38,23 @@ extern "C" {
* to wait for the next sync cycle.
*/
/// Aliases for esp_sntp prefixed API (inherently thread safe)
#define esp_sntp_sync_time sntp_sync_time
#define esp_sntp_set_sync_mode sntp_set_sync_mode
#define esp_sntp_get_sync_mode sntp_get_sync_mode
#define esp_sntp_get_sync_status sntp_get_sync_status
#define esp_sntp_set_sync_status sntp_set_sync_status
#define esp_sntp_set_time_sync_notification_cb sntp_set_time_sync_notification_cb
#define esp_sntp_set_sync_interval sntp_set_sync_interval
#define esp_sntp_get_sync_interval sntp_get_sync_interval
#define esp_sntp_restart sntp_restart
#ifndef SNTP_OPMODE_POLL
#define SNTP_OPMODE_POLL ESP_SNTP_OPMODE_POLL
#else
#warning "Defined!"
#endif /* SNTP_OPMODE_POLL */
/// SNTP time update mode
typedef enum {
SNTP_SYNC_MODE_IMMED, /*!< Update system time immediately when receiving a response from the SNTP server. */
@@ -51,6 +68,12 @@ typedef enum {
SNTP_SYNC_STATUS_IN_PROGRESS, // Smooth time sync in progress.
} sntp_sync_status_t;
/// SNTP operating modes per lwip SNTP module
typedef enum {
ESP_SNTP_OPMODE_POLL,
ESP_SNTP_OPMODE_LISTENONLY,
} esp_sntp_operatingmode_t;
/**
* @brief SNTP callback function for notifying about time sync event
*
@@ -143,6 +166,106 @@ uint32_t sntp_get_sync_interval(void);
*/
bool sntp_restart(void);
/**
* @brief Sets SNTP operating mode. The mode has to be set before init.
*
* @param operating_mode Desired operating mode
*/
void esp_sntp_setoperatingmode(esp_sntp_operatingmode_t operating_mode);
/**
* @brief Init and start SNTP service
*/
void esp_sntp_init(void);
/**
* @brief Stops SNTP service
*/
void esp_sntp_stop(void);
/**
* @brief Sets SNTP server address
*
* @param idx Index of the server
* @param addr IP address of the server
*/
void esp_sntp_setserver(u8_t idx, const ip_addr_t *addr);
/**
* @brief Sets SNTP hostname
* @param idx Index of the server
* @param server Name of the server
*/
void esp_sntp_setservername(u8_t idx, const char *server);
/**
* @brief Gets SNTP server name
* @param idx Index of the server
* @return Name of the server
*/
const char *esp_sntp_getservername(u8_t idx);
/**
* @brief Get SNTP server IP
* @param idx Index of the server
* @return IP address of the server
*/
const ip_addr_t* esp_sntp_getserver(u8_t idx);
#if LWIP_DHCP_GET_NTP_SRV
/**
* @brief Enable acquiring SNTP server from DHCP
* @param enable True for enabling SNTP from DHCP
*/
void esp_sntp_servermode_dhcp(bool enable);
#endif /* LWIP_DHCP_GET_NTP_SRV */
#if !defined(ESP_LWIP_COMPONENT_BUILD) && !defined(ESP_NETIF_COMPONENT_BUILD)
/**
* @brief if not build within lwip, provide translating inlines,
* that will warn about thread safety
*/
static inline __attribute__((deprecated("use esp_sntp_setoperatingmode() instead")))
void sntp_setoperatingmode(u8_t operating_mode)
{
esp_sntp_setoperatingmode(operating_mode);
}
static inline __attribute__((deprecated("use esp_sntp_servermode_dhcp() instead")))
void sntp_servermode_dhcp(int set_servers_from_dhcp)
{
#if LWIP_DHCP_GET_NTP_SRV
esp_sntp_servermode_dhcp(set_servers_from_dhcp);
#endif
}
static inline __attribute__((deprecated("use esp_sntp_setservername() instead")))
void sntp_setservername(u8_t idx, const char *server)
{
esp_sntp_setservername(idx, server);
}
static inline __attribute__((deprecated("use esp_sntp_init() instead")))
void sntp_init(void)
{
esp_sntp_init();
}
static inline __attribute__((deprecated("use esp_sntp_getservername() instead")))
const char *sntp_getservername(u8_t idx)
{
return esp_sntp_getservername(idx);
}
static inline __attribute__((deprecated("use esp_sntp_getserver() instead")))
const ip_addr_t* sntp_getserver(u8_t idx)
{
return esp_sntp_getserver(idx);
}
#endif /* ESP_LWIP_COMPONENT_BUILD */
#ifdef __cplusplus
}
#endif

View File

@@ -1,27 +1,16 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __SNTP_H__
#define __SNTP_H__
#pragma once
#warning "sntp.h in IDF's lwip port folder is deprecated. Please include esp_sntp.h"
/*
* This header is provided only for compatibility reasons for existing
* applications which directly include "sntp.h" from the IDF default paths.
* and will be removed in IDF v5.0.
* and will be removed in IDF v6.0.
* It is recommended to use "esp_sntp.h" from IDF's lwip port folder
*/
#include "esp_sntp.h"
#endif // __SNTP_H__

View File

@@ -53,7 +53,6 @@ static sys_mutex_t g_lwip_protect_mutex = NULL;
static pthread_key_t sys_thread_sem_key;
static void sys_thread_sem_free(void* data);
sys_thread_t g_lwip_task;
#if !LWIP_COMPAT_MUTEX
@@ -428,10 +427,8 @@ sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize
ret = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &rtos_task,
CONFIG_LWIP_TCPIP_TASK_AFFINITY);
g_lwip_task = rtos_task;
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_task_hdlxxx : %x, prio:%d,stack:%d\n",
(u32_t)g_lwip_task,TCPIP_THREAD_PRIO,TCPIP_THREAD_STACKSIZE));
LWIP_DEBUGF(TCPIP_DEBUG, ("new lwip task : %x, prio:%d,stack:%d\n",
(u32_t)rtos_task, prio, stacksize));
if (ret != pdTRUE) {
return NULL;
@@ -577,3 +574,36 @@ sys_delay_ms(uint32_t ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}
bool
sys_thread_tcpip(sys_thread_core_lock_t type)
{
static sys_thread_t lwip_task = NULL;
#if LWIP_TCPIP_CORE_LOCKING
static sys_thread_t core_lock_holder = NULL;
#endif
switch (type) {
default:
return false;
case LWIP_CORE_IS_TCPIP_INITIALIZED:
return lwip_task != NULL;
case LWIP_CORE_MARK_TCPIP_TASK:
LWIP_ASSERT("LWIP_CORE_MARK_TCPIP_TASK: lwip_task == NULL", (lwip_task == NULL));
lwip_task = (sys_thread_t) xTaskGetCurrentTaskHandle();
return true;
#if LWIP_TCPIP_CORE_LOCKING
case LWIP_CORE_LOCK_QUERY_HOLDER:
return lwip_task ? core_lock_holder == (sys_thread_t) xTaskGetCurrentTaskHandle() : true;
case LWIP_CORE_LOCK_MARK_HOLDER:
core_lock_holder = (sys_thread_t) xTaskGetCurrentTaskHandle();
return true;
case LWIP_CORE_LOCK_UNMARK_HOLDER:
core_lock_holder = NULL;
return true;
#else
case LWIP_CORE_LOCK_QUERY_HOLDER:
return lwip_task == NULL || lwip_task == (sys_thread_t) xTaskGetCurrentTaskHandle();
#endif /* LWIP_TCPIP_CORE_LOCKING */
}
return true;
}

View File

@@ -100,6 +100,17 @@ sys_sem_t* sys_thread_sem_init(void);
void sys_thread_sem_deinit(void);
sys_sem_t* sys_thread_sem_get(void);
typedef enum {
LWIP_CORE_LOCK_QUERY_HOLDER,
LWIP_CORE_LOCK_MARK_HOLDER,
LWIP_CORE_LOCK_UNMARK_HOLDER,
LWIP_CORE_MARK_TCPIP_TASK,
LWIP_CORE_IS_TCPIP_INITIALIZED,
} sys_thread_core_lock_t;
bool
sys_thread_tcpip(sys_thread_core_lock_t type);
#ifdef __cplusplus
}
#endif

View File

@@ -12,6 +12,7 @@
#include "lwip/pbuf.h"
#include "netif/dhcp_state.h"
#ifdef ESP_IDF_LWIP_HOOK_FILENAME
#include ESP_IDF_LWIP_HOOK_FILENAME
#endif

View File

@@ -26,6 +26,7 @@
#include "sdkconfig.h"
#include "sntp/sntp_get_set_time.h"
#include "sockets_ext.h"
#include "arch/sys_arch.h"
#ifdef __cplusplus
extern "C" {
@@ -46,9 +47,20 @@ extern "C" {
*/
#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING
#define LWIP_TCPIP_CORE_LOCKING 1
#define LOCK_TCPIP_CORE() do { sys_mutex_lock(&lock_tcpip_core); sys_thread_tcpip(LWIP_CORE_LOCK_MARK_HOLDER); } while(0)
#define UNLOCK_TCPIP_CORE() do { sys_thread_tcpip(LWIP_CORE_LOCK_UNMARK_HOLDER); sys_mutex_unlock(&lock_tcpip_core); } while(0)
#ifdef CONFIG_LWIP_CHECK_THREAD_SAFETY
#define LWIP_ASSERT_CORE_LOCKED() do { LWIP_ASSERT("Required to lock TCPIP core functionality!", sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)); } while(0)
#endif /* CONFIG_LWIP_CHECK_THREAD_SAFETY */
#else
#define LWIP_TCPIP_CORE_LOCKING 0
#endif
#ifdef CONFIG_LWIP_CHECK_THREAD_SAFETY
#define LWIP_ASSERT_CORE_LOCKED() do { LWIP_ASSERT("Required to run in TCPIP context!", sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)); } while(0)
#endif /* CONFIG_LWIP_CHECK_THREAD_SAFETY */
#endif /* CONFIG_LWIP_TCPIP_CORE_LOCKING */
#define LWIP_MARK_TCPIP_THREAD() sys_thread_tcpip(LWIP_CORE_MARK_TCPIP_TASK)
/**
* SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
@@ -845,11 +857,7 @@ static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min)
* The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup().
* Ports may call these for threads created with sys_thread_new().
*/
#if LWIP_TCPIP_CORE_LOCKING
#define LWIP_NETCONN_SEM_PER_THREAD 0
#else
#define LWIP_NETCONN_SEM_PER_THREAD 1
#endif
/** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread,
* writing from a 2nd thread and closing from a 3rd thread at the same time.
@@ -1198,11 +1206,17 @@ static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min)
#endif
#define LWIP_HOOK_FILENAME "lwip_default_hooks.h"
#define LWIP_HOOK_IP4_ROUTE_SRC ip4_route_src_hook
#if LWIP_NETCONN_FULLDUPLEX
#define LWIP_DONE_SOCK(s) done_socket(sock)
#else
#define LWIP_DONE_SOCK(s) ((void)1)
#endif /* LWIP_NETCONN_FULLDUPLEX */
#define LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, err) \
lwip_getsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(done_socket(sock), true): false
lwip_getsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(LWIP_DONE_SOCK(sock), true): false
#define LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) \
lwip_setsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(done_socket(sock), true): false
lwip_setsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(LWIP_DONE_SOCK(sock), true): false
/*
---------------------------------------

View File

@@ -1,2 +1,4 @@
CONFIG_LWIP_TCPIP_CORE_LOCKING=n
CONFIG_LWIP_CHECK_THREAD_SAFETY=n
CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=n
CONFIG_FREERTOS_SMP=n

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -18,6 +18,8 @@
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
#include "lwip/tcpip.h"
#include "lwip/prot/iana.h"
#include "ping/ping_sock.h"
#include "dhcpserver/dhcpserver.h"
#include "dhcpserver/dhcpserver_options.h"
@@ -142,12 +144,18 @@ TEST(lwip, dhcp_server_init_deinit)
dhcps_delete(dhcps);
}
TEST(lwip, dhcp_server_start_stop_localhost)
{
test_case_uses_tcpip();
struct netif *netif;
dhcps_t *dhcps;
struct dhcps_api {
EventGroupHandle_t event;
ip4_addr_t netmask;
ip4_addr_t ip;
err_t ret_start;
err_t ret_stop;
};
static void dhcps_test_net_classes_api(void* ctx)
{
struct netif *netif;
struct dhcps_api *api = ctx;
NETIF_FOREACH(netif) {
if (netif->name[0] == 'l' && netif->name[1] == 'o') {
@@ -156,41 +164,51 @@ TEST(lwip, dhcp_server_start_stop_localhost)
}
TEST_ASSERT_NOT_NULL(netif);
//Class A
dhcps = dhcps_new();
IP4_ADDR(&netmask, 255,0,0,0);
dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&netmask, sizeof(netmask));
ip4_addr_t a_ip = { .addr = 0x7f0001 };
IP4_ADDR(&netmask, 255,0,0,0);
TEST_ASSERT(dhcps_start(dhcps, netif, a_ip) == ERR_OK);
TEST_ASSERT(dhcps_stop(dhcps, netif) == ERR_OK);
dhcps_t *dhcps = dhcps_new();
dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&api->netmask, sizeof(api->netmask));
api->ret_start = dhcps_start(dhcps, netif, api->ip);
api->ret_stop = dhcps_stop(dhcps, netif);
dhcps_delete(dhcps);
xEventGroupSetBits(api->event, 1);
}
//Class B
dhcps = dhcps_new();
IP4_ADDR(&netmask, 255,255,0,0);
dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&netmask, sizeof(netmask));
ip4_addr_t b_ip = { .addr = 0x1000080 };
TEST_ASSERT(dhcps_start(dhcps, netif, b_ip) == ERR_OK);
TEST_ASSERT(dhcps_stop(dhcps, netif) == ERR_OK);
dhcps_delete(dhcps);
static void dhcps_test_net_classes(uint32_t ip, uint32_t mask, bool pass)
{
//Class C
dhcps = dhcps_new();
IP4_ADDR(&netmask, 255,255,255,0);
dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&netmask, sizeof(netmask));
ip4_addr_t c_ip = { .addr = 0x101A8C0 };
TEST_ASSERT(dhcps_start(dhcps, netif, c_ip) == ERR_OK);
TEST_ASSERT(dhcps_stop(dhcps, netif) == ERR_OK);
dhcps_delete(dhcps);
struct dhcps_api api = {
.ret_start = ERR_IF,
.ret_stop = ERR_IF,
.ip = {.addr = PP_HTONL(ip)},
.netmask = {.addr = PP_HTONL(mask)},
.event = xEventGroupCreate()
};
tcpip_callback(dhcps_test_net_classes_api, &api);
xEventGroupWaitBits(api.event, 1, true, true, pdMS_TO_TICKS(5000));
vEventGroupDelete(api.event);
err_t ret_start_expected = pass ? ERR_OK : ERR_ARG;
TEST_ASSERT(api.ret_start == ret_start_expected);
TEST_ASSERT(api.ret_stop == ERR_OK);
}
TEST(lwip, dhcp_server_start_stop_localhost)
{
test_case_uses_tcpip();
// Class A: IP: 127.0.0.1, Mask: 255.0.0.0
dhcps_test_net_classes(0x7f000001, 0xFF000000, true);
// Class B: IP: 128.1.1.1, Mask: 255.255.0.0
dhcps_test_net_classes(0x80010101, 0xFFFF0000, true);
// Class C: IP: 192.168.1.1, Mask: 255.255.255.0
dhcps_test_net_classes(0xC0A80101, 0xFFFFFF00, true);
// Class A: IP: 127.0.0.1, with Class C Mask: 255.255.255.0
// expect dhcps_start() to fail
dhcps_test_net_classes(0x7f000001, 0xFFFFFF00, false);
//Class A Subnet C
dhcps = dhcps_new();
IP4_ADDR(&netmask, 255,255,255,0);
dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&netmask, sizeof(netmask));
TEST_ASSERT(dhcps_start(dhcps, netif, a_ip) == ERR_ARG);
TEST_ASSERT(dhcps_stop(dhcps, netif) == ERR_OK);
dhcps_delete(dhcps);
}
@@ -248,11 +266,10 @@ void test_sntp_timestamps(int year, bool msb_flag)
{
int sock = test_sntp_server_create();
// setup lwip's SNTP in polling mode
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "127.0.0.1");
sntp_init();
// init and start the SNTP
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
esp_sntp_setservername(0, "127.0.0.1");
esp_sntp_init();
// wait until time sync
int retry = 0;
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET) {
@@ -269,7 +286,7 @@ void test_sntp_timestamps(int year, bool msb_flag)
TEST_ASSERT_EQUAL(year, 1900 + timeinfo.tm_year);
// close the SNTP and the fake server
sntp_stop();
esp_sntp_stop();
close(sock);
}

View File

@@ -156,6 +156,7 @@ INPUT = \
$(PROJECT_PATH)/components/esp_netif/include/esp_netif_types.h \
$(PROJECT_PATH)/components/esp_netif/include/esp_netif.h \
$(PROJECT_PATH)/components/esp_netif/include/esp_vfs_l2tap.h \
$(PROJECT_PATH)/components/esp_netif/include/esp_netif_sntp.h \
$(PROJECT_PATH)/components/esp_partition/include/esp_partition.h \
$(PROJECT_PATH)/components/esp_phy/include/esp_phy_init.h \
$(PROJECT_PATH)/components/esp_pm/include/$(IDF_TARGET)/pm.h \

View File

@@ -14,10 +14,15 @@ ESP-IDF supports the following lwIP TCP/IP stack functions:
Adapted APIs
^^^^^^^^^^^^
.. warning::
When using any lwIP API (other than `BSD Sockets API`_), please make sure that it is thread safe. To check if a given API call is safe, enable :ref:`CONFIG_LWIP_CHECK_THREAD_SAFETY` and run the application. This way lwIP asserts the TCP/IP core functionality to be correctly accessed; the execution aborts if it is not locked properly or accessed from the correct task (`lwIP FreeRTOS Task`_).
The general recommendation is to use :doc:`/api-reference/network/esp_netif` component to interact with lwIP.
Some common lwIP "app" APIs are supported indirectly by ESP-IDF:
- DHCP Server & Client are supported indirectly via the :doc:`/api-reference/network/esp_netif` functionality
- Simple Network Time Protocol (SNTP) is supported via the :component_file:`lwip/include/apps/sntp/sntp.h` :component_file:`lwip/lwip/src/include/lwip/apps/sntp.h` functions (see also :ref:`system-time-sntp-sync`)
- Simple Network Time Protocol (SNTP) is also supported via the :doc:`/api-reference/network/esp_netif`, or directly via the :component_file:`lwip/include/apps/esp_sntp.h` functions that provide thread-safe API to :component_file:`lwip/lwip/src/include/lwip/apps/sntp.h` functions (see also :ref:`system-time-sntp-sync`)
- ICMP Ping is supported using a variation on the lwIP ping API. See :doc:`/api-reference/protocols/icmp_echo`.
- NetBIOS lookup is available using the standard lwIP API. :example:`protocols/http_server/restful_server` has an option to demonstrate using NetBIOS to look up a host on the LAN.
- mDNS uses a different implementation to the lwIP default mDNS (see :doc:`/api-reference/protocols/mdns`), but lwIP can look up mDNS hosts using standard APIs such as ``gethostbyname()`` and the convention ``hostname.local``, provided the :ref:`CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES` setting is enabled.

View File

@@ -21,14 +21,14 @@ ESP-NETIF architecture
| (A) USER CODE |
| |
| Apps |
.................| init settings events |
. +----------------------------------------+
. . | *
. . | *
--------+ +===========================+ * +-----------------------+
| | new/config get/set | * | |
| | |...*.....| init |
| | new/config get/set/apps | * | init |
| | |...*.....| Apps (DHCP, SNTP) |
| |---------------------------| * | |
init | | |**** | |
start |************| event handler |*********| DHCP |
@@ -132,6 +132,7 @@ ESP-NETIF is an intermediary between an IO driver and a network stack, connectin
* Set interface up or down
* DHCP server and client API
* DNS API
* `SNTP API`_
6) Driver conversion utilities
@@ -242,6 +243,81 @@ select()
Select is used in a standard way, just :ref:`CONFIG_VFS_SUPPORT_SELECT` needs to be enabled to be the ``select()`` function available.
.. _esp_netif-sntp-api:
SNTP API
--------
You can find a brief introduction to SNTP in general, its initialization code and basic modes in :ref:`system-time-sntp-sync` section in the :doc:`System Time Document</api-reference/system/system_time>`.
This section provides more details about specific use cases of SNTP service, with statically configured servers, or using DHCP provided servers, or both.
The workflow is usually very simple:
1) Initialize and configure the service using :cpp:func:`esp_netif_sntp_init()`.
2) Start the service via :cpp:func:`esp_netif_sntp_start()`. This step is not needed if we auto-started the service in the previous step (default). It's useful to start the service explicitly after connecting, if we want to use DHCP obtained NTP servers. (This option needs to be enabled before connecting, but SNTP service should be started after)
3) Wait for the system time to synchronize using :cpp:func:`esp_netif_sntp_sync_wait()` (only if needed).
4) Stop and destroy the service using :cpp:func:`esp_netif_sntp_deinit()`.
Basic mode with statically defined server(s)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Initialize the module with the default configuration after connecting to network. Note that it's possible to provide multiple NTP servers in the configuration struct:
.. code-block:: c
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2,
ESP_SNTP_SERVER_LIST("time.windows.com", "pool.ntp.org" ) );
esp_netif_sntp_init(&config);
.. note::
If we want to configure multiple SNTP servers, we have to update lwIP configuration :ref:`CONFIG_LWIP_SNTP_MAX_SERVERS`.
Use DHCP obtained SNTP server(s)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
First of all, we have to enable lwIP configuration option :ref:`CONFIG_LWIP_DHCP_GET_NTP_SRV`.
Then we have to initialize the SNTP module with the DHCP option and no NTP server:
.. code-block:: c
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(0, {} );
config.start = false; // start SNTP service explicitly
config.server_from_dhcp = true; // accept NTP offer from DHCP server
esp_netif_sntp_init(&config);
Then, once we're connected, we could start the service using:
.. code-block:: c
esp_netif_sntp_start();
.. note::
It's also possible to start the service during initialization (default ``config.start=true``). This would likely cause the initial SNTP request to fail (since we are not connected yet) and thus some backoff time for subsequent requests.
Use both static and dynamic servers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Very similar to the scenario above (DHCP provided SNTP server), but in this configuration we need to make sure that the static server configuration is refreshed when obtaining NTP servers by DHCP. The underlying lwIP code cleans up the rest of the list of NTP servers when DHCP provided information gets accepted. Thus the ESP-NETIF SNTP module saves the statically configured server(s) and reconfigures them after obtaining DHCP lease.
The typical configuration now looks as per below, providing the specific ``IP_EVENT`` to update the config and index of the first server to reconfigure (for example setting ``config.index_of_first_server=1`` would keep DHCP provided server at index 0, and the statically configured server at index 1).
.. code-block:: c
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
config.start = false; // start SNTP service explicitly (after connecting)
config.server_from_dhcp = true; // accept NTP offers from DHCP server
config.renew_servers_after_new_IP = true; // let esp-netif update configured SNTP server(s) after receiving DHCP lease
config.index_of_first_server = 1; // updates from server num 1, leaving server 0 (from DHCP) intact
config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; // IP event on which we refresh the configuration
Then we start the service normally with :cpp:func:`esp_netif_sntp_start()`.
ESP-NETIF programmer's manual
-----------------------------
@@ -287,6 +363,7 @@ API Reference
-------------
.. include-build-file:: inc/esp_netif.inc
.. include-build-file:: inc/esp_netif_sntp.inc
.. include-build-file:: inc/esp_netif_types.inc
.. include-build-file:: inc/esp_netif_ip_addr.inc
.. include-build-file:: inc/esp_vfs_l2tap.inc

View File

@@ -41,9 +41,9 @@ The RTC timer has the following clock sources:
- ``Internal {IDF_TARGET_RTC_CLK_FRE} RC oscillator`` (default): Features the lowest Deep-sleep current consumption and no dependence on any external components. However, the frequency stability of this clock source is affected by temperature fluctuations, so time may drift in both Deep-sleep and Light-sleep modes.
:not esp32c2: - ``External 32 kHz crystal``: Requires a 32 kHz crystal to be connected to the {IDF_TARGET_EXT_CRYSTAL_PIN} pins. This source provides a better frequency stability at the expense of a slightly higher (by 1 μA) Deep-sleep current consumption.
- ``External 32 kHz oscillator at {IDF_TARGET_EXT_OSC_PIN} pin``: Allows using 32 kHz clock generated by an external circuit. The external clock signal must be connected to the {IDF_TARGET_EXT_OSC_PIN} pin. The amplitude should be less than 1.2 V for sine wave signal and less than 1 V for square wave signal. Common mode voltage should be in the range of 0.1 < Vcm < 0.5xVamp, where Vamp stands for signal amplitude. In this case, the {IDF_TARGET_EXT_OSC_PIN} pin cannot be used as a GPIO pin.
- ``Internal {IDF_TARGET_INT_OSC_FRE} oscillator, divided by 256 ({IDF_TARGET_INT_OSC_FRE_DIVIDED})``: Provides better frequency stability than the ``Internal {IDF_TARGET_RTC_CLK_FRE} RC oscillator`` at the expense of a higher (by 5 μA) Deep-sleep current consumption. It also does not require external components.
The choice depends on your requirements for system time accuracy and power consumption in sleep modes. To modify the RTC clock source, set :ref:`CONFIG_RTC_CLK_SRC` in project configuration.
@@ -108,28 +108,46 @@ SNTP Time Synchronization
To set the current time, you can use the POSIX functions ``settimeofday()`` and ``adjtime()``. They are used internally in the lwIP SNTP library to set current time when a response from the NTP server is received. These functions can also be used separately from the lwIP SNTP library.
The function to use inside the lwIP SNTP library depends on the sync mode for system time. Use the function :cpp:func:`sntp_set_sync_mode` to set one of the following sync modes:
Some lwIP APIs, including SNTP functions, are not thread safe, so it is recommended to use :doc:`esp_netif component <../network/esp_netif>` when interacting with SNTP module.
To initialize a particular SNTP server and also start the SNTP service, simply create a default SNTP server configuration with a particular server name, then call :cpp:func:`esp_netif_sntp_init()` to register that server and start the SNTP service.
.. code-block:: c
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
esp_netif_sntp_init(&config);
This code automatically performs time synchronization once a reply from the SNTP server is received. Sometimes it is useful to wait until the time gets synchronized, :cpp:func:`esp_netif_sntp_sync_wait()` can be used for this purpose:
.. code-block:: c
if (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(10000)) != ESP_OK) {
printf("Failed to update system time within 10s timeout");
}
To configure multiple NTP servers (or use more advanced settings, such as DHCP provided NTP servers), please refer to the detailed description of :ref:`esp_netif-sntp-api` in :doc:`esp_netif <../network/esp_netif>` documentation.
The lwIP SNTP library could work in one of the following sync modes:
- :cpp:enumerator:`SNTP_SYNC_MODE_IMMED` (default): Updates system time immediately upon receiving a response from the SNTP server after using ``settimeofday()``.
- :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH`: Updates time smoothly by gradually reducing time error using the function ``adjtime()``. If the difference between the SNTP response time and system time is more than 35 minutes, update system time immediately by using ``settimeofday()``.
The lwIP SNTP library has API functions for setting a callback function for a certain event. You might need the following functions:
If you want to choose the :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH` mode, please set the :cpp:member:`esp_sntp_config::smooth` to ``true`` in the SNTP configuration struct. Otherwise (and by default) the :cpp:enumerator:`SNTP_SYNC_MODE_IMMED` mode will be used.
- :cpp:func:`sntp_set_time_sync_notification_cb()`: Can be used to set a callback function that will notify of the time synchronization process.
- :cpp:func:`sntp_get_sync_status()` and :cpp:func:`sntp_set_sync_status()`: Can be used to get/set time synchronization status.
To start synchronization via SNTP, just call the following three functions:
.. code-block:: c
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
sntp_init();
For setting a callback function that is called when time gets synchronized, use the :cpp:member:`esp_sntp_config::sync_cb` field in the configuration struct.
An application with this initialization code will periodically synchronize the time. The time synchronization period is determined by :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` (the default value is one hour). To modify the variable, set :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` in project configuration.
A code example that demonstrates the implementation of time synchronization based on the lwIP SNTP library is provided in the :example:`protocols/sntp` directory.
Note that it's also possible to use lwIP API directly, but care must be taken to thread safety. Here we list the thread-safe APIs:
- :cpp:func:`sntp_set_time_sync_notification_cb` can be used to set a callback function that will notify of the time synchronization process.
- :cpp:func:`sntp_get_sync_status` and :cpp:func:`sntp_set_sync_status` can be used to get/set time synchronization status.
- :cpp:func:`sntp_set_sync_mode` can be used to set the synchronization mode.
- :cpp:func:`esp_sntp_setoperatingmode` sets the preferred operating mode.:cpp:enumerator:`ESP_SNTP_OPMODE_POLL` and :cpp:func:`esp_sntp_init` initializes SNTP module.
- :cpp:func:`esp_sntp_setservername` configures one SNTP server.
Timezones
---------

View File

@@ -7,3 +7,4 @@ Migration from 5.0 to 5.1
:maxdepth: 1
peripherals
networking

View File

@@ -0,0 +1,9 @@
Networking
===========
:link_to_translation:`zh_CN:[中文]`
SNTP
----
SNTP module now provides thread safe APIs to access lwIP functionality. It's recommended to use :doc:`ESP_NETIF </api-reference/network/esp_netif>` API. Please refer to the chapter :ref:`esp_netif-sntp-api` for more details.

View File

@@ -41,9 +41,9 @@ RTC 定时器有以下时钟源:
- ``内置 {IDF_TARGET_RTC_CLK_FRE} RC 振荡器`` 默认Deep-sleep 模式下电流消耗最低,不依赖任何外部元件。但由于温度波动会影响该时钟源的频率稳定性,在 Deep-sleep 和 Light-sleep 模式下都有可能发生时间偏移。
:not esp32c2: - ``外置 32 kHz 晶振``:需要将一个 32 kHz 晶振连接到 {IDF_TARGET_EXT_CRYSTAL_PIN} 管脚。频率稳定性更高,但在 Deep-sleep 模式下电流消耗略高(比默认模式高 1 μA
- ``管脚 {IDF_TARGET_EXT_OSC_PIN} 外置 32 kHz 振荡器``:允许使用由外部电路产生的 32 kHz 时钟。外部时钟信号必须连接到管脚 {IDF_TARGET_EXT_OSC_PIN}。正弦波信号的振幅应小于 1.2 V方波信号的振幅应小于 1 V。正常模式下电压范围应为 0.1 < Vcm < 0.5 xVamp其中 Vamp 代表信号振幅。使用此时钟源时,管脚 {IDF_TARGET_EXT_OSC_PIN} 无法用作 GPIO 管脚。
- ``内置 {IDF_TARGET_INT_OSC_FRE} 振荡器的 256 分频时钟 ({IDF_TARGET_INT_OSC_FRE_DIVIDED})``:频率稳定性优于 ``内置 {IDF_TARGET_RTC_CLK_FRE} RC 振荡器``,同样无需外部元件,但 Deep-sleep 模式下电流消耗更高(比默认模式高 5 μA
时钟源的选择取决于系统时间精度要求和睡眠模式下的功耗要求。要修改 RTC 时钟源,请在项目配置中设置 :ref:`CONFIG_RTC_CLK_SRC`
@@ -108,28 +108,46 @@ SNTP 时间同步
要设置当前时间,可以使用 POSIX 函数 ``settimeofday()````adjtime()``。lwIP 中的 SNTP 库会在收到 NTP 服务器的响应报文后,调用这两个函数以更新当前的系统时间。当然,用户可以在 lwIP SNTP 库之外独立地使用这两个函数。
在 lwIP SNTP 库内部调用的函数依赖于系统时间的同步模式。可使用函数 :cpp:func:`sntp_set_sync_mode` 来设置下列同步模式之一
包括 SNTP 函数在内的一些 lwIP API 并非线程安全,因此建议在与 SNTP 模块交互时使用 :doc:`esp_netif component <../network/esp_netif>`
- :cpp:enumerator:`SNTP_SYNC_MODE_IMMED` (默认):使用函数 ``settimeofday()`` 后,收到 SNTP 服务器响应时立即更新系统时间。
- :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH`:使用函数 ``adjtime()`` 后,通过逐渐减小时间误差,平滑地更新时间。如果 SNTP 响应报文中的时间与当前系统时间相差大于 35 分钟,则会通过 ``settimeofday()`` 立即更新系统时间。
lwIP SNTP 库提供了 API 函数,用于设置某个事件的回调函数。您可能需要使用以下函数:
- :cpp:func:`sntp_set_time_sync_notification_cb()`:用于设置回调函数,通知时间同步的过程。
- :cpp:func:`sntp_get_sync_status()`:cpp:func:`sntp_set_sync_status()`:用于获取或设置时间同步状态。
通过 SNTP 开始时间同步,只需调用以下三个函数:
要初始化特定的 SNTP 服务器并启动 SNTP 服务,只需创建有特定服务器名称的默认 SNTP 服务器配置,然后调用 :cpp:func:`esp_netif_sntp_init()` 注册该服务器并启动 SNTP 服务。
.. code-block:: c
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
sntp_init();
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
esp_netif_sntp_init(&config);
一旦收到 SNTP 服务器的响应,此代码会自动执行时间同步。有时等待时间同步很有意义,调用 :cpp:func:`esp_netif_sntp_sync_wait()` 可实现此目的:
.. code-block:: c
if (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(10000)) != ESP_OK) {
printf("Failed to update system time within 10s timeout");
}
要配置多个 NTP 服务器(或使用更高级的设置,例如 DHCP 提供的 NTP 服务器),请参考 :doc:`esp_netif <../network/esp_netif>` 文档 :ref:`esp_netif-sntp-api` 中的详细说明。
lwIP SNTP 库可在下列任一同步模式下工作:
- :cpp:enumerator:`SNTP_SYNC_MODE_IMMED` (默认):使用 ``settimeofday()``,收到 SNTP 服务器响应后立即更新系统时间。
- :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH`:使用函数 ``adjtime()`` 逐渐减少时间误差以平滑更新时间。如果 SNTP 响应时间和系统时间之差超过 35 分钟,请立即使用 ``settimeofday()`` 更新系统时间。
如要选择 :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH` 模式,请将 SNTP 配置结构体中的 :cpp:member:`esp_sntp_config::smooth` 设置为 ``true``,否则将默认使用 :cpp:enumerator:`SNTP_SYNC_MODE_IMMED` 模式。
设置时间同步时的回调函数,请使用配置结构体中的 :cpp:member:`esp_sntp_config::sync_cb` 字段。
添加此初始化代码后,应用程序将定期同步时间。时间同步周期由 :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` 设置(默认为一小时)。如需修改,请在项目配置中设置 :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY`
如需查看示例代码,请前往 :example:`protocols/sntp` 目录。该目录下的示例展示了如何基于 lwIP SNTP 库实现时间同步。
您也可以直接使用 lwIP API但请务必注意线程安全。线程安全的 API 如下:
- :cpp:func:`sntp_set_time_sync_notification_cb` 用于设置通知时间同步过程的回调函数。
- :cpp:func:`sntp_get_sync_status` 和 :cpp:func:`sntp_set_sync_status` 用于获取/设置时间同步状态。
- :cpp:func:`sntp_set_sync_mode` 用于设置同步模式。
- :cpp:func:`esp_sntp_setoperatingmode` 用于设置首选操作模式。:cpp:enumerator:`ESP_SNTP_OPMODE_POLL` 和 :cpp:func:`esp_sntp_init` 可初始化 SNTP 模块。
- :cpp:func:`esp_sntp_setservername` 用于配置特定 SNTP 服务器。
时区
------

View File

@@ -7,3 +7,4 @@
:maxdepth: 1
peripherals
networking

View File

@@ -0,0 +1,9 @@
网络
===========
:link_to_translation:`en:[English]`
SNTP
*****
SNTP 模块现在提供线程安全的 API 用于访问 lwIP 功能。建议使用 :doc:`ESP_NETIF </api-reference/network/esp_netif>` API。了解更多信息请参考章节 :ref:`esp_netif-sntp-api`

View File

@@ -1,6 +1,7 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_ot_cli_extension: "~0.2.0"
espressif/esp_ot_cli_extension:
version: "~0.3.0"
espressif/mdns: "^1.0.3"
## Required IDF version
idf:

View File

@@ -1,5 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_ot_cli_extension: "~0.2.0"
espressif/esp_ot_cli_extension:
version: "~0.3.0"
idf:
version: ">=4.1.0"

View File

@@ -17,11 +17,11 @@
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "lwip/apps/sntp.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "esp_netif.h"
#include "esp_netif_sntp.h"
#include "sdkconfig.h"
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
@@ -90,8 +90,12 @@ static void set_time(void)
settimeofday(&tv, &tz);
/* Start SNTP service */
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_init();
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("time.windows.com");
esp_netif_sntp_init(&config);
if (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(10000)) != ESP_OK) {
printf("Failed to update system time, continuing");
}
esp_netif_deinit();
}
static void http2_task(void *args)

View File

@@ -16,8 +16,8 @@
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_sntp.h"
#include "esp_netif.h"
#include "esp_netif_sntp.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
@@ -33,31 +33,18 @@ static const char *TAG = "time_sync";
void initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "time.windows.com");
sntp_setservername(1, "pool.ntp.org");
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
#endif
sntp_init();
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2,
ESP_SNTP_SERVER_LIST("time.windows.com", "pool.ntp.org" ) );
esp_netif_sntp_init(&config);
}
static esp_err_t obtain_time(void)
{
/**
* NTP server address could be aquired via DHCP,
* see LWIP_DHCP_GET_NTP_SRV menuconfig option
*/
#ifdef LWIP_DHCP_GET_NTP_SRV
sntp_servermode_dhcp(1);
#endif
// wait for time to be set
int retry = 0;
const int retry_count = 10;
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
while (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(2000)) != ESP_OK && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
if (retry == retry_count) {
return ESP_FAIL;
@@ -96,7 +83,7 @@ esp_err_t fetch_and_store_time_in_nvs(void *args)
}
nvs_close(my_handle);
sntp_stop();
esp_netif_deinit();
exit:
if (err != ESP_OK) {

View File

@@ -19,3 +19,4 @@ CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_LWIP_CHECK_THREAD_SAFETY=y

View File

@@ -9,3 +9,5 @@ CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_LWIP_TCPIP_CORE_LOCKING=y
CONFIG_LWIP_CHECK_THREAD_SAFETY=y

View File

@@ -8,3 +8,4 @@ CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_LWIP_CHECK_THREAD_SAFETY=y

View File

@@ -9,3 +9,5 @@ CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_LWIP_TCPIP_CORE_LOCKING=y
CONFIG_LWIP_CHECK_THREAD_SAFETY=y

View File

@@ -9,10 +9,6 @@
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <netdb.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
@@ -20,6 +16,8 @@
#include "esp_sleep.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "esp_netif_sntp.h"
#include "lwip/ip_addr.h"
#include "esp_sntp.h"
static const char *TAG = "example";
@@ -35,7 +33,6 @@ static const char *TAG = "example";
RTC_DATA_ATTR static int boot_count = 0;
static void obtain_time(void);
static void initialize_sntp(void);
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_CUSTOM
void sntp_sync_time(struct timeval *tv)
@@ -121,24 +118,55 @@ void app_main(void)
esp_deep_sleep(1000000LL * deep_sleep_sec);
}
static void print_servers(void)
{
ESP_LOGI(TAG, "List of configured NTP servers:");
for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){
if (esp_sntp_getservername(i)){
ESP_LOGI(TAG, "server %d: %s", i, esp_sntp_getservername(i));
} else {
// we have either IPv4 or IPv6 address, let's print it
char buff[INET6_ADDRSTRLEN];
ip_addr_t const *ip = esp_sntp_getserver(i);
if (ipaddr_ntoa_r(ip, buff, INET6_ADDRSTRLEN) != NULL)
ESP_LOGI(TAG, "server %d: %s", i, buff);
}
}
}
static void obtain_time(void)
{
ESP_ERROR_CHECK( nvs_flash_init() );
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK( esp_event_loop_create_default() );
#if LWIP_DHCP_GET_NTP_SRV
/**
* NTP server address could be aquired via DHCP,
* NTP server address could be acquired via DHCP,
* see following menuconfig options:
* 'LWIP_DHCP_GET_NTP_SRV' - enable STNP over DHCP
* 'LWIP_SNTP_DEBUG' - enable debugging messages
*
* NOTE: This call should be made BEFORE esp aquires IP address from DHCP,
* NOTE: This call should be made BEFORE esp acquires IP address from DHCP,
* otherwise NTP option would be rejected by default.
*/
#ifdef LWIP_DHCP_GET_NTP_SRV
sntp_servermode_dhcp(1); // accept NTP offers from DHCP server, if any
ESP_LOGI(TAG, "Initializing SNTP");
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER);
config.start = false; // start SNTP service explicitly (after connecting)
config.server_from_dhcp = true; // accept NTP offers from DHCP server, if any (need to enable *before* connecting)
config.renew_servers_after_new_IP = true; // let esp-netif update configured SNTP server(s) after receiving DHCP lease
config.index_of_first_server = 1; // updates from server num 1, leaving server 0 (from DHCP) intact
// configure the event on which we renew servers
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
config.ip_event_to_renew = IP_EVENT_STA_GOT_IP;
#else
config.ip_event_to_renew = IP_EVENT_ETH_GOT_IP;
#endif
config.sync_cb = time_sync_notification_cb; // only if we need the notification function
esp_netif_sntp_init(&config);
#endif /* LWIP_DHCP_GET_NTP_SRV */
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
@@ -146,67 +174,53 @@ static void obtain_time(void)
*/
ESP_ERROR_CHECK(example_connect());
initialize_sntp();
#if LWIP_DHCP_GET_NTP_SRV
ESP_LOGI(TAG, "Starting SNTP");
esp_netif_sntp_start();
#if LWIP_IPV6 && SNTP_MAX_SERVERS > 2
/* This demonstrates using IPv6 address as an additional SNTP server
* (statically assigned IPv6 address is also possible)
*/
ip_addr_t ip6;
if (ipaddr_aton("2a01:3f7::1", &ip6)) { // ipv6 ntp source "ntp.netnod.se"
esp_sntp_setserver(2, &ip6);
}
#endif /* LWIP_IPV6 */
#else
ESP_LOGI(TAG, "Initializing and starting SNTP");
#if CONFIG_LWIP_SNTP_MAX_SERVERS > 1
/* This demonstrates configuring more than one server
*/
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2,
ESP_SNTP_SERVER_LIST(CONFIG_SNTP_TIME_SERVER, "pool.ntp.org" ) );
#else
/*
* This is the basic default config with one server and starting the service
*/
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER);
#endif
config.sync_cb = time_sync_notification_cb; // Note: This is only needed if we want
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
config.smooth_sync = true;
#endif
esp_netif_sntp_init(&config);
#endif
print_servers();
// wait for time to be set
time_t now = 0;
struct tm timeinfo = { 0 };
int retry = 0;
const int retry_count = 15;
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == ESP_ERR_TIMEOUT && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
time(&now);
localtime_r(&now, &timeinfo);
ESP_ERROR_CHECK( example_disconnect() );
}
static void initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
/*
* If 'NTP over DHCP' is enabled, we set dynamic pool address
* as a 'secondary' server. It will act as a fallback server in case that address
* provided via NTP over DHCP is not accessible
*/
#if LWIP_DHCP_GET_NTP_SRV && SNTP_MAX_SERVERS > 1
sntp_setservername(1, "pool.ntp.org");
#if LWIP_IPV6 && SNTP_MAX_SERVERS > 2 // statically assigned IPv6 address is also possible
ip_addr_t ip6;
if (ipaddr_aton("2a01:3f7::1", &ip6)) { // ipv6 ntp source "ntp.netnod.se"
sntp_setserver(2, &ip6);
}
#endif /* LWIP_IPV6 */
#else /* LWIP_DHCP_GET_NTP_SRV && (SNTP_MAX_SERVERS > 1) */
// otherwise, use DNS address from a pool
sntp_setservername(0, CONFIG_SNTP_TIME_SERVER);
sntp_setservername(1, "pool.ntp.org"); // set the secondary NTP server (will be used only if SNTP_MAX_SERVERS > 1)
#endif
sntp_set_time_sync_notification_cb(time_sync_notification_cb);
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
#endif
sntp_init();
ESP_LOGI(TAG, "List of configured NTP servers:");
for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){
if (sntp_getservername(i)){
ESP_LOGI(TAG, "server %d: %s", i, sntp_getservername(i));
} else {
// we have either IPv4 or IPv6 address, let's print it
char buff[INET6_ADDRSTRLEN];
ip_addr_t const *ip = sntp_getserver(i);
if (ipaddr_ntoa_r(ip, buff, INET6_ADDRSTRLEN) != NULL)
ESP_LOGI(TAG, "server %d: %s", i, buff);
}
}
esp_netif_sntp_deinit();
}

View File

@@ -22,7 +22,7 @@ def test_get_time_from_sntp_server(dut: Dut) -> None:
dut.write(f'{ap_ssid} {ap_password}')
dut.expect('IPv4 address:')
dut.expect('Initializing SNTP')
dut.expect('Initializing and starting SNTP')
dut.expect(r'Waiting for system time to be set... \(\d+/\d+\)')
dut.expect('Notification of a time synchronization event')

View File

@@ -15,3 +15,4 @@ CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_EXAMPLE_CONNECT_IPV6=n
CONFIG_LWIP_CHECK_THREAD_SAFETY=y

View File

@@ -437,7 +437,6 @@ components/esp_local_ctrl/src/esp_local_ctrl_handler.c
components/esp_local_ctrl/src/esp_local_ctrl_priv.h
components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c
components/esp_netif/include/esp_netif_ppp.h
components/esp_netif/private_include/esp_netif_private.h
components/esp_netif/test/test_esp_netif.c
components/esp_netif/test_apps/component_ut_test.py
components/esp_netif/test_apps/main/esp_netif_test.c
@@ -724,7 +723,6 @@ components/lwip/apps/ping/ping.c
components/lwip/include/apps/dhcpserver/dhcpserver_options.h
components/lwip/include/apps/esp_ping.h
components/lwip/include/apps/ping/ping.h
components/lwip/include/apps/sntp/sntp.h
components/lwip/port/esp32/debug/lwip_debug.c
components/lwip/port/esp32/freertos/sys_arch.c
components/lwip/port/esp32/hooks/tcp_isn_default.c

View File

@@ -1,3 +1,5 @@
TEST_COMPONENTS=mqtt
CONFIG_MQTT_PROTOCOL_5=y
CONFIG_MQTT5_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTTV5_BROKER_TCP}"
CONFIG_LWIP_TCPIP_CORE_LOCKING=y
CONFIG_LWIP_CHECK_THREAD_SAFETY=y