Thank you for your hint @thethinker!
Is SNTP_GET_SYSTEM_TIME under the surface the same as calling gettimeofday()?
Code: Select all
#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);
I came up with the following solution (at last in the post) which starts the event with an accuracy of 1000usec. But I'm polling on the usec value for a short while, to get a timer started as soon the time reaches a nearby "whole" second:
Code: Select all
while (temp.tv_usec/10 < 99999)
{
gettimeofday(&temp, NULL);
}
Is there a nicer non blocking solution for this? As i continued reading about timers I found that the systems time keeping is done by the frc1 timer - is it possible to read out at which "count" of the timer the seconds get raised?
If someone coincidentally reads my code through and notices any other newbie programming mistakes or just anything what should be done otherwise, any information is appreciated.
Code: Select all
#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 "nvs_flash.h"
#include "lwip/err.h"
#include "apps/sntp/sntp.h"
#include <sys/types.h> //contains struct timeval;
#include "apps/sntp/sntp_opts.h"
#define EXAMPLE_WIFI_SSID "mySSID" //CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS "myPW"//CONFIG_WIFI_PASSWORD
static EventGroupHandle_t wifi_event_group;
const int CONNECTED_BIT = BIT0;
static const char *TAG = "#Debug:";
time_t now;
struct tm timeinfo;
TaskHandle_t timer_start_task_handle;
TimerHandle_t tmr1; //Timer to Start the Event (Not Reloading)
TimerHandle_t tmr2; //Timer to Do Something every second, after the event started
int id1 = 1;
int id2 = 2;
int interval1 = 5000;
int interval2 = 1000;
char strftime_buf[64];
static void obtain_time(void);
static void initialize_sntp(void);
static void initialize_wifi(void);
static esp_err_t event_handler(void *ctx, system_event_t *event);
static void timer_start_task(void *pvParameter);
static void timerOneCallBack( TimerHandle_t xTimer );
static void timerTwoCallBack( TimerHandle_t xTimer );
void app_main()
{
time(&now);
localtime_r(&now, &timeinfo);
tmr1 = xTimerCreate("StartTimer", pdMS_TO_TICKS(interval1), pdFALSE, ( void * )id1, &timerOneCallBack);
tmr2 = xTimerCreate("SecTimer", pdMS_TO_TICKS(interval2), pdTRUE, ( void * )id2, &timerTwoCallBack);
// 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);
}
// Set Timezone to GMT+1
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
tzset();
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in Budapest is: %s", strftime_buf);
xTaskCreate(&timer_start_task, "time_printf_task", 2048, NULL, 5, &timer_start_task_handle);
}
static void timerOneCallBack( TimerHandle_t xTimer )
{
xTimerStart(tmr2, 0);
struct timeval tmp_time = {0};
SNTP_GET_SYSTEM_TIME(tmp_time.tv_sec, tmp_time.tv_usec); //Is it the same as using gettimeofaday(&tmp_time);
ESP_LOGI(TAG,"###Ring Ring! Timer1 Callback activated.###");
ESP_LOGI(TAG, "sec holds: %d", (int)tmp_time.tv_sec);
ESP_LOGI(TAG, "usec holds: %d", (int)tmp_time.tv_usec);
time(&now);
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in Budapest / Vienna / Brüssel is: %s", strftime_buf);
}
static void timerTwoCallBack( TimerHandle_t xTimer )
{
ESP_LOGI(TAG,"###Ring Ring! Timer2 Callback activated.###");
}
static void obtain_time(void)
{
ESP_ERROR_CHECK( nvs_flash_init() );
initialize_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(1000 / portTICK_PERIOD_MS);
time(&now);
localtime_r(&now, &timeinfo);
}
ESP_ERROR_CHECK( esp_wifi_stop() ); //Remove if MQTT message is implemented
}
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 initialize_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(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
void timer_start_task(void *pvParameter)
{
while(1)
{
// The Start time of the logging event - Later it will be received via MQTT
struct tm start_time = {
.tm_year = 118,
.tm_mon = 2, //0 for January?
.tm_mday = 17,
.tm_hour = 10,
.tm_min = 29,
.tm_sec = 0,
.tm_isdst = 1,
};
mktime(&start_time);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &start_time);
ESP_LOGI(TAG, "The saved start_time is: %s", strftime_buf);
time(&now);
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time is: %s", strftime_buf);
vTaskDelay(250 / portTICK_PERIOD_MS);
time_t raw_start_time;
time_t raw_now; // additional variable is not really needed
raw_start_time = mktime(&start_time);
time(&raw_now);
int difi;
signed int tmp_difi = difftime(raw_now, raw_start_time);
if (tmp_difi > 0) {
ESP_LOGI(TAG, "Start Time was in the past");
break;
}
else
{
difi = abs(tmp_difi);
}
ESP_LOGI(TAG, "Difftime in Secs until event start is: %d", difi);
struct timeval temp;
SNTP_GET_SYSTEM_TIME(temp.tv_sec, temp.tv_usec);
if ((int)temp.tv_usec/10 > 99999)
{
xTimerChangePeriod(tmr1, difi*100, 0);
if( xTimerStart(tmr1, 0 ) != pdPASS )
{
ESP_LOGI(TAG, "Timer start error");
}
else {
ESP_LOGI(TAG, "Timer started");
}
}
else {
while (temp.tv_usec/10 < 99999)
{
gettimeofday(&temp, NULL);
}
xTimerChangePeriod(tmr1, (difi-1)*100, 0);
if( xTimerStart(tmr1, 0 ) != pdPASS )
{
ESP_LOGI(TAG, "Timer start error");
}
else {
ESP_LOGI(TAG, "Timer started");
}
}
break;
}
vTaskDelete(0);
}
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;
}
Terminal Output:
Code: Select all
I (3552) #Debug:: The current date/time in Budapest is: Sat Mar 17 09:28:54 2018
I (3552) #Debug:: The saved start_time is: Sat Mar 17 09:29:00 2018
I (3562) #Debug:: The current date/time is: Sat Mar 17 09:28:54 2018
I (3822) #Debug:: Difftime in Secs until event start is: 6
I (4052) #Debug:: Timer started
I (9052) #Debug:: ###Ring Ring! Timer1 Callback activated.###
I (9052) #Debug:: sec holds: 1521275339
I (9052) #Debug:: usec holds: 997817
I (9052) #Debug:: The current date/time in Budapest / Vienna / Brüssel is: Sat Mar 17 09:29:00 2018
I (10052) #Debug:: ###Ring Ring! Timer2 Callback activated.###
I (11052) #Debug:: ###Ring Ring! Timer2 Callback activated.###
Thank you!