forked from espressif/esp-idf
Merge branch 'feat/netif_sntp_events' into 'master'
[esp_netif]: Support posting event on SNTP time updates Closes IDF-1729 See merge request espressif/esp-idf!42075
This commit is contained in:
@@ -17,6 +17,29 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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
|
* @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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
static const char *TAG = "esp_netif_sntp";
|
static const char *TAG = "esp_netif_sntp";
|
||||||
|
|
||||||
|
ESP_EVENT_DEFINE_BASE(NETIF_SNTP_EVENT);
|
||||||
|
|
||||||
typedef struct sntp_storage {
|
typedef struct sntp_storage {
|
||||||
esp_sntp_time_cb_t sync_cb;
|
esp_sntp_time_cb_t sync_cb;
|
||||||
SemaphoreHandle_t sync_sem;
|
SemaphoreHandle_t sync_sem;
|
||||||
@@ -38,6 +40,14 @@ static void sync_time_cb(struct timeval *tv)
|
|||||||
if (s_storage && s_storage->sync_cb) {
|
if (s_storage && s_storage->sync_cb) {
|
||||||
s_storage->sync_cb(tv);
|
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)
|
static esp_err_t sntp_init_api(void *ctx)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "unity_fixture.h"
|
#include "unity_fixture.h"
|
||||||
#include "esp_netif.h"
|
#include "esp_netif.h"
|
||||||
#include "esp_netif_sntp.h"
|
#include "esp_netif_sntp.h"
|
||||||
|
#include "esp_event.h"
|
||||||
#include "esp_netif_net_stack.h"
|
#include "esp_netif_net_stack.h"
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
@@ -18,8 +19,9 @@
|
|||||||
#include "memory_checks.h"
|
#include "memory_checks.h"
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
#include "esp_netif_test.h"
|
#include "esp_netif_test.h"
|
||||||
#include "esp_event.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
|
#include "sntp/sntp_get_set_time.h"
|
||||||
|
|
||||||
TEST_GROUP(esp_netif);
|
TEST_GROUP(esp_netif);
|
||||||
|
|
||||||
@@ -68,6 +70,44 @@ TEST(esp_netif, init_and_destroy_sntp)
|
|||||||
esp_netif_sntp_deinit();
|
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)
|
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"};
|
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)
|
||||||
RUN_TEST_CASE(esp_netif, init_and_destroy_sntp)
|
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, convert_ip_addresses)
|
||||||
RUN_TEST_CASE(esp_netif, get_from_if_key)
|
RUN_TEST_CASE(esp_netif, get_from_if_key)
|
||||||
RUN_TEST_CASE(esp_netif, create_delete_multiple_netifs)
|
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).
|
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()`.
|
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)
|
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_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
|
||||||
esp_netif_sntp_init(&config);
|
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
|
.. code-block:: c
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ SNTP 时间同步
|
|||||||
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
|
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
|
||||||
esp_netif_sntp_init(&config);
|
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
|
.. 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_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`.
|
- `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
|
## Mode of update time
|
||||||
|
|
||||||
`sntp_set_sync_mode()` - Set the sync mode of the system time. It has two mode:
|
`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 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
|
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_CUSTOM
|
||||||
void sntp_sync_time(struct timeval *tv)
|
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( nvs_flash_init() );
|
||||||
ESP_ERROR_CHECK(esp_netif_init());
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
ESP_ERROR_CHECK( esp_event_loop_create_default() );
|
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
|
#if LWIP_DHCP_GET_NTP_SRV
|
||||||
/**
|
/**
|
||||||
@@ -223,4 +241,5 @@ static void obtain_time(void)
|
|||||||
|
|
||||||
ESP_ERROR_CHECK( example_disconnect() );
|
ESP_ERROR_CHECK( example_disconnect() );
|
||||||
esp_netif_sntp_deinit();
|
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