mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
feat(esp_netif): Support posting event on SNTP time update
This commit is contained in:
committed by
David Čermák
parent
6bfcd4b41c
commit
787bb39765
@@ -17,6 +17,29 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SNTP event base for esp-netif
|
||||
*/
|
||||
ESP_EVENT_DECLARE_BASE(NETIF_SNTP_EVENT);
|
||||
|
||||
/**
|
||||
* @brief Event IDs for NETIF_SNTP_EVENT
|
||||
*/
|
||||
typedef enum {
|
||||
NETIF_SNTP_TIME_SYNC = 0, /**< System time synchronized via SNTP */
|
||||
} esp_netif_sntp_event_t;
|
||||
|
||||
/**
|
||||
* @brief Event payload for NETIF_SNTP_TIME_SYNC
|
||||
*
|
||||
* The event data passed to handlers registered for
|
||||
* `NETIF_SNTP_EVENT`/`NETIF_SNTP_TIME_SYNC` is a pointer to this struct.
|
||||
*/
|
||||
typedef struct esp_netif_sntp_time_sync {
|
||||
struct timeval tv; ///< Time of synchronization as reported by SNTP
|
||||
} esp_netif_sntp_time_sync_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Time sync notification function
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
static const char *TAG = "esp_netif_sntp";
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(NETIF_SNTP_EVENT);
|
||||
|
||||
typedef struct sntp_storage {
|
||||
esp_sntp_time_cb_t sync_cb;
|
||||
SemaphoreHandle_t sync_sem;
|
||||
@@ -38,6 +40,14 @@ static void sync_time_cb(struct timeval *tv)
|
||||
if (s_storage && s_storage->sync_cb) {
|
||||
s_storage->sync_cb(tv);
|
||||
}
|
||||
// Post event with the timeval payload
|
||||
esp_netif_sntp_time_sync_t evt = {0};
|
||||
if (tv) {
|
||||
evt.tv = *tv;
|
||||
}
|
||||
if (esp_event_post(NETIF_SNTP_EVENT, NETIF_SNTP_TIME_SYNC, &evt, sizeof(evt), 0) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error posting SNTP time sync");
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t sntp_init_api(void *ctx)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "unity_fixture.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_netif_sntp.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif_net_stack.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "nvs_flash.h"
|
||||
@@ -18,8 +19,9 @@
|
||||
#include "memory_checks.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "esp_netif_test.h"
|
||||
#include "esp_event.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "sntp/sntp_get_set_time.h"
|
||||
|
||||
TEST_GROUP(esp_netif);
|
||||
|
||||
@@ -68,6 +70,44 @@ TEST(esp_netif, init_and_destroy_sntp)
|
||||
esp_netif_sntp_deinit();
|
||||
}
|
||||
|
||||
static SemaphoreHandle_t s_sntp_evt_sem;
|
||||
static void sntp_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
(void)arg; (void)base; (void)id; (void)data;
|
||||
if (s_sntp_evt_sem) {
|
||||
xSemaphoreGive(s_sntp_evt_sem);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(esp_netif, sntp_posts_time_sync_event)
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
TEST_ESP_OK(esp_event_loop_create_default());
|
||||
|
||||
// Register handler for NETIF_SNTP_EVENT
|
||||
s_sntp_evt_sem = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_NULL(s_sntp_evt_sem);
|
||||
TEST_ESP_OK(esp_event_handler_register(NETIF_SNTP_EVENT, NETIF_SNTP_TIME_SYNC, &sntp_event_handler, NULL));
|
||||
|
||||
// Initialize esp-netif SNTP (no auto-start needed for this test)
|
||||
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("127.0.0.1");
|
||||
config.start = false;
|
||||
TEST_ESP_OK(esp_netif_sntp_init(&config));
|
||||
|
||||
// Trigger the SNTP time sync callback path artificially
|
||||
sntp_set_system_time(1, 0);
|
||||
|
||||
// Wait for event to be posted
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xQueueSemaphoreTake(s_sntp_evt_sem, pdMS_TO_TICKS(1000)));
|
||||
|
||||
// Cleanup
|
||||
esp_netif_sntp_deinit();
|
||||
TEST_ESP_OK(esp_event_handler_unregister(NETIF_SNTP_EVENT, NETIF_SNTP_TIME_SYNC, &sntp_event_handler));
|
||||
vSemaphoreDelete(s_sntp_evt_sem);
|
||||
s_sntp_evt_sem = NULL;
|
||||
TEST_ESP_OK(esp_event_loop_delete_default());
|
||||
}
|
||||
|
||||
TEST(esp_netif, convert_ip_addresses)
|
||||
{
|
||||
const char *ipv4_src[] = {"127.168.1.1", "255.255.255.0", "305.500.721.801", "127.168.1..", "abc.def.***.ddd"};
|
||||
@@ -666,6 +706,7 @@ TEST_GROUP_RUNNER(esp_netif)
|
||||
*/
|
||||
RUN_TEST_CASE(esp_netif, init_and_destroy)
|
||||
RUN_TEST_CASE(esp_netif, init_and_destroy_sntp)
|
||||
RUN_TEST_CASE(esp_netif, sntp_posts_time_sync_event)
|
||||
RUN_TEST_CASE(esp_netif, convert_ip_addresses)
|
||||
RUN_TEST_CASE(esp_netif, get_from_if_key)
|
||||
RUN_TEST_CASE(esp_netif, create_delete_multiple_netifs)
|
||||
|
||||
@@ -40,6 +40,31 @@ This section provides more details on specific use cases for the SNTP service, s
|
||||
3. Wait for the system time to synchronize using :cpp:func:`esp_netif_sntp_sync_wait()` (if required).
|
||||
4. Stop and destroy the service using :cpp:func:`esp_netif_sntp_deinit()`.
|
||||
|
||||
Events
|
||||
^^^^^^
|
||||
|
||||
The SNTP wrapper posts an event when the system time is synchronized:
|
||||
|
||||
- Event base: ``NETIF_SNTP_EVENT``
|
||||
- Event ID: ``NETIF_SNTP_TIME_SYNC``
|
||||
- Event data: pointer to :cpp:type:`esp_netif_sntp_time_sync_t` with the synchronized ``timeval``
|
||||
|
||||
Register a handler after creating the default event loop:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void sntp_evt_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
const esp_netif_sntp_time_sync_t *evt = (const esp_netif_sntp_time_sync_t *)data;
|
||||
if (evt) {
|
||||
ESP_LOGI("sntp", "time synchronized: %ld.%06ld", (long)evt->tv.tv_sec, (long)evt->tv.tv_usec);
|
||||
// Optionally convert to human-readable time using localtime_r() or gmtime_r()
|
||||
}
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_SNTP_EVENT, NETIF_SNTP_TIME_SYNC, &sntp_evt_handler, NULL));
|
||||
|
||||
|
||||
Basic Mode with Statically Defined Server(s)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -105,7 +105,7 @@ To initialize a particular SNTP server and also start the SNTP service, simply 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:
|
||||
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. Applications can also subscribe to an event posted when time is synchronized (``NETIF_SNTP_EVENT``, ID ``NETIF_SNTP_TIME_SYNC``). The event data is a pointer to :cpp:type:`esp_netif_sntp_time_sync_t` containing the synchronized ``timeval``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ SNTP 时间同步
|
||||
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()` 可实现此目的:
|
||||
一旦收到 SNTP 服务器的响应,此代码会自动执行时间同步。有时等待时间同步很有意义,调用 :cpp:func:`esp_netif_sntp_sync_wait()` 可实现此目的。应用也可以订阅时间同步事件(事件基座 ``NETIF_SNTP_EVENT``,事件 ID ``NETIF_SNTP_TIME_SYNC``):
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
|
||||
@@ -83,6 +83,15 @@ This example can use 3 time synchronization method:
|
||||
- `sntp_get_sync_status()` and `sntp_set_sync_status()` - get/set time synchronization status.
|
||||
- `sntp_get_sync_mode()` and `sntp_set_sync_mode()` - get/set the sync mode. Allowable two mode: `SNTP_SYNC_MODE_IMMED` and `SNTP_SYNC_MODE_SMOOTH`.
|
||||
|
||||
## Events
|
||||
|
||||
The esp-netif SNTP wrapper emits an event when the system time is synchronized:
|
||||
|
||||
- Event base: `NETIF_SNTP_EVENT`
|
||||
- Event ID: `NETIF_SNTP_TIME_SYNC`
|
||||
|
||||
Register a handler after creating the default event loop (the event data is a pointer to `esp_netif_sntp_time_sync_t` containing the synchronized `timeval`). You can convert the timeval to human-readable local time or UTC if desired using `localtime_r()`/`gmtime_r()`.
|
||||
|
||||
## Mode of update time
|
||||
|
||||
`sntp_set_sync_mode()` - Set the sync mode of the system time. It has two mode:
|
||||
|
||||
@@ -34,6 +34,22 @@ RTC_DATA_ATTR static int boot_count = 0;
|
||||
|
||||
static void obtain_time(void);
|
||||
|
||||
static void sntp_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
(void)arg; (void)base; (void)id;
|
||||
const esp_netif_sntp_time_sync_t *evt = (const esp_netif_sntp_time_sync_t *)data;
|
||||
if (evt) {
|
||||
char ts[64];
|
||||
time_t t = evt->tv.tv_sec;
|
||||
struct tm tm_utc;
|
||||
gmtime_r(&t, &tm_utc);
|
||||
strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", &tm_utc);
|
||||
ESP_LOGI(TAG, "SNTP event: time synced (UTC): %s.%06ld", ts, (long)evt->tv.tv_usec);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "SNTP event: time synced (no timeval provided)");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_CUSTOM
|
||||
void sntp_sync_time(struct timeval *tv)
|
||||
{
|
||||
@@ -140,6 +156,8 @@ 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() );
|
||||
// Register handler to log SNTP event with timeval payload
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_SNTP_EVENT, NETIF_SNTP_TIME_SYNC, &sntp_event_handler, NULL));
|
||||
|
||||
#if LWIP_DHCP_GET_NTP_SRV
|
||||
/**
|
||||
@@ -223,4 +241,5 @@ static void obtain_time(void)
|
||||
|
||||
ESP_ERROR_CHECK( example_disconnect() );
|
||||
esp_netif_sntp_deinit();
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(NETIF_SNTP_EVENT, NETIF_SNTP_TIME_SYNC, &sntp_event_handler));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user