123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- /* time_helper.c
- *
- * Copyright (C) 2006-2024 wolfSSL Inc.
- *
- * This file is part of wolfSSL.
- *
- * wolfSSL is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * wolfSSL is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
- */
- /* common Espressif time_helper */
- #include "time_helper.h"
- #include "sdkconfig.h"
- /* wolfSSL */
- /* Always include wolfcrypt/settings.h before any other wolfSSL file. */
- /* Reminder: settings.h pulls in user_settings.h; don't include it here. */
- #ifdef WOLFSSL_USER_SETTINGS
- #include <wolfssl/wolfcrypt/settings.h>
- #ifndef WOLFSSL_ESPIDF
- #warning "Problem with wolfSSL user_settings."
- #warning "Check components/wolfssl/include"
- #endif
- /* This project not yet using the library */
- #undef USE_WOLFSSL_ESP_SDK_WIFI
- #include <wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h>
- #else
- /* Define WOLFSSL_USER_SETTINGS project wide for settings.h to include */
- /* wolfSSL user settings in ./components/wolfssl/include/user_settings.h */
- #error "Missing WOLFSSL_USER_SETTINGS in CMakeLists or Makefile:\
- CFLAGS +=-DWOLFSSL_USER_SETTINGS"
- #endif
- #include <esp_log.h>
- #include <esp_idf_version.h>
- #if defined(ESP_IDF_VERSION_MAJOR) && defined(ESP_IDF_VERSION_MINOR)
- #if (ESP_IDF_VERSION_MAJOR == 5) && (ESP_IDF_VERSION_MINOR >= 1)
- #define HAS_ESP_NETIF_SNTP 1
- #include <lwip/apps/sntp.h>
- #include <esp_netif_sntp.h>
- #else
- #include <string.h>
- #include <esp_sntp.h>
- #endif
- #else
- /* TODO Consider non ESP-IDF environments */
- #endif
- /* ESP-IDF uses a 64-bit signed integer to represent time_t starting from
- * release v5.0. See: Espressif api-reference/system/system_time
- */
- /* see https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html */
- #ifndef TIME_ZONE
- /*
- * PST represents Pacific Standard Time.
- * +8 specifies the offset from UTC (Coordinated Universal Time), indicating
- * that Pacific Time is UTC-8 during standard time.
- * PDT represents Pacific Daylight Time.
- * M3.2.0 indicates that Daylight Saving Time (DST) starts on the
- * second (2) Sunday (0) of March (3).
- * M11.1.0 indicates that DST ends on the first (1) Sunday (0) of November (11)
- */
- #define TIME_ZONE "PST+8PDT,M3.2.0,M11.1.0"
- #endif /* not defined: TIME_ZONE, so we are setting our own */
- #define NTP_RETRY_COUNT 10
- /* NELEMS(x) number of elements
- * To determine the number of elements in the array, we can divide the total
- * size of the array by the size of the array element.
- * See https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c
- **/
- #define NELEMS(x) ( (int)(sizeof(x) / sizeof((x)[0])) )
- /* See also CONFIG_LWIP_SNTP_MAX_SERVERS in sdkconfig */
- #define NTP_SERVER_LIST ( (char*[]) { \
- "pool.ntp.org", \
- "time.nist.gov", \
- "utcnist.colorado.edu" \
- } \
- )
- /* #define NTP_SERVER_COUNT using NELEMS:
- *
- * (int)(sizeof(NTP_SERVER_LIST) / sizeof(NTP_SERVER_LIST[0]))
- */
- #define NTP_SERVER_COUNT NELEMS(NTP_SERVER_LIST)
- #ifndef CONFIG_LWIP_SNTP_MAX_SERVERS
- /* We should find max value in sdkconfig, if not set it to our count:*/
- #define CONFIG_LWIP_SNTP_MAX_SERVERS NTP_SERVER_COUNT
- #endif
- char* ntpServerList[NTP_SERVER_COUNT] = NTP_SERVER_LIST;
- const static char* TAG = "time_helper";
- /* our NTP server list is global info */
- extern char* ntpServerList[NTP_SERVER_COUNT];
- /* Show the current date and time */
- int esp_show_current_datetime(void)
- {
- time_t now;
- char strftime_buf[64];
- struct tm timeinfo;
- time(&now);
- setenv("TZ", TIME_ZONE, 1);
- tzset();
- localtime_r(&now, &timeinfo);
- strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
- ESP_LOGI(TAG, "The current date/time is: %s", strftime_buf);
- return ESP_OK;
- }
- /* the worst-case scenario is a hard-coded date/time */
- int set_fixed_default_time(void)
- {
- /* ideally, we'd like to set time from network,
- * but let's set a default time, just in case */
- struct tm timeinfo = {
- .tm_year = 2024 - 1900,
- .tm_mon = 3,
- .tm_mday = 01,
- .tm_hour = 13,
- .tm_min = 01,
- .tm_sec = 05
- };
- struct timeval now;
- time_t interim_time;
- int ret = -1;
- /* set interim static time */
- interim_time = mktime(&timeinfo);
- ESP_LOGI(TAG, "Adjusting time from fixed value");
- now = (struct timeval){ .tv_sec = interim_time };
- ret = settimeofday(&now, NULL);
- ESP_LOGI(TAG, "settimeofday result = %d", ret);
- return ret;
- }
- /* probably_valid_time_string(s)
- *
- * some sanity checks on time string before calling sscanf()
- *
- * returns 0 == ESP_OK == Success if str is likely a valid time.
- * -1 == ESP_FAIL otherwise
- */
- int probably_valid_time_string(const char* str)
- {
- int ret = ESP_OK;
- size_t length = 0;
- size_t spaces = 0;
- size_t colons = 0;
- while (str[length] != '\0') {
- if (str[length] == ' ') {
- spaces++;
- }
- if (str[length] == ':') {
- colons++;
- }
- length++;
- }
- if ((length > 32) || (spaces < 4) || (spaces > 5) || (colons > 2)) {
- ret = ESP_FAIL;
- ESP_LOGE(TAG, "ERROR, failed time sanity check: %s", str);
- }
- return ret;
- }
- /* set_time_from_string(s)
- *
- * returns 0 = success if able to set the time from the provided string
- * error for any other value, typically -1 */
- int set_time_from_string(const char* time_buffer)
- {
- /* expecting github default formatting: 'Thu Aug 31 12:41:45 2023 -0700' */
- char offset[28]; /* large arrays, just in case there's still bad data */
- char day_str[28];
- char month_str[28];
- const char *format = "%3s %3s %d %d:%d:%d %d %s";
- struct tm this_timeinfo;
- struct timeval now;
- time_t interim_time;
- int day, year, hour, minute, second;
- int quote_offset = 0;
- int ret = 0;
- /* perform some basic sanity checks */
- ret = probably_valid_time_string(time_buffer);
- if (ret == ESP_OK) {
- /* we are expecting the string to be encapsulated in single quotes */
- if (*time_buffer == 0x27) {
- quote_offset = 1;
- }
- ret = sscanf(time_buffer + quote_offset,
- format,
- day_str, month_str,
- &day, &hour, &minute, &second, &year, &offset);
- if (ret == 8) {
- /* we found a match for all components */
- const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
- for (int i = 0; i < 12; i++) {
- if (strcmp(month_str, months[i]) == 0) {
- this_timeinfo.tm_mon = i;
- break;
- }
- }
- this_timeinfo.tm_mday = day;
- this_timeinfo.tm_hour = hour;
- this_timeinfo.tm_min = minute;
- this_timeinfo.tm_sec = second;
- this_timeinfo.tm_year = year - 1900; /* Years since 1900 */
- interim_time = mktime(&this_timeinfo);
- now = (struct timeval){ .tv_sec = interim_time };
- ret = settimeofday(&now, NULL);
- ESP_LOGI(TAG, "Time updated to %s", time_buffer);
- }
- else {
- ESP_LOGE(TAG, "Failed to convert \"%s\" to a tm date.",
- time_buffer);
- ESP_LOGI(TAG, "Trying fixed date that was hard-coded....");
- set_fixed_default_time();
- ret = ESP_FAIL;
- }
- }
- return ret;
- }
- /* set time; returns 0 if succecssfully configured with NTP */
- int set_time(void)
- {
- #ifndef NTP_SERVER_COUNT
- ESP_LOGW(TAG, "Warning: no sntp server names defined. "
- "Setting to empty list");
- #define NTP_SERVER_COUNT 0
- #warning "NTP not properly configured"
- #endif /* not defined: NTP_SERVER_COUNT */
- #ifdef HAS_ESP_NETIF_SNTP
- #if CONFIG_LWIP_SNTP_MAX_SERVERS > 1
- esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(
- NTP_SERVER_COUNT,
- ESP_SNTP_SERVER_LIST(ntpServerList[0])
- );
- #else
- esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(ntpServerList[0]);
- #endif /* CONFIG_LWIP_SNTP_MAX_SERVERS > 1 */
- #endif /* HAS_ESP_NETIF_SNTP */
- int ret = 0;
- int i = 0; /* counter for time servers */
- ESP_LOGI(TAG, "Setting the time. Startup time:");
- esp_show_current_datetime();
- #ifdef LIBWOLFSSL_VERSION_GIT_HASH_DATE
- /* initially set a default approximate time from recent git commit */
- ESP_LOGI(TAG, "Found git hash date, attempting to set system date: %s",
- LIBWOLFSSL_VERSION_GIT_HASH_DATE);
- set_time_from_string(LIBWOLFSSL_VERSION_GIT_HASH_DATE"\0");
- esp_show_current_datetime();
- ret = -4;
- #else
- /* otherwise set a fixed time that was hard coded */
- set_fixed_default_time();
- esp_show_current_datetime();
- ret = -3;
- #endif
- #ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
- config.smooth_sync = true;
- #endif
- if (NTP_SERVER_COUNT) {
- /* next, let's setup NTP time servers
- *
- * see Espressif api-reference/system/system_time
- *
- * WARNING: do not set operating mode while SNTP client is running!
- */
- /* TODO Consider esp_sntp_setoperatingmode(SNTP_OPMODE_POLL); */
- sntp_setoperatingmode(SNTP_OPMODE_POLL);
- if (NTP_SERVER_COUNT > CONFIG_LWIP_SNTP_MAX_SERVERS) {
- ESP_LOGW(TAG, "WARNING: %d NTP Servers defined, but "
- "CONFIG_LWIP_SNTP_MAX_SERVERS = %d",
- NTP_SERVER_COUNT,CONFIG_LWIP_SNTP_MAX_SERVERS);
- }
- ESP_LOGI(TAG, "sntp_setservername:");
- for (i = 0; i < CONFIG_LWIP_SNTP_MAX_SERVERS; i++) {
- const char* thisServer = ntpServerList[i];
- if (strncmp(thisServer, "\x00", 1) == 0) {
- /* just in case we run out of NTP servers */
- break;
- }
- ESP_LOGI(TAG, "%s", thisServer);
- sntp_setservername(i, thisServer);
- ret = ESP_OK;
- }
- #ifdef HAS_ESP_NETIF_SNTP
- ret = esp_netif_sntp_init(&config);
- #else
- ESP_LOGW(TAG,"Warning: Consider upgrading ESP-IDF to take advantage "
- "of updated SNTP libraries");
- #endif
- if (ret == ESP_OK) {
- ESP_LOGV(TAG, "Successfully called esp_netif_sntp_init");
- }
- else {
- ESP_LOGE(TAG, "ERROR: esp_netif_sntp_init return = %d", ret);
- }
- sntp_init();
- switch (ret) {
- case ESP_ERR_INVALID_STATE:
- break;
- default:
- break;
- }
- ESP_LOGI(TAG, "sntp_init done.");
- }
- else {
- ESP_LOGW(TAG, "No sntp time servers found.");
- ret = -1;
- }
- esp_show_current_datetime();
- ESP_LOGI(TAG, "time helper existing with result = %d", ret);
- return ret;
- }
- /* wait for NTP to actually set the time */
- int set_time_wait_for_ntp(void)
- {
- int ret = 0;
- #ifdef HAS_ESP_NETIF_SNTP
- int ntp_retry = 0;
- const int ntp_retry_count = NTP_RETRY_COUNT;
- ret = esp_netif_sntp_start();
- ret = esp_netif_sntp_sync_wait(500 / portTICK_PERIOD_MS);
- #else
- ESP_LOGW(TAG, "HAS_ESP_NETIF_SNTP not defined");
- #endif /* HAS_ESP_NETIF_SNTP */
- esp_show_current_datetime();
- #ifdef HAS_ESP_NETIF_SNTP
- while (ret == ESP_ERR_TIMEOUT && (ntp_retry++ < ntp_retry_count)) {
- ret = esp_netif_sntp_sync_wait(1000 / portTICK_PERIOD_MS);
- ESP_LOGI(TAG, "Waiting for NTP to sync time... (%d/%d)",
- ntp_retry,
- ntp_retry_count);
- esp_show_current_datetime();
- }
- #endif /* HAS_ESP_NETIF_SNTP */
- #ifdef TIME_ZONE
- setenv("TZ", TIME_ZONE, 1);
- tzset();
- #endif
- if (ret == ESP_OK) {
- ESP_LOGI(TAG, "Successfully set time via NTP servers.");
- }
- else {
- ESP_LOGW(TAG, "Warning: Failed to set time with NTP: "
- "result = 0x%0x: %s",
- ret, esp_err_to_name(ret));
- }
- return ret;
- }
|