diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 038da496..6d260f56 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -81,6 +81,7 @@ SetDateTimeView::SetDateTimeView( &field_second, &text_weekday, &text_day_of_year, + &text_in_dst_range, &checkbox_dst_enable, &options_dst_start_which, &options_dst_start_weekday, @@ -100,18 +101,25 @@ SetDateTimeView::SetDateTimeView( options_dst_start_month.set_options(month_options); options_dst_end_month.set_options(month_options); + const auto dst_changed_fn = [this](size_t, uint32_t) { + handle_date_field_update(); + }; + const auto date_changed_fn = [this](int32_t) { - auto weekday = rtc_time::day_of_week(field_year.value(), field_month.value(), field_day.value()); - auto doy = rtc_time::day_of_year(field_year.value(), field_month.value(), field_day.value()); - bool valid_date = (field_day.value() <= rtc_time::days_per_month(field_year.value(), field_month.value())); - text_weekday.set(valid_date ? weekday_options[weekday].first : "-"); - text_day_of_year.set(valid_date ? to_string_dec_uint(doy, 3) : "-"); + handle_date_field_update(); }; field_year.on_change = date_changed_fn; field_month.on_change = date_changed_fn; field_day.on_change = date_changed_fn; + options_dst_start_which.on_change = dst_changed_fn; + options_dst_start_weekday.on_change = dst_changed_fn; + options_dst_start_month.on_change = dst_changed_fn; + options_dst_end_which.on_change = dst_changed_fn; + options_dst_end_weekday.on_change = dst_changed_fn; + options_dst_end_month.on_change = dst_changed_fn; + rtc::RTC datetime; rtc_time::now(datetime); SetDateTimeModel model{ @@ -146,6 +154,17 @@ void SetDateTimeView::form_init(const SetDateTimeModel& model) { } SetDateTimeModel SetDateTimeView::form_collect() { + return { + .year = static_cast(field_year.value()), + .month = static_cast(field_month.value()), + .day = static_cast(field_day.value()), + .hour = static_cast(field_hour.value()), + .minute = static_cast(field_minute.value()), + .second = static_cast(field_second.value()), + .dst = dst_collect()}; +} + +pmem::dst_config_t SetDateTimeView::dst_collect() { pmem::dst_config_t dst; dst.b.dst_enabled = static_cast(checkbox_dst_enable.value()); dst.b.start_which = static_cast(options_dst_start_which.selected_index_value()); @@ -154,14 +173,16 @@ SetDateTimeModel SetDateTimeView::form_collect() { dst.b.end_which = static_cast(options_dst_end_which.selected_index_value()); dst.b.end_weekday = static_cast(options_dst_end_weekday.selected_index_value()); dst.b.end_month = static_cast(options_dst_end_month.selected_index_value()); - return { - .year = static_cast(field_year.value()), - .month = static_cast(field_month.value()), - .day = static_cast(field_day.value()), - .hour = static_cast(field_hour.value()), - .minute = static_cast(field_minute.value()), - .second = static_cast(field_second.value()), - .dst = dst}; + return dst; +} + +void SetDateTimeView::handle_date_field_update() { + auto weekday = rtc_time::day_of_week(field_year.value(), field_month.value(), field_day.value()); + auto doy = rtc_time::day_of_year(field_year.value(), field_month.value(), field_day.value()); + bool valid_date = (field_day.value() <= rtc_time::days_per_month(field_year.value(), field_month.value())); + text_weekday.set(valid_date ? weekday_options[weekday].first : "-"); + text_day_of_year.set(valid_date ? to_string_dec_uint(doy, 3) : "-"); + text_in_dst_range.set(checkbox_dst_enable.value() && rtc_time::dst_test_date_range(field_year.value(), doy, dst_collect()) ? "DST" : ""); } /* SetRadioView ******************************************/ diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 68396769..2f5cb2e9 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -126,6 +126,9 @@ class SetDateTimeView : public View { Text text_day_of_year{ {26 * 8, 6 * 16, 3 * 8, 16}, ""}; + Text text_in_dst_range{ + {17 * 8, 7 * 16, 3 * 8, 16}, + ""}; Checkbox checkbox_dst_enable{ {2 * 8, 9 * 16}, @@ -171,6 +174,8 @@ class SetDateTimeView : public View { void form_init(const SetDateTimeModel& model); SetDateTimeModel form_collect(); + portapack::persistent_memory::dst_config_t dst_collect(); + void handle_date_field_update(); }; struct SetFrequencyCorrectionModel { diff --git a/firmware/application/rtc_time.cpp b/firmware/application/rtc_time.cpp index 99890118..68e8824d 100644 --- a/firmware/application/rtc_time.cpp +++ b/firmware/application/rtc_time.cpp @@ -21,9 +21,10 @@ */ #include "rtc_time.hpp" -#include "portapack_persistent_memory.hpp" +using namespace lpc43xx; using namespace portapack; + namespace pmem = portapack::persistent_memory; namespace rtc_time { @@ -77,8 +78,10 @@ rtc::RTC dst_adjust_returned_time(rtc::RTC& datetime) { if (doy != dst_current_doy) { if (datetime.year() != dst_current_year) dst_update_date_range(datetime.year(), doy); - else - dst_check_date_range(doy); + else { + dst_current_doy = doy; + dst_in_range = dst_check_date_range(doy, dst_start_doy, dst_end_doy); + } } // Not in DST date range @@ -105,15 +108,13 @@ rtc::RTC dst_adjust_returned_time(rtc::RTC& datetime) { } // Check if current date is within the DST range (called when date changes) -void dst_check_date_range(uint16_t doy) { - dst_current_doy = doy; - +bool dst_check_date_range(uint16_t doy, uint16_t start_doy, uint16_t end_doy) { // Check if date is within DST range // (note that dates are reversed in Southern hemisphere because Summer starts in December) - if (dst_start_doy <= dst_end_doy) - dst_in_range = ((doy >= dst_start_doy) && (doy < dst_end_doy)); + if (start_doy <= end_doy) + return ((doy >= start_doy) && (doy < end_doy)); else - dst_in_range = ((doy >= dst_start_doy) || (doy < dst_end_doy)); + return ((doy >= start_doy) || (doy < end_doy)); } // Update DST parameters (called at power-up, when year changes, or DST settings are changed) @@ -125,12 +126,20 @@ void dst_update_date_range(uint16_t year, uint16_t doy) { dst_start_doy = day_of_year_of_nth_weekday(dst_current_year, dst.b.start_month, dst.b.start_which, dst.b.start_weekday); dst_end_doy = day_of_year_of_nth_weekday(dst_current_year, dst.b.end_month, dst.b.end_which, dst.b.end_weekday); - dst_check_date_range(doy); + dst_current_doy = doy; + dst_in_range = dst_check_date_range(doy, dst_start_doy, dst_end_doy); } else { dst_in_range = false; } } +// Test date range for display purposes only when setting Time +bool dst_test_date_range(uint16_t year, uint16_t doy, pmem::dst_config_t dst) { + uint16_t start_doy = day_of_year_of_nth_weekday(year, dst.b.start_month, dst.b.start_which, dst.b.start_weekday); + uint16_t end_doy = day_of_year_of_nth_weekday(year, dst.b.end_month, dst.b.end_which, dst.b.end_weekday); + return dst_check_date_range(doy, start_doy, end_doy); +} + // Set RTC clock. // If the user has enabled DST, the time entered and passed to this function is interpreted as having been adjusted for DST. // When DST functionality is enabled in pmem, the value stored in the RTC hardware is non-DST time, and we only fudge the time when read. diff --git a/firmware/application/rtc_time.hpp b/firmware/application/rtc_time.hpp index 52839a1a..a0bfd422 100644 --- a/firmware/application/rtc_time.hpp +++ b/firmware/application/rtc_time.hpp @@ -25,7 +25,7 @@ #include "signal.hpp" #include "lpc43xx_cpp.hpp" -using namespace lpc43xx; +#include "portapack_persistent_memory.hpp" namespace rtc_time { @@ -45,8 +45,9 @@ rtc::RTC now(rtc::RTC& out_datetime); /* Daylight Savings Time functions */ void dst_init(); rtc::RTC dst_adjust_returned_time(rtc::RTC& datetime); -void dst_check_date_range(uint16_t doy); +bool dst_check_date_range(uint16_t doy, uint16_t start_doy, uint16_t end_doy); void dst_update_date_range(uint16_t year, uint16_t doy); +bool dst_test_date_range(uint16_t year, uint16_t doy, portapack::persistent_memory::dst_config_t dst); uint8_t days_per_month(uint16_t year, uint8_t month); uint8_t current_day_of_week(); uint8_t day_of_week(uint16_t year, uint8_t month, uint8_t day);