diff --git a/lib/ccronexpr/ccronexpr.c b/lib/ccronexpr/ccronexpr.c index bf1358a19..826d95536 100644 --- a/lib/ccronexpr/ccronexpr.c +++ b/lib/ccronexpr/ccronexpr.c @@ -31,6 +31,30 @@ #include "ccronexpr.h" +#define CRON_MAX_SECONDS 60 +#define CRON_MAX_MINUTES 60 +#define CRON_MAX_HOURS 24 +#define CRON_MAX_DAYS_OF_WEEK 8 +#define CRON_MAX_DAYS_OF_MONTH 32 +#define CRON_MAX_MONTHS 12 +#define CRON_MAX_YEARS_DIFF 4 + +#define CRON_CF_SECOND 0 +#define CRON_CF_MINUTE 1 +#define CRON_CF_HOUR_OF_DAY 2 +#define CRON_CF_DAY_OF_WEEK 3 +#define CRON_CF_DAY_OF_MONTH 4 +#define CRON_CF_MONTH 5 +#define CRON_CF_YEAR 6 + +#define CRON_CF_ARR_LEN 7 + + +static const char* const DAYS_ARR[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; +#define CRON_DAYS_ARR_LEN 7 +static const char* const MONTHS_ARR[] = { "FOO", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; +#define CRON_MONTHS_ARR_LEN 13 + #define CRON_MAX_STR_LEN_TO_SPLIT 256 #define CRON_MAX_NUM_TO_SRING 1000000000 /* computes number of digits in decimal number */ @@ -60,7 +84,7 @@ void cron_free(void* p); /* forward declarations for platforms that may need them */ /* can be hidden in time.h */ -#if !defined(_WIN32) && !defined(__AVR__) && !(defined(ESP8266) || defined(ESP32)) && !defined(ANDROID) +#if !defined(_WIN32) && !defined(__AVR__) && !defined(ESP8266) && !defined(ESP_PLATFORM) && !defined(ANDROID) struct tm *gmtime_r(const time_t *timep, struct tm *result); time_t timegm(struct tm* __tp); struct tm *localtime_r(const time_t *timep, struct tm *result); @@ -78,15 +102,16 @@ time_t cron_mktime_gm(struct tm* tm) { #elif defined(__AVR__) /* https://www.nongnu.org/avr-libc/user-manual/group__avr__time.html */ return mk_gmtime(tm); -#elif (defined(ESP8266) || defined(ESP32)) +#elif defined(ESP8266) || defined(ESP_PLATFORM) /* https://linux.die.net/man/3/timegm */ /* http://www.catb.org/esr/time-programming/ */ /* portable version of timegm() */ - time_t ret; - char *tz; - tz = getenv("TZ"); - if (tz) - tz = strdup(tz); + time_t ret = -1; + char *tz_orig = NULL; + char *tz = NULL; + tz_orig = getenv("TZ"); + if (tz_orig) + tz = strdup(tz_orig); setenv("TZ", "UTC+0", 1); tzset(); ret = mktime(tm); @@ -257,6 +282,7 @@ static int add_to_field(struct tm* calendar, int field, int val) { calendar->tm_hour = calendar->tm_hour + val; break; case CRON_CF_DAY_OF_WEEK: /* mkgmtime ignores this field */ + break; case CRON_CF_DAY_OF_MONTH: calendar->tm_mday = calendar->tm_mday + val; break; @@ -496,12 +522,12 @@ static int do_next(cron_expr* expr, struct tm* calendar, unsigned int dot) { if (!resets || !empty_list) { res = -1; } - if (resets) { - cron_free(resets); - } if (empty_list) { cron_free(empty_list); } + if (resets) { + cron_free(resets); + } return res; } @@ -624,6 +650,7 @@ static char** split_str(const char* str, char del, size_t* len_out) { int c = str[i]; if (del == str[i]) { if (bi > 0) { + if (ri >= len) goto return_error; tmp = strdupl(buf, bi); if (!tmp) goto return_error; res[ri++] = tmp; @@ -636,6 +663,7 @@ static char** split_str(const char* str, char del, size_t* len_out) { } /* tail */ if (bi > 0) { + if (ri >= len) goto return_error; tmp = strdupl(buf, bi); if (!tmp) goto return_error; res[ri++] = tmp; @@ -645,10 +673,10 @@ static char** split_str(const char* str, char del, size_t* len_out) { return res; return_error: + free_splitted(res, len); if (buf) { cron_free(buf); } - free_splitted(res, len); *len_out = 0; return NULL; } diff --git a/lib/ccronexpr/ccronexpr.h b/lib/ccronexpr/ccronexpr.h index a6ad02b80..06395572b 100644 --- a/lib/ccronexpr/ccronexpr.h +++ b/lib/ccronexpr/ccronexpr.h @@ -36,6 +36,12 @@ extern "C" { #include /*added for use if uint*_t data types*/ + +#define CRON_INVALID_INSTANT ((time_t) -1) + +// Define to use local time +#define CRON_USE_LOCAL_TIME + /** * Parsed cron expression */ @@ -90,30 +96,6 @@ time_t cron_prev(cron_expr* expr, time_t date); } /* extern "C"*/ #endif -#define CRON_MAX_SECONDS 60 -#define CRON_MAX_MINUTES 60 -#define CRON_MAX_HOURS 24 -#define CRON_MAX_DAYS_OF_WEEK 8 -#define CRON_MAX_DAYS_OF_MONTH 32 -#define CRON_MAX_MONTHS 12 -#define CRON_MAX_YEARS_DIFF 4 - -#define CRON_CF_SECOND 0 -#define CRON_CF_MINUTE 1 -#define CRON_CF_HOUR_OF_DAY 2 -#define CRON_CF_DAY_OF_WEEK 3 -#define CRON_CF_DAY_OF_MONTH 4 -#define CRON_CF_MONTH 5 -#define CRON_CF_YEAR 6 - -#define CRON_CF_ARR_LEN 7 - -#define CRON_INVALID_INSTANT ((time_t) -1) - -static const char* const DAYS_ARR[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; -#define CRON_DAYS_ARR_LEN 7 -static const char* const MONTHS_ARR[] = { "FOO", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; -#define CRON_MONTHS_ARR_LEN 13 #endif /* CCRONEXPR_H */ diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index a02b8c82b..15e2924bb 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -29,7 +29,7 @@ extends = common board_build.f_cpu = 80000000L build_flags = ${debug_flags.build_flags} ${mqtt_flags.build_flags} -DHTTPCLIENT_1_1_COMPATIBLE=0 build_unflags = -DDEBUG_ESP_PORT -lib_deps = https://github.com/TD-er/ESPEasySerial.git +lib_deps = https://github.com/TD-er/ESPEasySerial.git#v1.0.14 lib_ignore = ESP32_ping, ESP32WebServer, IRremoteESP8266, HeatpumpIR, SD(esp8266), SDFS board = esp12e diff --git a/pre_custom_esp82xx.py b/pre_custom_esp82xx.py index 18faeb995..4e2038ada 100644 --- a/pre_custom_esp82xx.py +++ b/pre_custom_esp82xx.py @@ -32,6 +32,7 @@ else: "USES_P052", # SenseAir "USES_P056", # SDS011-Dust "USES_P059", # Encoder + "USES_P081", # Cron "USES_P082", # GPS "USES_P085", # AcuDC24x "USES_P087", # Serial Proxy diff --git a/src/_P081_Cron.ino b/src/_P081_Cron.ino index 7a2a87429..50924b383 100644 --- a/src/_P081_Cron.ino +++ b/src/_P081_Cron.ino @@ -1,9 +1,7 @@ // ####################################################################################################### - // #################################### Plugin 081: CRON tasks Scheduler ########################### // ####################################################################################################### -// FIXME TD-er: There is some kind of memory leak in this cron plugin. #ifdef USES_P081 @@ -12,7 +10,7 @@ extern "C" { -#include "ccronexpr.h" + #include "ccronexpr.h" } @@ -30,7 +28,7 @@ extern "C" struct P081_data_struct : public PluginTaskData_base { - P081_data_struct(const String& expression) + explicit P081_data_struct(const String& expression) { const char *error; @@ -97,21 +95,23 @@ time_t P081_computeNextCronTime(taskIndex_t taskIndex, time_t last) static_cast(getPluginTaskData(taskIndex)); if ((nullptr != P081_data) && P081_data->isInitialized()) { - int32_t freeHeapStart = ESP.getFreeHeap(); + // int32_t freeHeapStart = ESP.getFreeHeap(); time_t res = P081_data->get_cron_next(last); - int32_t freeHeapEnd = ESP.getFreeHeap(); + /* + int32_t freeHeapEnd = ESP.getFreeHeap(); - if (freeHeapEnd < freeHeapStart) { - String log = F("Cron: Free Heap Decreased: "); - log += String(freeHeapStart - freeHeapEnd); - log += F(" ("); - log += freeHeapStart; - log += F(" -> "); - log += freeHeapEnd; - addLog(LOG_LEVEL_INFO, log); - } + if (freeHeapEnd < freeHeapStart) { + String log = F("Cron: Free Heap Decreased: "); + log += String(freeHeapStart - freeHeapEnd); + log += F(" ("); + log += freeHeapStart; + log += F(" -> "); + log += freeHeapEnd; + addLog(LOG_LEVEL_INFO, log); + } + */ return res; } return CRON_INVALID_INSTANT; @@ -144,6 +144,28 @@ time_t P081_getCurrentTime() return mktime((struct tm *)¤t); } +void P081_check_or_init(struct EventStruct *event) +{ + if (systemTimePresent()) { + const time_t current_time = P081_getCurrentTime(); + time_t last_exec_time = P081_getCronExecTime(LASTEXECUTION); + time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION); + + // Must check if the values of LASTEXECUTION and NEXTEXECUTION make sense. + // These can be invalid values from a reboot, or simply contain uninitialized values. + if ((last_exec_time > current_time) || (last_exec_time == CRON_INVALID_INSTANT) || (next_exec_time == CRON_INVALID_INSTANT)) { + // Last execution time cannot be correct. + last_exec_time = CRON_INVALID_INSTANT; + const time_t tmp_next = P081_computeNextCronTime(event->TaskIndex, current_time); + + if ((tmp_next < next_exec_time) || (next_exec_time == CRON_INVALID_INSTANT)) { + next_exec_time = tmp_next; + } + P081_setCronExecTimes(event, CRON_INVALID_INSTANT, next_exec_time); + } + } +} + boolean Plugin_081(byte function, struct EventStruct *event, String& string) { boolean success = false; @@ -251,6 +273,7 @@ boolean Plugin_081(byte function, struct EventStruct *event, String& string) } if (P081_data->isInitialized()) { + P081_check_or_init(event); success = true; } else { clearPluginTaskData(event->TaskIndex); @@ -277,31 +300,18 @@ boolean Plugin_081(byte function, struct EventStruct *event, String& string) { // code to be executed once a second. Tasks which do not require fast response can be added here if (systemTimePresent()) { - const time_t current_time = P081_getCurrentTime(); - time_t last_exec_time = P081_getCronExecTime(LASTEXECUTION); - time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION); - - // Must check if the values of LASTEXECUTION and NEXTEXECUTION make sense. - // These can be invalid values from a reboot, or simply contain uninitialized values. - if ((last_exec_time > current_time) || (last_exec_time == CRON_INVALID_INSTANT) || (next_exec_time == CRON_INVALID_INSTANT)) { - // Last execution time cannot be correct. - last_exec_time = CRON_INVALID_INSTANT; - const time_t tmp_next = P081_computeNextCronTime(event->TaskIndex, current_time); - - if ((tmp_next < next_exec_time) || (next_exec_time == CRON_INVALID_INSTANT)) { - next_exec_time = tmp_next; - } - P081_setCronExecTimes(event, CRON_INVALID_INSTANT, next_exec_time); - } + P081_check_or_init(event); + time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION); if (next_exec_time != CRON_INVALID_INSTANT) { - const bool cron_elapsed = (next_exec_time <= current_time); + const time_t current_time = P081_getCurrentTime(); + const bool cron_elapsed = (next_exec_time <= current_time); if (cron_elapsed) { addLog(LOG_LEVEL_DEBUG, F("Cron Elapsed")); - last_exec_time = next_exec_time; - next_exec_time = P081_computeNextCronTime(event->TaskIndex, last_exec_time); + time_t last_exec_time = next_exec_time; + next_exec_time = P081_computeNextCronTime(event->TaskIndex, current_time); P081_setCronExecTimes(event, last_exec_time, next_exec_time); addLog(LOG_LEVEL_DEBUG, String(F("Next execution:")) + getDateTimeString(*gmtime(&next_exec_time)));