addtions for allarm sheduling
This commit is contained in:
parent
ecfb7ef1bc
commit
fa9a43dd52
@ -41,6 +41,7 @@ add_executable(smart_alarm smart_alarm.cpp
|
|||||||
ui.cpp
|
ui.cpp
|
||||||
fonts/Font5x7FixedMono.c
|
fonts/Font5x7FixedMono.c
|
||||||
alarm.cpp
|
alarm.cpp
|
||||||
|
dateutils.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
pico_set_program_name(smart_alarm "smart_alarm")
|
pico_set_program_name(smart_alarm "smart_alarm")
|
||||||
|
|||||||
143
alarm.cpp
143
alarm.cpp
@ -4,6 +4,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "alarm.h"
|
#include "alarm.h"
|
||||||
|
|
||||||
|
#include "hardware/rtc.h"
|
||||||
|
#include "pico/util/datetime.h"
|
||||||
|
|
||||||
|
|
||||||
alarm::alarm(uint8_t hours, uint8_t minutes, const std::array<bool, 7> &days_enabled, bool every_other_week, bool even_week){
|
alarm::alarm(uint8_t hours, uint8_t minutes, const std::array<bool, 7> &days_enabled, bool every_other_week, bool even_week){
|
||||||
@ -122,4 +124,145 @@ void alarm::set_even_week(bool even_week) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "pico/util/datetime.h"
|
||||||
|
|
||||||
|
datetime_t alarm::get_next_ring_time() const {
|
||||||
|
if (!enabled()) {
|
||||||
|
datetime_t invalid = {0};
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
datetime_t now;
|
||||||
|
rtc_get_datetime(&now);
|
||||||
|
|
||||||
|
datetime_t candidate = now;
|
||||||
|
candidate.hour = hours();
|
||||||
|
candidate.min = minutes();
|
||||||
|
candidate.sec = 0;
|
||||||
|
|
||||||
|
auto days = days_enabled();
|
||||||
|
bool any_day_enabled = false;
|
||||||
|
for (uint8_t i = 0; i < 7; i++) {
|
||||||
|
if (days[i]) {
|
||||||
|
any_day_enabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!any_day_enabled) {
|
||||||
|
if (candidate.hour < now.hour ||
|
||||||
|
(candidate.hour == now.hour && candidate.min <= now.min)) {
|
||||||
|
datetime_t invalid = {0};
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimized ISO 8601 week calculation
|
||||||
|
auto get_iso_week_number = [](const datetime_t& dt) -> uint8_t {
|
||||||
|
uint16_t ordinal = dt.day;
|
||||||
|
const uint8_t days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
|
for (uint8_t m = 1; m < dt.month; m++) {
|
||||||
|
ordinal += days_in_month[m];
|
||||||
|
if (m == 2 && (dt.year % 4 == 0 && (dt.year % 100 != 0 || dt.year % 400 == 0))) {
|
||||||
|
ordinal++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t iso_weekday = (dt.dotw == 0) ? 7 : dt.dotw;
|
||||||
|
uint8_t week = (ordinal - iso_weekday + 10) / 7;
|
||||||
|
|
||||||
|
if (week == 0) {
|
||||||
|
// use int16_t insted of uint16_t to avoid warning
|
||||||
|
int16_t prev_year = dt.year - 1;
|
||||||
|
bool leap = (prev_year % 4 == 0 && (prev_year % 100 != 0 || prev_year % 400 == 0));
|
||||||
|
|
||||||
|
datetime_t prev_jan1 = {prev_year, 1, 1, 0, 0, 0, 0};
|
||||||
|
uint8_t jan1_weekday = (prev_jan1.dotw == 0) ? 7 : prev_jan1.dotw;
|
||||||
|
|
||||||
|
if (jan1_weekday == 4 || jan1_weekday == 5 || (leap && jan1_weekday == 3)) {
|
||||||
|
return 53;
|
||||||
|
}
|
||||||
|
return 52;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (week == 53) {
|
||||||
|
bool leap = (dt.year % 4 == 0 && (dt.year % 100 != 0 || dt.year % 400 == 0));
|
||||||
|
uint16_t year_length = leap ? 366 : 365;
|
||||||
|
|
||||||
|
uint16_t remaining_days = year_length - ordinal;
|
||||||
|
uint8_t dec31_weekday = (iso_weekday + remaining_days) % 7;
|
||||||
|
if (dec31_weekday == 0) dec31_weekday = 7;
|
||||||
|
|
||||||
|
if (dec31_weekday <= 3) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return week;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint8_t days_ahead = 0; days_ahead < 14; days_ahead++) {
|
||||||
|
datetime_t test_date = now;
|
||||||
|
|
||||||
|
test_date.day += days_ahead;
|
||||||
|
|
||||||
|
const uint8_t days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
uint8_t max_days = days_in_month[test_date.month];
|
||||||
|
if (test_date.month == 2 && (test_date.year % 4 == 0 &&
|
||||||
|
(test_date.year % 100 != 0 || test_date.year % 400 == 0))) {
|
||||||
|
max_days = 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (test_date.day > max_days) {
|
||||||
|
test_date.day -= max_days;
|
||||||
|
test_date.month++;
|
||||||
|
if (test_date.month > 12) {
|
||||||
|
test_date.month = 1;
|
||||||
|
test_date.year++;
|
||||||
|
}
|
||||||
|
max_days = days_in_month[test_date.month];
|
||||||
|
if (test_date.month == 2 && (test_date.year % 4 == 0 &&
|
||||||
|
(test_date.year % 100 != 0 || test_date.year % 400 == 0))) {
|
||||||
|
max_days = 29;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dotw = (now.dotw + days_ahead) % 7;
|
||||||
|
test_date.dotw = dotw;
|
||||||
|
|
||||||
|
if (!days[dotw]) continue;
|
||||||
|
|
||||||
|
test_date.hour = hours();
|
||||||
|
test_date.min = minutes();
|
||||||
|
test_date.sec = 0;
|
||||||
|
|
||||||
|
if (days_ahead == 0) {
|
||||||
|
if (test_date.hour < now.hour ||
|
||||||
|
(test_date.hour == now.hour && test_date.min <= now.min)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (every_other_week()) {
|
||||||
|
uint8_t current_week = get_iso_week_number(now);
|
||||||
|
uint8_t test_week = get_iso_week_number(test_date);
|
||||||
|
|
||||||
|
bool is_even_week = (test_week % 2 == 0);
|
||||||
|
|
||||||
|
if (even_week() != is_even_week) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return test_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
datetime_t invalid = {0};
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<alarm> alarms;
|
std::vector<alarm> alarms;
|
||||||
3
alarm.h
3
alarm.h
@ -4,6 +4,8 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "pico/types.h"
|
||||||
|
|
||||||
struct alarm
|
struct alarm
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -19,6 +21,7 @@ public:
|
|||||||
[[nodiscard]] bool every_other_week() const;
|
[[nodiscard]] bool every_other_week() const;
|
||||||
[[nodiscard]] bool even_week() const;
|
[[nodiscard]] bool even_week() const;
|
||||||
[[nodiscard]] bool enabled() const;
|
[[nodiscard]] bool enabled() const;
|
||||||
|
[[nodiscard]] datetime_t get_next_ring_time() const;
|
||||||
|
|
||||||
// Enable/disable methods
|
// Enable/disable methods
|
||||||
void enable();
|
void enable();
|
||||||
|
|||||||
33
dateutils.cpp
Normal file
33
dateutils.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "dateutils.h"
|
||||||
|
|
||||||
|
#include "pico/types.h"
|
||||||
|
|
||||||
|
|
||||||
|
datetime_compare_res compare_datetime(const datetime_t *dt1, const datetime_t *dt2) {
|
||||||
|
// Compare year first
|
||||||
|
if (dt1->year > dt2->year) return BIGGER_THAN;
|
||||||
|
if (dt1->year < dt2->year) return SMALLER_THAN;
|
||||||
|
|
||||||
|
// Years are equal, compare month
|
||||||
|
if (dt1->month > dt2->month) return BIGGER_THAN;
|
||||||
|
if (dt1->month < dt2->month) return SMALLER_THAN;
|
||||||
|
|
||||||
|
// Months are equal, compare day
|
||||||
|
if (dt1->day > dt2->day) return BIGGER_THAN;
|
||||||
|
if (dt1->day < dt2->day) return SMALLER_THAN;
|
||||||
|
|
||||||
|
// Days are equal, compare hour
|
||||||
|
if (dt1->hour > dt2->hour) return BIGGER_THAN;
|
||||||
|
if (dt1->hour < dt2->hour) return SMALLER_THAN;
|
||||||
|
|
||||||
|
// Hours are equal, compare minute
|
||||||
|
if (dt1->min > dt2->min) return BIGGER_THAN;
|
||||||
|
if (dt1->min < dt2->min) return SMALLER_THAN;
|
||||||
|
|
||||||
|
// Minutes are equal, compare second
|
||||||
|
if (dt1->sec > dt2->sec) return BIGGER_THAN;
|
||||||
|
if (dt1->sec < dt2->sec) return SMALLER_THAN;
|
||||||
|
|
||||||
|
// All fields are equal
|
||||||
|
return EQUALS;
|
||||||
|
}
|
||||||
11
dateutils.h
Normal file
11
dateutils.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef SMART_ALARM_DATEUTILS_H
|
||||||
|
#define SMART_ALARM_DATEUTILS_H
|
||||||
|
#include "pico/types.h"
|
||||||
|
|
||||||
|
enum datetime_compare_res {
|
||||||
|
EQUALS,
|
||||||
|
BIGGER_THAN,
|
||||||
|
SMALLER_THAN,
|
||||||
|
};
|
||||||
|
datetime_compare_res compare_datetime(const datetime_t *dt1, const datetime_t *dt2);
|
||||||
|
#endif //SMART_ALARM_DATEUTILS_H
|
||||||
Loading…
x
Reference in New Issue
Block a user