Merge branch 'feature/time_syscalls' into 'master'

implement time syscalls

This change adds optional support for libc time functions.
New menuconfig option allows selecting FRC1,  RTC, both, or none to be used for timekeeping.

- If only FRC1 timer is used, gettimeofday will provide time at
		  microsecond resolution. Time will not be preserved when going
		  into deep sleep mode.
- If both FRC1 and RTC timers are used, timekeeping will
		  continue in deep sleep. Time will be reported at 1 microsecond
		  resolution.
- If only RTC timer is used, timekeeping will continue in
		  deep sleep, but time will be measured at 6.(6) microsecond
		  resolution. Also the gettimeofday function itself may take 
		  longer to run.
- If no timers are used, gettimeofday function will return -1 and
		  set errno to ENOSYS. 

`times` function returns time derived from FreeRTOS ticks. It reports all as 'system' time, 'user' time is reported as zero.

`settimeofday` function may be used to set current time.

LwIP SNTP module is hooked up into the system through `settimeofday`/`gettimeofday`.

Example demonstrating this functionality is also added.

ref. TW6415

See merge request !168
pull/42/merge
Ivan Grokhotkov 2016-11-03 18:02:58 +08:00
commit abecab7525
15 zmienionych plików z 530 dodań i 11 usunięć

Wyświetl plik

@ -319,6 +319,49 @@ config BROWNOUT_DET_RESETDELAY
before trying to restart the chip. You can set the delay here.
choice ESP32_TIME_SYSCALL
prompt "Timers used for gettimeofday function"
default ESP32_TIME_SYSCALL_USE_RTC_FRC1
help
This setting defines which hardware timers are used to
implement 'gettimeofday' and 'time' functions in C library.
- If only FRC1 timer is used, gettimeofday will provide time at
microsecond resolution. Time will not be preserved when going
into deep sleep mode.
- If both FRC1 and RTC timers are used, timekeeping will
continue in deep sleep. Time will be reported at 1 microsecond
resolution.
- If only RTC timer is used, timekeeping will continue in
deep sleep, but time will be measured at 6.(6) microsecond
resolution. Also the gettimeofday function itself may take
longer to run.
- If no timers are used, gettimeofday and time functions
return -1 and set errno to ENOSYS.
config ESP32_TIME_SYSCALL_USE_RTC
bool "RTC"
config ESP32_TIME_SYSCALL_USE_RTC_FRC1
bool "RTC and FRC1"
config ESP32_TIME_SYSCALL_USE_FRC1
bool "FRC1"
config ESP32_TIME_SYSCALL_USE_NONE
bool "None"
endchoice
choice ESP32_RTC_CLOCK_SOURCE
prompt "RTC clock source"
default ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
help
Choose which clock is used as RTC clock source.
The only available option for now is to use internal
150kHz RC oscillator.
config ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
bool "Internal RC"
config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
bool "External 32kHz crystal"
depends on DOCUMENTATION_FOR_RTC_CNTL
endchoice
endmenu

Wyświetl plik

@ -169,7 +169,8 @@ void start_cpu0_default(void)
#if CONFIG_TASK_WDT
esp_task_wdt_init();
#endif
esp_setup_syscalls();
esp_setup_syscall_table();
esp_setup_time_syscalls();
esp_vfs_dev_uart_register();
esp_reent_init(_GLOBAL_REENT);
const char* default_uart_dev = "/dev/uart/0";

Wyświetl plik

@ -0,0 +1,49 @@
// Copyright 2015-2016 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.
#ifndef _SOC_FRC_TIMER_REG_H_
#define _SOC_FRC_TIMER_REG_H_
#include "soc.h"
/**
* These are the register definitions for "legacy" timers
*/
#define REG_FRC_TIMER_BASE(i) (DR_REG_FRC_TIMER_BASE + i*0x20)
#define FRC_TIMER_LOAD_REG(i) (REG_FRC_TIMER_BASE(i) + 0x0) // timer load value (23 bit for i==0, 32 bit for i==1)
#define FRC_TIMER_LOAD_VALUE(i) ((i == 0)?0x007FFFFF:0xffffffff)
#define FRC_TIMER_LOAD_VALUE_S 0
#define FRC_TIMER_COUNT_REG(i) (REG_FRC_TIMER_BASE(i) + 0x4) // timer count value (23 bit for i==0, 32 bit for i==1)
#define FRC_TIMER_COUNT ((i == 0)?0x007FFFFF:0xffffffff)
#define FRC_TIMER_COUNT_S 0
#define FRC_TIMER_CTRL_REG(i) (REG_FRC_TIMER_BASE(i) + 0x8)
#define FRC_TIMER_INT_ENABLE (BIT(8)) // enable interrupt
#define FRC_TIMER_ENABLE (BIT(7)) // enable timer
#define FRC_TIMER_AUTOLOAD (BIT(6)) // enable autoload
#define FRC_TIMER_PRESCALER 0x00000007 // 0: divide by 1, 2: divide by 16, 4: divide by 256
#define FRC_TIMER_PRESCALER_S 1
#define FRC_TIMER_EDGE_INT (BIT(0)) // 0: level, 1: edge
#define FRC_TIMER_INT_REG(i) (REG_FRC_TIMER_BASE(i) + 0xC)
#define FRC_TIMER_INT_CLR (BIT(0)) // clear interrupt
#define FRC_TIMER_ALARM_REG(i) (REG_FRC_TIMER_BASE(i) + 0x10) // timer alarm value; register only present for i == 1
#define FRC_TIMER_ALARM 0xFFFFFFFF
#define FRC_TIMER_ALARM_S 0
#endif //_SOC_FRC_TIMER_REG_H_

Wyświetl plik

@ -239,6 +239,9 @@
#define RTC_CNTL_TIME_VALID_V 0x1
#define RTC_CNTL_TIME_VALID_S 30
/* frequency of RTC slow clock, Hz */
#define RTC_CTNL_SLOWCLK_FREQ 150000
#define RTC_CNTL_TIME0_REG (DR_REG_RTCCNTL_BASE + 0x10)
/* RTC_CNTL_TIME_LO : RO ;bitpos:[31:0] ;default: 32'h0 ; */
/*description: RTC timer low 32 bits*/

Wyświetl plik

@ -148,6 +148,7 @@
#define DR_REG_GPIO_SD_BASE 0x3ff44f00
#define DR_REG_FE2_BASE 0x3ff45000
#define DR_REG_FE_BASE 0x3ff46000
#define DR_REG_FRC_TIMER_BASE 0x3ff47000
#define DR_REG_RTCCNTL_BASE 0x3ff48000
#define DR_REG_RTCIO_BASE 0x3ff48400
#define DR_REG_SARADC_BASE 0x3ff48800
@ -281,9 +282,9 @@
* 19 2 extern level
* 20 2 extern level
* 21 2 extern level
* 22 3 extern edge
* 22 3 extern edge FRC1 timer
* 23 3 extern level
* 24 4 extern level
* 24 4 extern level TG1_WDT
* 25 4 extern level Reserved Reserved
* 26 5 extern level Reserved Reserved
* 27 3 extern level Reserved Reserved
@ -301,8 +302,10 @@
#define ETS_T0_WDT_INUM 3
#define ETS_WBB_INUM 4
#define ETS_TG0_T1_INUM 10 /**< use edge interrupt*/
#define ETS_FRC1_INUM 22
#define ETS_T1_WDT_INUM 24
//CPU0 Intrrupt number used in ROM, should be cancelled in SDK
//CPU0 Interrupt number used in ROM, should be cancelled in SDK
#define ETS_SLC_INUM 1
#define ETS_UART0_INUM 5
#define ETS_UART1_INUM 5

Wyświetl plik

@ -24,6 +24,15 @@ config LWIP_SO_REUSE
Enabling this option allows binding to a port which remains in
TIME_WAIT.
config LWIP_DHCP_MAX_NTP_SERVERS
int "Maximum number of NTP servers"
default 1
range 1 16
help
Set maxumum number of NTP servers used by LwIP SNTP module.
First argument of sntp_setserver/sntp_setservername functions
is limited to this value.
endmenu

Wyświetl plik

@ -33,6 +33,8 @@
#define __LWIPOPTS_H__
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "esp_task.h"
#include "sdkconfig.h"
@ -552,7 +554,22 @@ extern unsigned char misc_prof_get_tcp_snd_buf(void);
#define LWIP_NETCONN_FULLDUPLEX 1
#define LWIP_NETCONN_SEM_PER_THREAD 1
#define LWIP_DHCP_MAX_NTP_SERVERS CONFIG_LWIP_DHCP_MAX_NTP_SERVERS
#define LWIP_TIMEVAL_PRIVATE 0
#define SNTP_SET_SYSTEM_TIME_US(sec, us) \
do { \
struct timeval tv = { .tv_sec = sec, .tv_usec = us }; \
settimeofday(&tv, NULL); \
} while (0);
#define SNTP_GET_SYSTEM_TIME(sec, us) \
do { \
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; \
gettimeofday(&tv, NULL); \
(sec) = tv.tv_sec; \
(us) = tv.tv_usec; \
} while (0);
#define SOC_SEND_LOG //printf

Wyświetl plik

@ -31,7 +31,13 @@ void esp_reent_init(struct _reent* r);
* Called from the startup code, not intended to be called from application
* code.
*/
void esp_setup_syscalls();
void esp_setup_syscall_table();
/**
* Initialize hardware timer used as time source for newlib time functions.
*
* Called from the startup code, not intended to be called from application.
*/
void esp_setup_time_syscalls();
#endif //__ESP_NEWLIB_H__

Wyświetl plik

@ -24,6 +24,7 @@
#include <sys/reent.h>
#include "rom/libc_stubs.h"
#include "esp_vfs.h"
#include "esp_newlib.h"
static struct _reent s_reent;
@ -79,7 +80,7 @@ static struct syscall_stub_table s_stub_table = {
._scanf_float = &_scanf_float,
};
void esp_setup_syscalls()
void esp_setup_syscall_table()
{
syscall_table_ptr_pro = &s_stub_table;
syscall_table_ptr_app = &s_stub_table;

Wyświetl plik

@ -14,22 +14,169 @@
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <reent.h>
#include <sys/types.h>
#include <sys/reent.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/lock.h>
#include "esp_attr.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/frc_timer_reg.h"
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 )
#define WITH_RTC 1
#endif
clock_t _times_r(struct _reent *r, struct tms *ptms)
#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 )
#define WITH_FRC1 1
#endif
#ifdef WITH_RTC
static uint64_t get_rtc_time_us()
{
__errno_r(r) = ENOSYS;
return (clock_t) -1;
SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_M);
while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID_M) == 0) {
;
}
CLEAR_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_M);
uint64_t low = READ_PERI_REG(RTC_CNTL_TIME0_REG);
uint64_t high = READ_PERI_REG(RTC_CNTL_TIME1_REG);
uint64_t ticks = (high << 32) | low;
return ticks * 100 / (RTC_CTNL_SLOWCLK_FREQ / 10000); // scale RTC_CTNL_SLOWCLK_FREQ to avoid overflow
}
#endif // WITH_RTC
// time from Epoch to the first boot time
#ifdef WITH_RTC
static RTC_DATA_ATTR struct timeval s_boot_time;
#else
static struct timeval s_boot_time;
#endif
static _lock_t s_boot_time_lock;
#ifdef WITH_FRC1
#define FRC1_PRESCALER 16
#define FRC1_PRESCALER_CTL 2
#define FRC1_TICK_FREQ (APB_CLK_FREQ / FRC1_PRESCALER)
#define FRC1_TICKS_PER_US (FRC1_TICK_FREQ / 1000000)
#define FRC1_ISR_PERIOD_US (FRC_TIMER_LOAD_VALUE(0) / FRC1_TICKS_PER_US)
// Counter frequency will be APB_CLK_FREQ / 16 = 5 MHz
// 1 tick = 0.2 us
// Timer has 23 bit counter, so interrupt will fire each 1677721.6 microseconds.
// This is not a whole number, so timer will drift by 0.3 ppm due to rounding error.
static volatile uint64_t s_microseconds = 0;
static void IRAM_ATTR frc_timer_isr()
{
WRITE_PERI_REG(FRC_TIMER_INT_REG(0), FRC_TIMER_INT_CLR);
s_microseconds += FRC1_ISR_PERIOD_US;
}
// TODO: read time from RTC
int _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz)
#endif // WITH_FRC1
void esp_setup_time_syscalls()
{
#if defined( WITH_FRC1 )
#if defined( WITH_RTC )
// initialize time from RTC clock
s_microseconds = get_rtc_time_us();
#endif //WITH_RTC
// set up timer
WRITE_PERI_REG(FRC_TIMER_CTRL_REG(0), \
FRC_TIMER_AUTOLOAD | \
(FRC1_PRESCALER_CTL << FRC_TIMER_PRESCALER_S) | \
FRC_TIMER_EDGE_INT);
WRITE_PERI_REG(FRC_TIMER_LOAD_REG(0), FRC_TIMER_LOAD_VALUE(0));
SET_PERI_REG_MASK(FRC_TIMER_CTRL_REG(0),
FRC_TIMER_ENABLE | \
FRC_TIMER_INT_ENABLE);
intr_matrix_set(xPortGetCoreID(), ETS_TIMER1_INTR_SOURCE, ETS_FRC1_INUM);
xt_set_interrupt_handler(ETS_FRC1_INUM, &frc_timer_isr, NULL);
xt_ints_on(1 << ETS_FRC1_INUM);
#endif // WITH_FRC1
}
clock_t IRAM_ATTR _times_r(struct _reent *r, struct tms *ptms)
{
clock_t t = xTaskGetTickCount() * (portTICK_PERIOD_MS * CLK_TCK / 1000);
ptms->tms_cstime = t;
ptms->tms_cutime = 0;
ptms->tms_stime = t;
ptms->tms_utime = 0;
struct timeval tv = {0, 0};
_gettimeofday_r(r, &tv, NULL);
return (clock_t) tv.tv_sec;
}
static uint64_t get_time_since_boot()
{
uint64_t microseconds = 0;
#ifdef WITH_FRC1
uint32_t timer_ticks_before = READ_PERI_REG(FRC_TIMER_COUNT_REG(0));
microseconds = s_microseconds;
uint32_t timer_ticks_after = READ_PERI_REG(FRC_TIMER_COUNT_REG(0));
if (timer_ticks_after > timer_ticks_before) {
// overflow happened at some point between getting
// timer_ticks_before and timer_ticks_after
// microseconds value is ambiguous, get a new one
microseconds = s_microseconds;
}
microseconds += (FRC_TIMER_LOAD_VALUE(0) - timer_ticks_after) / FRC1_TICKS_PER_US;
#elif defined(WITH_RTC)
microseconds = get_rtc_time_us();
#endif
return microseconds;
}
int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz)
{
(void) tz;
#if defined( WITH_FRC1 ) || defined( WITH_RTC )
uint64_t microseconds = get_time_since_boot();
if (tv) {
_lock_acquire(&s_boot_time_lock);
microseconds += s_boot_time.tv_usec;
tv->tv_sec = s_boot_time.tv_sec + microseconds / 1000000;
tv->tv_usec = microseconds % 1000000;
_lock_release(&s_boot_time_lock);
}
return 0;
#else
__errno_r(r) = ENOSYS;
return -1;
#endif // defined( WITH_FRC1 ) || defined( WITH_RTC )
}
int settimeofday(const struct timeval *tv, const struct timezone *tz)
{
(void) tz;
#if defined( WITH_FRC1 ) || defined( WITH_RTC )
if (tv) {
_lock_acquire(&s_boot_time_lock);
uint64_t now = ((uint64_t) tv->tv_sec) * 1000000LL + tv->tv_usec;
uint64_t since_boot = get_time_since_boot();
uint64_t boot_time = now - since_boot;
s_boot_time.tv_sec = boot_time / 1000000;
s_boot_time.tv_usec = boot_time % 1000000;
_lock_release(&s_boot_time_lock);
}
return 0;
#else
__errno_r(r) = ENOSYS;
return -1;
#endif
}

Wyświetl plik

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := sntp
include $(IDF_PATH)/make/project.mk

Wyświetl plik

@ -0,0 +1,41 @@
# Example: using LwIP SNTP module and time functions
This example demonstrates the use of LwIP SNTP module to obtain time from Internet servers. See the README.md file in the upper level 'examples' directory for more information about examples.
## Obtaining time using LwIP SNTP module
When this example boots first time after ESP32 is reset, it connects to WiFi and obtains time using SNTP.
See `initialize_sntp` function for details.
## Timekeeping
Once time is synchronized, ESP32 will perform timekeeping using built-in timers.
- RTC clock is used to maintain accurate time when chip is in deep sleep mode
- FRC1 timer is used to provide time at microsecond accuracy when ESP32 is running.
Timekeeping using RTC timer is demonstrated in this example by going into deep sleep mode. After wake up, ESP32 will print current time without connecting to WiFi.
To use this functionality, make sure "Timers used for gettimeofday function" option in "ESP32-specific config" menu of menuconfig is set to "RTC and FRC1" or "RTC".
## Working with time
To get current time, [`gettimeofday`](http://man7.org/linux/man-pages/man2/gettimeofday.2.html) function may be used. Additionally the following [standard C library functions](http://en.cppreference.com/w/cpp/header/ctime) can be used to obtain time and manipulate it:
gettimeofday
time
asctime
clock
ctime
difftime
gmtime
localtime
mktime
strftime
To set time, [`settimeofday`](http://man7.org/linux/man-pages/man2/settimeofday.2.html) POSIX function can be used. It is used internally in LwIP SNTP library to set current time when response from NTP server is received.
## Timezones
To set local timezone, use [`setenv`](http://man7.org/linux/man-pages/man3/setenv.3.html) and [`tzset`](http://man7.org/linux/man-pages/man3/tzset.3.html) POSIX functions. First, call `setenv` to set `TZ` environment variable to the correct value depending on device location. Format of the time string is described in [libc documentation](https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html). Next, call `tzset` to update C library runtime data for the new time zone. Once these steps are done, `localtime` function will return correct local time, taking time zone offset and daylight saving time into account.

Wyświetl plik

@ -0,0 +1,17 @@
menu "Example Configuration"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "myssid"
help
WiFi password (WPA or WPA2) for the example to use.
Can be left blank if the network has no security set.
endmenu

Wyświetl plik

@ -0,0 +1,10 @@
#
# Main Makefile. This is basically the same as a component makefile.
#
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default,
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
include $(IDF_PATH)/make/component_common.mk

Wyświetl plik

@ -0,0 +1,163 @@
/* LwIP SNTP example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_deepsleep.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "apps/sntp/sntp.h"
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
to the AP with an IP? */
const int CONNECTED_BIT = BIT0;
static const char *TAG = "example";
/* Variable holding number of times ESP32 restarted since first boot.
* It is placed into RTC memory using RTC_DATA_ATTR and
* maintains its value when ESP32 wakes from deep sleep.
*/
RTC_DATA_ATTR static int boot_count = 0;
static void obtain_time(void);
static void initialize_sntp(void);
static void initialise_wifi(void);
static esp_err_t event_handler(void *ctx, system_event_t *event);
void app_main()
{
++boot_count;
ESP_LOGI(TAG, "Boot count: %d", boot_count);
time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
// Is time set? If not, tm_year will be (1970 - 1900).
if (timeinfo.tm_year < (2016 - 1900)) {
ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
obtain_time();
// update 'now' variable with current time
time(&now);
}
char strftime_buf[64];
// Set timezone to Eastern Standard Time and print local time
setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1);
tzset();
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in New York is: %s", strftime_buf);
// Set timezone to China Standard Time
setenv("TZ", "CST-8CDT-9,M4.2.0/2,M9.2.0/3", 1);
tzset();
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf);
const int deep_sleep_sec = 10;
ESP_LOGI(TAG, "Entering deep sleep for %d seconds", deep_sleep_sec);
system_deep_sleep(1000000LL * deep_sleep_sec);
}
static void obtain_time(void)
{
nvs_flash_init();
system_init();
initialise_wifi();
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
false, true, portMAX_DELAY);
initialize_sntp();
// wait for time to be set
time_t now = 0;
struct tm timeinfo = { 0 };
int retry = 0;
const int retry_count = 10;
while(timeinfo.tm_year < (2016 - 1900) && ++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);
}
}
static void initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
sntp_init();
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}