#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#if defined(WOLFSSL_ESPIDF)
#include "sdkconfig.h"
#if defined(USE_WOLFSSL_ESP_SDK_TIME)
#include <esp_log.h>
#include <esp_err.h>
#include <wolfssl/wolfcrypt/port/Espressif/esp-sdk-lib.h>
#define ESP_SDK_TIME_LIB_VERSION 1
static const char* TAG = "time lib";
esp_err_t esp_sdk_time_lib_init(void)
{
int ret = ESP_OK;
ESP_LOGI(TAG, "esp_sdk_time_lib_init Ver %d", ESP_SDK_TIME_LIB_VERSION);
return ret;
}
#if defined(CONFIG_IDF_TARGET_ESP8266)
#include <time.h>
#elif 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>
#elif (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
#endif
#ifndef TIME_ZONE
#define TIME_ZONE "PST+8PDT,M3.2.0,M11.1.0"
#endif
#define NTP_RETRY_COUNT 10
#define NELEMS(x) ( (int)(sizeof(x) / sizeof((x)[0])) )
#define NTP_SERVER_LIST ( (char*[]) { \
"pool.ntp.org", \
"time.nist.gov", \
"utcnist.colorado.edu" \
} \
)
#define NTP_SERVER_COUNT NELEMS(NTP_SERVER_LIST)
#ifndef CONFIG_LWIP_SNTP_MAX_SERVERS
#define CONFIG_LWIP_SNTP_MAX_SERVERS NTP_SERVER_COUNT
#endif
#ifndef __DATE__
#define YEAR 2024
#define MONTH 9
#define DAY 25
#else
#define YEAR ( \
((__DATE__)[7] - '0') * 1000 + \
((__DATE__)[8] - '0') * 100 + \
((__DATE__)[9] - '0') * 10 + \
((__DATE__)[10] - '0') * 1 \
)
#define MONTH ( \
__DATE__[2] == 'n' ? (__DATE__[1] == 'a' ? 1 : 6) \
: __DATE__[2] == 'b' ? 2 \
: __DATE__[2] == 'r' ? (__DATE__[0] == 'M' ? 3 : 4) \
: __DATE__[2] == 'y' ? 5 \
: __DATE__[2] == 'l' ? 7 \
: __DATE__[2] == 'g' ? 8 \
: __DATE__[2] == 'p' ? 9 \
: __DATE__[2] == 't' ? 10 \
: __DATE__[2] == 'v' ? 11 \
: 12 \
)
#define DAY ( \
((__DATE__)[4] - '0') * 10 + \
((__DATE__)[5] - '0') * 1 \
)
#endif
extern char* ntpServerList[NTP_SERVER_COUNT];
char* ntpServerList[NTP_SERVER_COUNT] = NTP_SERVER_LIST;
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;
}
int set_fixed_default_time(void)
{
ESP_LOGV(TAG, "Default Date %s", __DATE__);
ESP_LOGV(TAG, "YEAR %d", YEAR);
ESP_LOGV(TAG, "MONTH %d", MONTH);
ESP_LOGV(TAG, "DAY %d", DAY);
struct tm timeinfo = {
.tm_year = YEAR - 1900,
.tm_mon = MONTH - 1,
.tm_mday = DAY,
.tm_hour = 13,
.tm_min = 1,
.tm_sec = 5
};
struct timeval now;
time_t interim_time;
int ret = -1;
interim_time = mktime(&timeinfo);
ESP_LOGI(TAG, "Adjusting time from fixed value");
now = (struct timeval){ .tv_sec = interim_time };
#if defined(CONFIG_IDF_TARGET_ESP8266)
(void)now;
#else
ret = settimeofday(&now, NULL);
#endif
ESP_LOGI(TAG, "settimeofday result = %d", ret);
return ret;
}
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;
}
#if defined(CONFIG_IDF_TARGET_ESP8266)
int set_time_from_string(const char* time_buffer)
{
ESP_LOGE(TAG, "set_time_from_string not implemented for ESP8266");
return ESP_FAIL;
}
int set_time(void)
{
ESP_LOGE(TAG, "set_time not implemented for ESP8266");
return ESP_FAIL;
}
int set_time_wait_for_ntp(void)
{
ESP_LOGE(TAG, "set_time_wait_for_ntp not implemented for ESP8266");
return ESP_FAIL;
}
#else
int set_time_from_string(const char* time_buffer)
{
char offset[28];
char day_str[28];
char month_str[28];
const char *format = "%3s %3s %d %d:%d:%d %d %27s";
struct tm this_timeinfo;
struct timeval now;
time_t interim_time;
int day, year, hour, minute, second;
int quote_offset = 0;
int ret = 0;
ret = probably_valid_time_string(time_buffer);
if (ret == ESP_OK) {
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) {
const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
int i;
for (i = 0; i < 12; i++) {
if (strcmp(month_str, months[i]) == 0) {
this_timeinfo.tm_mon = i;
break;
}
}
if (i == 12) {
return ESP_FAIL;
}
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;
this_timeinfo.tm_isdst = -1;
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;
}
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
#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
#endif
int ret = 0;
int i = 0;
ESP_LOGI(TAG, "Setting the time. Startup time:");
esp_show_current_datetime();
#ifdef LIBWOLFSSL_VERSION_GIT_HASH_DATE
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
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) {
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;
if (i >= NTP_SERVER_COUNT) {
break;
}
thisServer = ntpServerList[i];
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;
}
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_LOGE(TAG, "HAS_ESP_NETIF_SNTP not defined");
#endif
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
#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;
}
#endif
#endif
#endif