Remote_Wifi_Switch/main/rtc.c

490 lines
13 KiB
C

/*
* rtc.c
*
* Created on: Jan 16, 2023
* Author: Sword
*/
#include "rtc.h"
#include <time.h>
#include <sys/time.h>
#include "esp_sntp.h"
<<<<<<< HEAD
=======
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lwip/sockets.h"
#include "lwip/err.h"
#include "lwip/netdb.h"
#include "lwip/icmp.h"
#include "esp_system.h"
#include "esp_log.h"
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include "nvm.h"
#include "nvs_flash.h"
>>>>>>> 4ea13f8 (Added azuma wifi switch backup code)
/** Date and time set to: 1st of December 2014, 23 hour 59 min and 31 seconds */
#define SET_HOUR 13 /*< Set hour to the RTC */
#define SET_MINUTE 0 /*< Set minute to the RTC */
#define SET_SECOND 0 /*< Set second to the RTC */
#define SET_WEEKDAY 3 /*< Set weekday to the RTC */
#define SET_YEARDAY 16 /*< day in the year, range 0 to 365 */
#define SET_DAY 26 /*< Set day to the RTC */
#define SET_MONTH 2 /*< Set month to the RTC */
#define SET_YEAR 2025 /*< Set year to the RTC */
#define RTC_SUBSECOND_COUNTER_LOAD_VALUE 32767
static const char* TAG = "RTC";
#define LOG_LOCAL_LEVEL ESP_LOG_INFO
#include "esp_log.h"
#include "esp_sntp.h"
static bool rtc_set = false;
<<<<<<< HEAD
=======
#define PING_HOST "8.8.8.8" // Google DNS
#define CHECK_INTERVAL 1 //60000 // Check every 60 seconds
#define MAX_DISCONNECT_TIME 5 //86400 // 24 hours in seconds
#define SEC 3600
static time_t last_successful_ping = 0;
/// Internet monitor //
time_t get_sntp_time()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec; // Return UNIX timestamp
}
bool ping_test()
{
struct sockaddr_in target_addr;
target_addr.sin_addr.s_addr = inet_addr(PING_HOST);
target_addr.sin_family = AF_INET;
target_addr.sin_port = htons(0);
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sock < 0)
{
ESP_LOGE(TAG, "Socket creation failed");
return false;
}
struct icmp_echo_hdr echo_req;
memset(&echo_req, 0, sizeof(echo_req));
echo_req.id = htons(1);
echo_req.seqno = htons(1);
echo_req.type = ICMP_ECHO;
if (sendto(sock, &echo_req, sizeof(echo_req), 0, (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0)
{
ESP_LOGE(TAG, "Ping send failed");
close(sock);
return false;
}
fd_set read_fds;
struct timeval timeout = {1, 0}; // 1 second timeout
FD_ZERO(&read_fds);
FD_SET(sock, &read_fds);
if (select(sock + 1, &read_fds, NULL, NULL, &timeout) > 0)
{
ESP_LOGI(TAG, "Internet is available");
close(sock);
return true;
}
ESP_LOGW(TAG, "Ping timeout, no internet");
close(sock);
return false;
}
void internet_monitor_task(void *pvParameter)
{
while (1)
{
time_t current_time = get_sntp_time();
if (ping_test())
{
last_successful_ping = current_time;
}
if (last_successful_ping > 0 && (current_time - last_successful_ping) > MAX_DISCONNECT_TIME)
{
ESP_LOGE(TAG, "No internet for %d hours, restarting...", (MAX_DISCONNECT_TIME/SEC));
/* erase the NVS partition */
ESP_ERROR_CHECK(nvs_flash_erase());
esp_restart();
}
vTaskDelay(pdMS_TO_TICKS(CHECK_INTERVAL)); // Wait before next check
}
}
// END ///
>>>>>>> 4ea13f8 (Added azuma wifi switch backup code)
int app_rtc_init(void)
{
int retval = RTC_STATUS_OK;
//RTC_InitType RTC_Init_struct;
//RTC_StructInit(&RTC_Init_struct);
//SysCtrl_PeripheralClockCmd(CLOCK_PERIPH_RTC, ENABLE);
/* Try to enable the down-counter to use as a millisecond counter, but
* does not seem to work without this __NOP delay.
*/
//RTC_Init_struct.RTC_TLR1 = RTC_SUBSECOND_COUNTER_LOAD_VALUE;
//RTC_Init(&RTC_Init_struct);
/** Delay between two write in RTC->TCR register has to be
* at least 3 x 32k cycle + 2 CPU cycle. For that reason it
* is neccessary to add the delay.
*/
// for (volatile uint32_t i = 0; i < 600; i++) {
// __asm("NOP");
// }
//RTC_DateTimeType RTC_DateTime;
struct tm rtc_time;
/* Set the present time and date */
/*RTC_DateTime.Second = SET_SECOND;
RTC_DateTime.Minute = SET_MINUTE;
RTC_DateTime.Hour = SET_HOUR;
RTC_DateTime.WeekDay = SET_WEEKDAY;
RTC_DateTime.MonthDay = SET_DAY;
RTC_DateTime.Month = SET_MONTH;
RTC_DateTime.Year = SET_YEAR;
RTC_SetTimeDate(&RTC_DateTime);*/
rtc_time.tm_sec = SET_SECOND;
rtc_time.tm_min = SET_MINUTE;
rtc_time.tm_hour = SET_HOUR;
rtc_time.tm_wday = SET_WEEKDAY;
rtc_time.tm_mday = SET_DAY;
rtc_time.tm_mon = SET_MONTH;
rtc_time.tm_year = SET_YEAR;
rtc_time.tm_yday = SET_YEARDAY;
time_t t = mktime(&rtc_time);
struct timeval now = { .tv_sec = t };
settimeofday(&now, NULL);
/* Enable RTC */
// RTC_Cmd(ENABLE);
/* Enable RTC clockwatch */
// RTC_ClockwatchCmd(ENABLE);
rtc_set = false;
return retval;
}
void rtc_get_timestamp(rtc_timestamp_t* ts)
{
if (ts) {
//RTC_DateTimeType RTC_DateTime;
//RTC_GetTimeDate(&RTC_DateTime);
/* RTC subsecond counter is a count-down counter */
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm *info = localtime( &tv.tv_sec );
ts->Millisecond = 7+1000*(info->tm_sec); //((RTC_SUBSECOND_COUNTER_LOAD_VALUE - RTC_GetTimerValue()) * 1000 + RTC_SUBSECOND_COUNTER_LOAD_VALUE) /
ts->Second = info->tm_sec;
ts->Minute = info->tm_min;
ts->Hour = info->tm_hour;
ts->WeekDay = info->tm_wday;
ts->MonthDay = info->tm_mday;
ts->Month = info->tm_mon;
ts->Year = info->tm_year;
}
}
void rtc_set_timestamp(rtc_timestamp_t* ts)
{
if (ts) {
rtc_set_timestamp_tz(ts, 0);
}
}
/* Set timestamp including a timezone offset in seconds.
* The timezone offset may be positive or negative. It is applied
* by subtraction, so a -ve offset (e.g. UTC-5) results in the
* timezone offset being added to the local timestamp
*/
void rtc_set_timestamp_tz(rtc_timestamp_t* ts, int32_t tz_offset_sec)
{
if (ts) {
struct tm buf;
buf.tm_year = ts->Year - 1900;
buf.tm_mon = ts->Month - 1;
buf.tm_mday = ts->MonthDay;
buf.tm_hour = ts->Hour;
buf.tm_min = ts->Minute;
buf.tm_sec = ts->Second;
time_t t = mktime(&buf);
/* Apply offset */
t -= tz_offset_sec;
/*
if (!rtc_is_set()) {
rtc_set_epoch((uint32_t)t);
}
*/
rtc_set_epoch((uint32_t)t);
}
}
void rtc_set_epoch(uint32_t epoch)
{
/*
* struct tm
Member Type Meaning Range
tm_sec int seconds after the minute 0 - 60 *
tm_min int minutes after the hour 0 - 59
tm_hour int hours since midnight 0 - 23
tm_mday int day of the month 1 - 31
tm_mon int months since January 0 - 11
tm_year int years since 1900
tm_wday int days since Sunday 0 - 6
tm_yday int days since January 1 0 - 365
tm_isdst int Daylight Saving Time flag
*/
struct tm* buf;
time_t t = epoch;
buf = localtime(&t);
ESP_LOGD(TAG,"rtc_set_epoch: %s\n", asctime(buf));
//RTC_DateTimeType RTC_DateTime;
//
///* Set the present time and date */
//RTC_DateTime.Second = buf->tm_sec;
//RTC_DateTime.Minute = buf->tm_min;
//RTC_DateTime.Hour = buf->tm_hour;
//RTC_DateTime.WeekDay = buf->tm_wday;
//RTC_DateTime.MonthDay = buf->tm_mday;
//RTC_DateTime.Month = buf->tm_mon + 1;
//RTC_DateTime.Year = buf->tm_year + 1900;
//RTC_SetTimeDate(&RTC_DateTime);
time_t tmi = mktime(buf);
struct timeval now = { .tv_sec = tmi };
settimeofday(&now, NULL);
rtc_set = true;
}
uint32_t rtc_get_epoch(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm *info = localtime( &tv.tv_sec );
struct tm buf;
buf.tm_year = info->tm_year - 1900;
buf.tm_mon = info->tm_mon - 1;
buf.tm_mday = info->tm_mday;
buf.tm_hour = info->tm_hour;
buf.tm_min = info->tm_min;
buf.tm_sec = info->tm_sec;
buf.tm_isdst = 0;
time_t t = mktime(&buf);
ESP_LOGD(TAG,"rtc_get_epoch: %s\n", ctime(&t));
return (uint32_t)t;
}
bool rtc_is_set(void)
{
return rtc_set;
}
///////////////////////////////////////////////////////
/*
void time_sync_notification_cb(struct timeval_1 *tv) {
ESP_LOGI(TAG, "Time synchronization event received");
}
*/
<<<<<<< HEAD
void obtain_time(void) {
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org"); // Set NTP server
// sntp_set_time_sync_notification_cb(time_sync_notification_cb);
sntp_init();
=======
void obtain_time(void) {
ESP_LOGI(TAG, "Initializing SNTP");
const char *ntp_servers[] = {
"pool.ntp.org",
"time.google.com",
"1.pool.ntp.org"
};
int server_index = 0;
int num_servers = sizeof(ntp_servers) / sizeof(ntp_servers[0]);
time_t now = 0;
struct tm timeinfo = { 0 };
while (server_index < num_servers) {
ESP_LOGI(TAG, "Using NTP server: %s", ntp_servers[server_index]);
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
esp_sntp_setservername(0, ntp_servers[server_index]);
esp_sntp_init();
int retry = 0;
const int max_retries = 10;
while (timeinfo.tm_year < (2020 - 1900) && retry < max_retries) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry + 1, max_retries);
vTaskDelay(2000 / portTICK_PERIOD_MS);
time(&now);
localtime_r(&now, &timeinfo);
retry++;
}
if (timeinfo.tm_year >= (2020 - 1900)) {
ESP_LOGI(TAG, "Time synchronized: %s", asctime(&timeinfo));
// create internet monitor task
xTaskCreate(&internet_monitor_task, "internet_monitor_task", 4096, NULL, 5, NULL);
return; // Exit the function since time is successfully obtained
}
ESP_LOGE(TAG, "Failed to sync time with %s, switching to next server...", ntp_servers[server_index]);
esp_sntp_stop(); // Stop SNTP before switching
server_index++; // Move to the next server
}
ESP_LOGE(TAG, "All NTP servers failed! Check network settings.");
}
/*void obtain_time(void) {
ESP_LOGI(TAG, "Initializing SNTP");
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
esp_sntp_setservername(0, "pool.ntp.org"); // Set NTP server
// sntp_set_time_sync_notification_cb(time_sync_notification_cb);
esp_sntp_init();
>>>>>>> 4ea13f8 (Added azuma wifi switch backup code)
// Wait for time to be set
time_t now = 0;
struct tm timeinfo = { 0 };
int retry = 0;
const int max_retries = 10;
while (timeinfo.tm_year < (2020 - 1900) && ++retry < max_retries) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, max_retries);
vTaskDelay(2000 / portTICK_PERIOD_MS);
time(&now);
localtime_r(&now, &timeinfo);
}
if (retry >= max_retries) {
ESP_LOGE(TAG, "Failed to obtain time");
} else {
ESP_LOGI(TAG, "Time synchronized");
}
<<<<<<< HEAD
}
char* get_time(void) {
struct tm timeinfo;
long int now;
char time_str[50];
time(&now);
ESP_LOGI(TAG, "Time print start %ld",now);
localtime_r(&now, &timeinfo);
const char *weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"};
// Format as "Weekday YYYY/MM/DD_HH:MM:SS_w" and store in the buffer
snprintf(time_str, sizeof(time_str), "%04d/%02d/%02d_%02d:%02d:%02d_%s",
timeinfo.tm_year + 1900,
timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,weekdays[timeinfo.tm_wday]);
ESP_LOGI(TAG, "Time and Date %s",time_str);
return time_str;
}
///////////////////////////////////////////////////////
=======
}*/
void get_time(char *time_str, size_t size) { // Buffer is provided by the caller
time_t now;
struct tm timeinfo;
time(&now);
// ESP_LOGI(TAG, "Time print start %ld", now);
localtime_r(&now, &timeinfo);
const char *weekdays[] = {"0", "1", "2", "3",
"4", "5", "6"};
// Format time string
snprintf(time_str, size, "%04d/%02d/%02d_%02d:%02d:%02d_%s",
timeinfo.tm_year + 1900,
timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
weekdays[timeinfo.tm_wday]);
ESP_LOGI(TAG, "Formatted Time: %s", time_str);
}
///////////////////////////////////////////////////////
>>>>>>> 4ea13f8 (Added azuma wifi switch backup code)