#define MOVEMENT_DEFAULT_LED_DURATION 1
#endif
+// Default to no set location latitude
+#ifndef MOVEMENT_DEFAULT_LATITUDE
+#define MOVEMENT_DEFAULT_LATITUDE 0
+#endif
+
+// Default to no set location longitude
+#ifndef MOVEMENT_DEFAULT_LONGITUDE
+#define MOVEMENT_DEFAULT_LONGITUDE 0
+#endif
+
+// Default to no set birthdate year
+#ifndef MOVEMENT_DEFAULT_BIRTHDATE_YEAR
+#define MOVEMENT_DEFAULT_BIRTHDATE_YEAR 0
+#endif
+
+// Default to no set birthdate month
+#ifndef MOVEMENT_DEFAULT_BIRTHDATE_MONTH
+#define MOVEMENT_DEFAULT_BIRTHDATE_MONTH 0
+#endif
+
+// Default to no set birthdate day
+#ifndef MOVEMENT_DEFAULT_BIRTHDATE_DAY
+#define MOVEMENT_DEFAULT_BIRTHDATE_DAY 0
+#endif
+
+ // Default to having DST get set
+ #ifndef MOVEMENT_DEFAULT_DST_ACTIVE
+ #define MOVEMENT_DEFAULT_DST_ACTIVE true
+ #endif
+
#if __EMSCRIPTEN__
#include <emscripten.h>
#endif
}
}
- if (date_time.unit.minute > 1 && date_time.unit.minute < 59) return false;
+ static bool _check_and_act_on_daylight_savings(void) {
+ if (!movement_state.settings.bit.dst_active) return false;
+ watch_date_time date_time = watch_rtc_get_date_time();
+ // No need for all of the unix time calculations for times not at the beginning or end of the hour
- watch_rtc_set_date_time(date_time);
++ if (date_time.unit.minute > 1 && date_time.unit.minute < 59) return false;
+ uint8_t dst_result = get_dst_status(date_time);
+ bool dst_skip_rolling_back = get_dst_skip_rolling_back();
+
+ if (dst_skip_rolling_back && (dst_result == DST_ENDED)) {
+ clear_dst_skip_rolling_back();
+ }
+ else if (dst_result == DST_ENDING && !dst_skip_rolling_back) {
+ date_time.unit.hour = (date_time.unit.hour + 24 - 1) % 24;
+ watch_rtc_set_date_time(date_time);
+ set_dst_skip_rolling_back();
+ return true;
+ }
+ else if (dst_result == DST_STARTING) {
+ date_time.unit.hour = (date_time.unit.hour + 1) % 24;
++ watch_rtc_set_date_time(date_time);
+ return true;
+ }
+ return false;
+ }
+
static void _movement_handle_background_tasks(void) {
for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) {
// For each face, if the watch face wants a background task...
movement_state.settings.bit.to_interval = MOVEMENT_DEFAULT_TIMEOUT_INTERVAL;
movement_state.settings.bit.le_interval = MOVEMENT_DEFAULT_LOW_ENERGY_INTERVAL;
movement_state.settings.bit.led_duration = MOVEMENT_DEFAULT_LED_DURATION;
+ movement_state.location.bit.latitude = MOVEMENT_DEFAULT_LATITUDE;
+ movement_state.location.bit.longitude = MOVEMENT_DEFAULT_LONGITUDE;
+ movement_state.birthdate.bit.year = MOVEMENT_DEFAULT_BIRTHDATE_YEAR;
+ movement_state.birthdate.bit.month = MOVEMENT_DEFAULT_BIRTHDATE_MONTH;
+ movement_state.birthdate.bit.day = MOVEMENT_DEFAULT_BIRTHDATE_DAY;
+ movement_state.settings.bit.dst_active = MOVEMENT_DEFAULT_DST_ACTIVE;
+
+ #ifdef MAKEFILE_TIMEZONE
+ timezone_offsets = dst_occurring(watch_rtc_get_date_time()) ? movement_timezone_dst_offsets : movement_timezone_offsets;
+ for (int i = 0; i < NUM_TIME_ZONES; i++) {
+ if (timezone_offsets[i] == MAKEFILE_TIMEZONE) {
+ movement_state.settings.bit.time_zone = i;
+ break;
+ }
+ }
+ #else
+ movement_state.settings.bit.time_zone = 35; // Atlantic Time as default
+ #endif
++
movement_state.light_ticks = -1;
movement_state.alarm_ticks = -1;
movement_state.next_available_backup_register = 4;
*/
#define MOVEMENT_DEFAULT_LED_DURATION 1
+/* The latitude and longitude used for the wearers location
+ * Set signed values in 1/100ths of a degree
+ */
+#define MOVEMENT_DEFAULT_LATITUDE 0
+#define MOVEMENT_DEFAULT_LONGITUDE 0
+
+/* The wearers birthdate
+ * Valid values:
+ * Year: 1 - 4095
+ * Month: 1 - 12
+ * Day: 1 - 31
+ */
+#define MOVEMENT_DEFAULT_BIRTHDATE_YEAR 0
+#define MOVEMENT_DEFAULT_BIRTHDATE_MONTH 0
+#define MOVEMENT_DEFAULT_BIRTHDATE_DAY 0
+
+ /* Set if using DST
+ * Valid values are:
+ * false: Don't allow the watch to use DST
+ * true: Allow the watch to use DST
+ */
+ #define MOVEMENT_DEFAULT_DST_ACTIVE true
+
#endif // MOVEMENT_CONFIG_H_
watch_buzzer_play_note(BUZZER_NOTE_C7, 50);
}
-static void start(countdown_state_t *state, movement_settings_t *settings) {
+static void schedule_countdown(countdown_state_t *state, movement_settings_t *settings) {
+ watch_date_time now = watch_rtc_get_date_time();
+ int16_t tz = get_tz_offset(settings, now);
- // Calculate the new state->now_ts but don't update it until we've updated the target -
- state->mode = cd_running;
- state->now_ts = watch_utility_date_time_to_unix_time(now, tz);
- state->target_ts = watch_utility_offset_timestamp(state->now_ts, state->hours, state->minutes, state->seconds);
++ // Calculate the new state->now_ts but don't update it until we've updated the target -
+ // avoid possible race where the old target is compared to the new time and immediately triggers
- uint32_t new_now = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), get_tz_offset(settings));
++ uint32_t new_now = watch_utility_date_time_to_unix_time(now, tz);
+ state->target_ts = watch_utility_offset_timestamp(new_now, state->hours, state->minutes, state->seconds);
+ state->now_ts = new_now;
- watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
+ watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, tz);
- movement_schedule_background_task(target_dt);
- watch_set_indicator(WATCH_INDICATOR_BELL);
+ movement_schedule_background_task_for_face(state->watch_face_index, target_dt);
+}
+
+static void auto_repeat(countdown_state_t *state, movement_settings_t *settings) {
+ movement_play_alarm();
+ load_countdown(state);
+ schedule_countdown(state, settings);
}
+static void start(countdown_state_t *state, movement_settings_t *settings) {
+ state->mode = cd_running;
+ schedule_countdown(state, settings);
+}
+
+
+
static void draw(countdown_state_t *state, uint8_t subsecond) {
char buf[16];
countdown_state_t *state = (countdown_state_t *)context;
if(state->mode == cd_running) {
watch_date_time now = watch_rtc_get_date_time();
- state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings, now));
- watch_set_indicator(WATCH_INDICATOR_BELL);
+ watch_set_indicator(WATCH_INDICATOR_SIGNAL);
}
watch_set_colon();
+ if(state->repeat)
+ watch_set_indicator(WATCH_INDICATOR_BELL);
movement_request_tick_frequency(1);
quick_ticks_running = false;
// STATIC FUNCTIONS AND CONSTANTS /////////////////////////////////////////////
/** @brief Planetary rulers in the Chaldean order from slowest to fastest
-- * @details Planetary rulers in the Chaldean order from slowest to fastest:
++ * @details Planetary rulers in the Chaldean order from slowest to fastest:
* Jupiter, Mars, Sun, Venus, Mercury, Moon
*/
static const char planets[7][3] = {"Sa", "Ju", "Ma", "So", "Ve", "Me", "Lu"}; // Latin
// calculate sunrise and sunset of current day in decimal hours after midnight
sun_rise_set(scratch_time.unit.year + WATCH_RTC_REFERENCE_YEAR, scratch_time.unit.month, scratch_time.unit.day, lon, lat, &sunrise, &sunset);
--
++
// calculate sunrise and sunset UNIX timestamps
sunrise_epoch = midnight_epoch + sunrise * 3600;
sunset_epoch = midnight_epoch + sunset * 3600;
state->phase_end = sunrise_epoch;
}
-- // calculate the duration of a planetary second during this solar phase
++ // calculate the duration of a planetary second during this solar phase
// and convert to Hertz so we can call a faster tick rate
state->freq = (1 / ((double)( state->phase_end - state->phase_start ) / 43200));
}
double night_hour_count = 0.0;
uint8_t weekday, planet, planetary_hour;
double hour_duration, current_hour, current_minute, current_second;
+ bool set_leading_zero = false;
+ watch_date_time date_time = watch_rtc_get_date_time();
watch_set_colon();
// get current time and convert to UTC
- state->scratch = watch_utility_date_time_convert_zone(watch_rtc_get_date_time(), movement_timezone_offsets[settings->bit.time_zone] * 60, 0);
- state->scratch = watch_utility_date_time_convert_zone(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60, 0);
++ state->scratch = watch_utility_date_time_convert_zone(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60, 0);
// when current phase ends calculate the next phase
if ( watch_utility_date_time_to_unix_time(state->scratch, 0) >= state->phase_end ) {
if ( state->ruler == 0 ) strncpy(ruler, planets[planet], 3);
if ( state->ruler == 1 ) strncpy(ruler, planetes[planet], 3);
if ( state->ruler == 2 ) strncpy(ruler, " ", 3);
--
++
// display planetary time with ruler of the hour or ruler of the day
if ( state->day_ruler ) sprintf(buf, "%s d%2d%02d%02d", ruler, state->scratch.unit.hour, state->scratch.unit.minute, state->scratch.unit.second);
else sprintf(buf, "%s h%2d%02d%02d", ruler, state->scratch.unit.hour, state->scratch.unit.minute, state->scratch.unit.second);
--
++
watch_display_string(buf, 0);
+ if (set_leading_zero)
+ watch_display_string("0", 4);
if ( state->ruler == 2 ) _planetary_icon(planet);
#endif
planetary_time_state_t *state = (planetary_time_state_t *)context;
--
++
// calculate phase
_planetary_solar_phase(settings, state);
}
return movement_default_loop_handler(event, settings);
}
- char buf[11];
+ char buf[13];
+ bool set_leading_zero = false;
++
if (current_page < 3) {
watch_set_colon();
if (settings->bit.clock_mode_24h) {
}
break;
}
- if (current_page != 2) // Do not set time when we are at seconds, it was already set previously
+ if (current_page != 2) { // Do not set time when we are at seconds, it was already set previously
watch_rtc_set_date_time(date_time_settings);
+ }
break;
-
+
case EVENT_ALARM_LONG_UP://Setting seconds on long release
switch (current_page) {
case 2: // second
if (settings->bit.time_zone > 40) settings->bit.time_zone = 0;
break;
}
- if (current_page != 2) // Do not set time when we are at seconds, it was already set previously
++
+ if (date_time_settings.unit.day > days_in_month(date_time_settings.unit.month, date_time_settings.unit.year + WATCH_RTC_REFERENCE_YEAR))
+ date_time_settings.unit.day = 1;
++
+ if (current_page != 2) { // Do not set time when we are at seconds, it was already set previously
watch_rtc_set_date_time(date_time_settings);
+ }
++
//TODO: Do not update whole RTC, just what we are changing
++
break;
case EVENT_TIMEOUT:
movement_move_to_face(0);