#include "filesystem.h"
#include "movement.h"
#include "shell.h"
-#include "watch_utility.h"
#ifndef MOVEMENT_FIRMWARE
#include "movement_config.h"
#define MOVEMENT_DEFAULT_LED_DURATION 1
#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
const int16_t movement_timeout_inactivity_deadlines[4] = {60, 120, 300, 1800};
movement_event_t event;
-#define NUM_TIME_ZONES 41
-const int16_t movement_timezone_offsets[NUM_TIME_ZONES] = {
+const int16_t movement_timezone_offsets[] = {
0, // 0 : 0:00:00 (UTC)
60, // 1 : 1:00:00 (Central European Time)
120, // 2 : 2:00:00 (South African Standard Time)
* having to separately change the hour and timezone info
* in the time set face.
*/
-const int16_t movement_timezone_dst_offsets[NUM_TIME_ZONES] = {
- 60, // 0 UTC + 1 = CET
- 120, // 1 CET + 1 = SAST
- 189, // 2 SAST + 1 = AST
- 240, // 3 AST + 1 = GST
- 270, // 4 IST + 1 = AT
- 300, // 5 GST + 1 = PST
- 330, // 6 AT + 1 = IST
- 360, // 7 PST + 1 = KT
- 390, // 8 IST + 1 = MT
- 345, // 9 Nepal has no equivalent DST timezone, but they don't observe DST anyway
- 420, // 10 KT + 1 = TST
- 390, // 11 Myanmar has no equivalent DST timezone, but they don't observe DST anyway
- 480, // 12 TST + 1 = CST
- 540, // 13 CST + 1 = JST
- 525, // 14 ACWST has no equivalent DST timezone, but they don't observe DST anyway
- 600, // 15 JST + 1 = AEST
- 630, // 16 ACST + 1 = LHST
- 660, // 17 AEST + 1 = SIT
- 630, // 18 LHST has no equivalent DST timezone, but they don't observe DST anyway
- 720, // 19 SIT + 1 = NZST
- 780, // 20 NZST + 1 = TT
- 825, // 21 CST + 1 = CDT
- 840, // 22 TT + 1 = LIT
- 825, // 23 CDT is already a daylight timezone
- 840, // 24 LIT has no equivalent DST timezone, but they don't observe DST anyway
- -660, // 25 BIT + 1 = NT
- -600, // 26 NT + 1 = HAST
- -540, // 27 HAST + 1 = AST
- -570, // 28 MIT has no equivalent DST timezone, but they don't observe DST anyway
- -480, // 29 AST + 1 = PST
- -420, // 30 PST + 1 = MST
- -360, // 31 MST + 1 = CST
- -300, // 32 CST + 1 = EST
- -240, // 33 EST + 1 = AST
- -210, // 34 VST + 1 = NST
- -180, // 35 AST + 1 = BT
- -150, // 36 NST + 1 = NDT
- -120, // 37 BT + 1 = 39
- -150, // 38 NDT is already a daylight timezone
- -60, // 39 FNT + 1 = AST
+const uint8_t movement_dst_jump_table[] = {
+ 1, // 0 UTC + 1 = CET
+ 2, // 1 CET + 1 = SAST
+ 3, // 2 SAST + 1 = AST
+ 5, // 3 AST + 1 = GST
+ 6, // 4 IST + 1 = AT
+ 7, // 5 GST + 1 = PST
+ 8, // 6 AT + 1 = IST
+ 10, // 7 PST + 1 = KT
+ 11, // 8 IST + 1 = MT
+ 9, // 9 Nepal has no equivalent DST timezone, but they don't observe DST anyway
+ 12, // 10 KT + 1 = TST
+ 11, // 11 Myanmar has no equivalent DST timezone, but they don't observe DST anyway
+ 13, // 12 TST + 1 = CST
+ 15, // 13 CST + 1 = JST
+ 14, // 14 ACWST has no equivalent DST timezone, but they don't observe DST anyway
+ 17, // 15 JST + 1 = AEST
+ 18, // 16 ACST + 1 = LHST
+ 19, // 17 AEST + 1 = SIT
+ 18, // 18 LHST has no equivalent DST timezone, but they don't observe DST anyway
+ 20, // 19 SIT + 1 = NZST
+ 22, // 20 NZST + 1 = TT
+ 23, // 21 CST + 1 = CDT
+ 24, // 22 TT + 1 = LIT
+ 23, // 23 CDT is already a daylight timezone
+ 24, // 24 LIT has no equivalent DST timezone, but they don't observe DST anyway
+ 26, // 25 BIT + 1 = NT
+ 27, // 26 NT + 1 = HAST
+ 29, // 27 HAST + 1 = AST
+ 28, // 28 MIT has no equivalent DST timezone, but they don't observe DST anyway
+ 30, // 29 AST + 1 = PST
+ 31, // 30 PST + 1 = MST
+ 32, // 31 MST + 1 = CST
+ 33, // 32 CST + 1 = EST
+ 35, // 33 EST + 1 = AST
+ 36, // 34 VST + 1 = NST
+ 37, // 35 AST + 1 = BT
+ 38, // 36 NST + 1 = NDT
+ 39, // 37 BT + 1 = 39
+ 38, // 38 NDT is already a daylight timezone
+ 40, // 39 FNT + 1 = AST
0 // 40 AST + 1 = UTC
};
+const uint8_t movement_dst_inverse_jump_table[] = {
+ 40, // 0
+ 0, // 1
+ 1, // 2
+ 2, // 3
+ 4, // 4
+ 3, // 5
+ 4, // 6
+ 5, // 7
+ 6, // 8
+ 9, // 9
+ 7, // 10
+ 8, // 11
+ 10, // 12
+ 12, // 13
+ 14, // 14
+ 13, // 15
+ 16, // 16
+ 15, // 17
+ 16, // 18
+ 17, // 19
+ 19, // 20
+ 21, // 21
+ 20, // 22
+ 21, // 23
+ 24, // 24
+ 25, // 25
+ 25, // 26
+ 26, // 27
+ 28, // 28
+ 27, // 29
+ 29, // 30
+ 30, // 31
+ 31, // 32
+ 32, // 33
+ 34, // 34
+ 33, // 35
+ 34, // 36
+ 35, // 37
+ 36, // 38
+ 37, // 39
+ 39 // 40
+};
+
const char movement_valid_position_0_chars[] = " AaBbCcDdEeFGgHhIiJKLMNnOoPQrSTtUuWXYZ-='+\\/0123456789";
const char movement_valid_position_1_chars[] = " ABCDEFHlJLNORTtUX-='01378";
}
}
-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
- 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...
watch_faces[i].loop(background_event, &movement_state.settings, watch_face_contexts[i]);
}
}
- _check_and_act_on_daylight_savings();
movement_state.needs_background_tasks_handled = false;
}
return movement_state.next_available_backup_register++;
}
-int16_t get_timezone_offset(uint8_t timezone_idx, watch_date_time date_time) {
- if (movement_state.settings.bit.dst_active && dst_occurring(date_time))
- return movement_timezone_dst_offsets[timezone_idx];
- return movement_timezone_offsets[timezone_idx];
-}
-
void app_init(void) {
#if defined(NO_FREQCORR)
watch_rtc_freqcorr_write(0, 0);
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.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;
filesystem_init();
#if __EMSCRIPTEN__
- const int16_t* timezone_offsets;
int32_t time_zone_offset = EM_ASM_INT({
return -new Date().getTimezoneOffset();
});
- 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] == time_zone_offset) {
+ for (int i = 0, count = sizeof(movement_timezone_offsets) / sizeof(movement_timezone_offsets[0]); i < count; i++) {
+ if (movement_timezone_offsets[i] == time_zone_offset) {
movement_state.settings.bit.time_zone = i;
break;
}
} movement_event_t;
extern const int16_t movement_timezone_offsets[];
-extern const int16_t movement_timezone_dst_offsets[];
+extern const uint8_t movement_dst_jump_table[];
+extern const uint8_t movement_dst_inverse_jump_table[];
extern const char movement_valid_position_0_chars[];
extern const char movement_valid_position_1_chars[];
void movement_play_alarm_beeps(uint8_t rounds, BuzzerNote alarm_note);
uint8_t movement_claim_backup_register(void);
-int16_t get_timezone_offset(uint8_t timezone_idx, watch_date_time date_time);
#endif // MOVEMENT_H_
*/
#define MOVEMENT_DEFAULT_LED_DURATION 1
-/* 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_
case EVENT_ACTIVATE:
case EVENT_TICK:
date_time = watch_rtc_get_date_time();
- centibeats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, event.subsecond, get_timezone_offset(settings->bit.time_zone, date_time));
+ centibeats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, event.subsecond, movement_timezone_offsets[settings->bit.time_zone]);
if (centibeats == state->last_centibeat_displayed) {
// we missed this update, try again next subsecond
state->next_subsecond_update = (event.subsecond + 1) % BEAT_REFRESH_FREQUENCY;
case EVENT_LOW_ENERGY_UPDATE:
if (!watch_tick_animation_is_running()) watch_start_tick_animation(432);
date_time = watch_rtc_get_date_time();
- centibeats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, event.subsecond, get_timezone_offset(settings->bit.time_zone, date_time));
+ centibeats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, event.subsecond, movement_timezone_offsets[settings->bit.time_zone]);
sprintf(buf, "bt %4lu ", centibeats / 100);
watch_display_string(buf, 0);
if (*context_ptr == NULL) {
*context_ptr = malloc(sizeof(day_night_percentage_state_t));
day_night_percentage_state_t *state = (day_night_percentage_state_t *)*context_ptr;
- watch_date_time date_time = watch_rtc_get_date_time();
- watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60, 0);
+ watch_date_time utc_now = watch_utility_date_time_convert_zone(watch_rtc_get_date_time(), movement_timezone_offsets[settings->bit.time_zone] * 60, 0);
recalculate(utc_now, state);
}
}
char buf[12];
watch_date_time date_time = watch_rtc_get_date_time();
- watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60, 0);
+ watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60, 0);
switch (event.event_type) {
case EVENT_ACTIVATE:
static void _update(movement_settings_t *settings, mars_time_state_t *state) {
char buf[11];
watch_date_time date_time = watch_rtc_get_date_time();
- uint32_t now = watch_utility_date_time_to_unix_time(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60);
+ uint32_t now = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
// TODO: I'm skipping over some steps here.
// https://www.giss.nasa.gov/tools/mars24/help/algorithm.html
double jdut = 2440587.5 + ((double)now / 86400.0);
movement_request_tick_frequency(4);
break;
}
- state->tz = get_timezone_offset(settings->bit.time_zone, watch_rtc_get_date_time());
refresh_face = true;
}
/* Determine current time at time zone and store date/time */
date_time = watch_rtc_get_date_time();
- timestamp = watch_utility_date_time_to_unix_time(date_time, state->tz * 60);
- date_time = watch_utility_date_time_from_unix_time(timestamp, state->tz_curr * 60);
+ timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
+ date_time = watch_utility_date_time_from_unix_time(timestamp, movement_timezone_offsets[state->current_zone] * 60);
previous_date_time = state->previous_date_time;
state->previous_date_time = date_time.reg;
watch_clear_indicator(WATCH_INDICATOR_PM);
refresh_face = false;
}
- result = div(state->tz_curr, 60);
+ result = div(movement_timezone_offsets[state->current_zone], 60);
hours = result.quot;
minutes = result.rem;
world_clock2_mode_t current_mode;
uint8_t current_zone;
uint32_t previous_date_time;
- int16_t tz;
- int16_t tz_curr;
} world_clock2_state_t;
void world_clock2_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void **context_ptr);
watch_date_time date_time;
switch (event.event_type) {
case EVENT_ACTIVATE:
- state->tz = get_timezone_offset(settings->bit.time_zone, watch_rtc_get_date_time());
- if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
+ if (settings->bit.clock_mode_24h && !settings->bit.clock_24h_leading_zero) watch_set_indicator(WATCH_INDICATOR_24H);
watch_set_colon();
state->previous_date_time = 0xFFFFFFFF;
// fall through
case EVENT_TICK:
case EVENT_LOW_ENERGY_UPDATE:
date_time = watch_rtc_get_date_time();
- timestamp = watch_utility_date_time_to_unix_time(date_time, state->tz * 60);
- date_time = watch_utility_date_time_from_unix_time(timestamp, state->tz_curr * 60);
+ timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
+ date_time = watch_utility_date_time_from_unix_time(timestamp, movement_timezone_offsets[state->settings.bit.timezone_index] * 60);
previous_date_time = state->previous_date_time;
state->previous_date_time = date_time.reg;
sprintf(buf, "%c%c %3d%02d ",
movement_valid_position_0_chars[state->settings.bit.char_0],
movement_valid_position_1_chars[state->settings.bit.char_1],
- (int8_t) (state->tz_curr / 60),
- (int8_t) (state->tz_curr % 60) * (state->tz_curr < 0 ? -1 : 1));
+ (int8_t) (movement_timezone_offsets[state->settings.bit.timezone_index] / 60),
+ (int8_t) (movement_timezone_offsets[state->settings.bit.timezone_index] % 60) * (movement_timezone_offsets[state->settings.bit.timezone_index] < 0 ? -1 : 1));
watch_set_colon();
watch_clear_indicator(WATCH_INDICATOR_PM);
uint8_t backup_register;
uint8_t current_screen;
uint32_t previous_date_time;
- int16_t tz;
- int16_t tz_curr;
} world_clock_state_t;
void world_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
#endif
watch_date_time date_time = watch_rtc_get_date_time();
- uint32_t timestamp = watch_utility_date_time_to_unix_time(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60);
+ uint32_t timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
date_time = watch_utility_date_time_from_unix_time(timestamp, 0);
double jd = astro_convert_date_to_julian_date(date_time.unit.year + WATCH_RTC_REFERENCE_YEAR, date_time.unit.month, date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
}
}
-static inline int32_t get_tz_offset(movement_settings_t *settings, watch_date_time date_time) {
- return get_timezone_offset(settings->bit.time_zone, date_time) * 60;
+static inline int32_t get_tz_offset(movement_settings_t *settings) {
+ return movement_timezone_offsets[settings->bit.time_zone] * 60;
}
static inline void store_countdown(countdown_state_t *state) {
}
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 -
+ // 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(now, tz);
+ uint32_t new_now = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), get_tz_offset(settings));
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, tz);
+ watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
movement_schedule_background_task_for_face(state->watch_face_index, target_dt);
}
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, now));
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
watch_set_indicator(WATCH_INDICATOR_SIGNAL);
}
watch_set_colon();
(void)state;
char buf[11];
watch_date_time date_time = watch_rtc_get_date_time();
- int16_t tz = get_timezone_offset(settings->bit.time_zone, date_time);
- uint32_t now = watch_utility_date_time_to_unix_time(date_time, tz * 60) + offset;
- date_time = watch_utility_date_time_from_unix_time(now, tz * 60);
+ uint32_t now = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60) + offset;
+ date_time = watch_utility_date_time_from_unix_time(now, movement_timezone_offsets[settings->bit.time_zone] * 60);
double currentfrac = fmod(now - FIRST_MOON, LUNAR_SECONDS) / LUNAR_SECONDS;
double currentday = currentfrac * LUNAR_DAYS;
uint8_t phase_index = 0;
switch (event.event_type) {
case EVENT_ACTIVATE:
-
_update(settings, state, state->offset);
break;
case EVENT_TICK:
static void _orrery_face_recalculate(movement_settings_t *settings, orrery_state_t *state) {
watch_date_time date_time = watch_rtc_get_date_time();
- uint32_t timestamp = watch_utility_date_time_to_unix_time(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60);
+ uint32_t timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
date_time = watch_utility_date_time_from_unix_time(timestamp, 0);
double jd = astro_convert_date_to_julian_date(date_time.unit.year + WATCH_RTC_REFERENCE_YEAR, date_time.unit.month, date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
double et = astro_convert_jd_to_julian_millenia_since_j2000(jd);
state->no_location = false;
watch_date_time date_time = watch_rtc_get_date_time(); // the current local date / time
- int16_t tz = get_timezone_offset(settings->bit.time_zone, date_time);
- watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, tz * 60, 0); // the current date / time in UTC
+ watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60, 0); // the current date / time in UTC
watch_date_time scratch_time; // scratchpad, contains different values at different times
watch_date_time midnight;
scratch_time.reg = midnight.reg = utc_now.reg;
double lon = (double)lon_centi / 100.0;
// save UTC offset
- state->utc_offset = ((double)tz) / 60.0;
+ state->utc_offset = ((double)movement_timezone_offsets[settings->bit.time_zone]) / 60.0;
// 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);
// get current time
watch_date_time date_time = watch_rtc_get_date_time(); // the current local date / time
- watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60, 0); // the current date / time in UTC
+ watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60, 0); // the current date / time in UTC
current_hour_epoch = watch_utility_date_time_to_unix_time(utc_now, 0);
// set the current planetary hour as default screen
// 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
state->no_location = false;
watch_date_time date_time = watch_rtc_get_date_time(); // the current local date / time
- int16_t tz = get_timezone_offset(settings->bit.time_zone, date_time);
- watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, tz * 60, 0); // the current date / time in UTC
+ watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60, 0); // the current date / time in UTC
watch_date_time scratch_time; // scratchpad, contains different values at different times
watch_date_time midnight;
scratch_time.reg = midnight.reg = utc_now.reg;
double lon = (double)lon_centi / 100.0;
// save UTC offset
- state->utc_offset = ((double)tz) / 60.0;
+ state->utc_offset = ((double)movement_timezone_offsets[settings->bit.time_zone]) / 60.0;
// get UNIX epoch time
now_epoch = watch_utility_date_time_to_unix_time(utc_now, 0);
// 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));
}
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(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60, 0);
+ state->scratch = watch_utility_date_time_convert_zone(watch_rtc_get_date_time(), movement_timezone_offsets[settings->bit.time_zone] * 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);
#endif
planetary_time_state_t *state = (planetary_time_state_t *)context;
-
+
// calculate phase
_planetary_solar_phase(settings, state);
}
#define sl_SELECTIONS 6
#define DEFAULT_MINUTES { 5,4,1,0,0,0 }
-static inline int32_t get_tz_offset(movement_settings_t *settings, watch_date_time date_time) {
- return get_timezone_offset(settings->bit.time_zone, date_time) * 60;
+static inline int32_t get_tz_offset(movement_settings_t *settings) {
+ return movement_timezone_offsets[settings->bit.time_zone] * 60;
}
static int lap = 0;
return;
}
state->nextbeep_ts = state->target_ts - beepseconds[beepflag+1];
- watch_date_time now = watch_rtc_get_date_time();
- watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->nextbeep_ts, get_tz_offset(settings, now));
+ watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->nextbeep_ts, get_tz_offset(settings));
movement_schedule_background_task_for_face(state->watch_face_index, target_dt);
//background task is set, now we have time to play the tune. If this is cancelled accidentally, the next alarm will still ring. Sound is implemented non-blocking, so that neither buttons nor display output are compromised.
for (int i = 0; i < 5; i++) {
}
if (state->index > 5 || state->minutes[state->index] == 0) {
watch_date_time now = watch_rtc_get_date_time();
- state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings, now));
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
state->target_ts = state->now_ts;
if (alarmflag != 0){
watch_buzzer_play_sequence(long_beep, NULL);
movement_request_tick_frequency(1); //synchronises tick with the moment the button was pressed. Solves 1s offset between sound and display, solves up to +-0.5s offset between button action and display.
state->mode = sl_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, now));
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
state->target_ts = watch_utility_offset_timestamp(state->now_ts, 0, state->minutes[state->index], 0);
ring(state, settings);
}
sailing_state_t *state = (sailing_state_t *)context;
if(state->mode == sl_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, now));
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
}
if(state->mode == sl_counting) {
watch_date_time now = watch_rtc_get_date_time();
- state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings, now));
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
watch_set_indicator(WATCH_INDICATOR_LAP);
}
switch (alarmflag) {
}
static void calculate_datetimes(solstice_state_t *state, movement_settings_t *settings) {
- watch_date_time date_time = watch_rtc_get_date_time();
for (int i = 0; i < 4; i++) {
// TODO: handle DST changes
- state->datetimes[i] = jde_to_date_time(calculate_solstice_equinox(2020 + state->year, i) + (get_timezone_offset(settings->bit.time_zone, date_time) / (60.0*24.0)));
+ state->datetimes[i] = jde_to_date_time(calculate_solstice_equinox(2020 + state->year, i) + (movement_timezone_offsets[settings->bit.time_zone] / (60.0*24.0)));
}
}
}
watch_date_time date_time = watch_rtc_get_date_time(); // the current local date / time
- watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, state->tz * 60, 0); // the current date / time in UTC
+ watch_date_time utc_now = watch_utility_date_time_convert_zone(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60, 0); // the current date / time in UTC
watch_date_time scratch_time; // scratchpad, contains different values at different times
scratch_time.reg = utc_now.reg;
// sunriset returns the rise/set times as signed decimal hours in UTC.
// this can mean hours below 0 or above 31, which won't fit into a watch_date_time struct.
// to deal with this, we set aside the offset in hours, and add it back before converting it to a watch_date_time.
- double hours_from_utc = ((double)state->tz) / 60.0;
+ double hours_from_utc = ((double)movement_timezone_offsets[settings->bit.time_zone]) / 60.0;
// we loop twice because if it's after sunset today, we need to recalculate to display values for tomorrow.
for(int i = 0; i < 2; i++) {
movement_location_t movement_location = (movement_location_t) watch_get_backup_data(1);
state->working_latitude = _sunrise_sunset_face_struct_from_latlon(movement_location.bit.latitude);
state->working_longitude = _sunrise_sunset_face_struct_from_latlon(movement_location.bit.longitude);
- state->tz = get_timezone_offset(settings->bit.time_zone, watch_rtc_get_date_time());
}
bool sunrise_sunset_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
uint8_t rise_index;
uint8_t active_digit;
bool location_changed;
- int16_t tz;
watch_date_time rise_set_expires;
sunrise_sunset_lat_lon_settings_t working_latitude;
sunrise_sunset_lat_lon_settings_t working_longitude;
static uint8_t _beeps_to_play; // temporary counter for ring signals playing
-static inline int32_t _get_tz_offset(movement_settings_t *settings, watch_date_time date_time) {
- return get_timezone_offset(settings->bit.time_zone, date_time) * 60;
+static inline int32_t _get_tz_offset(movement_settings_t *settings) {
+ return movement_timezone_offsets[settings->bit.time_zone] * 60;
}
static void _signal_callback() {
static void _start(timer_state_t *state, movement_settings_t *settings, bool with_beep) {
if (state->timers[state->current_timer].value == 0) return;
watch_date_time now = watch_rtc_get_date_time();
- int32_t tz = _get_tz_offset(settings, now);
- state->now_ts = watch_utility_date_time_to_unix_time(now, tz);
+ state->now_ts = watch_utility_date_time_to_unix_time(now, _get_tz_offset(settings));
if (state->mode == pausing)
state->target_ts = state->now_ts + state->paused_left;
else
state->timers[state->current_timer].unit.hours,
state->timers[state->current_timer].unit.minutes,
state->timers[state->current_timer].unit.seconds);
- watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, tz);
+ watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, _get_tz_offset(settings));
state->mode = running;
movement_schedule_background_task_for_face(state->watch_face_index, target_dt);
watch_set_indicator(WATCH_INDICATOR_BELL);
watch_set_colon();
if(state->mode == 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, now));
+ state->now_ts = watch_utility_date_time_to_unix_time(now, _get_tz_offset(settings));
watch_set_indicator(WATCH_INDICATOR_BELL);
} else {
state->pausing_seconds = 1;
static uint8_t focus_min = 25;
static uint8_t break_min = 5;
-static inline int32_t get_tz_offset(movement_settings_t *settings, watch_date_time date_time) {
- return get_timezone_offset(settings->bit.time_zone, date_time) * 60;
+static inline int32_t get_tz_offset(movement_settings_t *settings) {
+ return movement_timezone_offsets[settings->bit.time_zone] * 60;
}
static uint8_t get_length(tomato_state_t *state) {
static void tomato_start(tomato_state_t *state, movement_settings_t *settings) {
watch_date_time now = watch_rtc_get_date_time();
- int32_t tz = get_tz_offset(settings, now);
int8_t length = (int8_t) get_length(state);
state->mode = tomato_run;
- state->now_ts = watch_utility_date_time_to_unix_time(now, tz);
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
state->target_ts = watch_utility_offset_timestamp(state->now_ts, 0, length, 0);
- watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, tz);
+ watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
movement_schedule_background_task(target_dt);
watch_set_indicator(WATCH_INDICATOR_BELL);
}
tomato_state_t *state = (tomato_state_t *)context;
if (state->mode == tomato_run) {
watch_date_time now = watch_rtc_get_date_time();
- state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings, now));
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
watch_set_indicator(WATCH_INDICATOR_BELL);
}
watch_set_colon();
totp_display(totp_state);
}
-static uint32_t totp_compute_base_timestamp(movement_settings_t *settings) {
- watch_date_time date_time = watch_rtc_get_date_time();
- return watch_utility_date_time_to_unix_time(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60);
+static inline uint32_t totp_compute_base_timestamp(movement_settings_t *settings) {
+ return watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), movement_timezone_offsets[settings->bit.time_zone] * 60);
}
void totp_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
}
#endif
- watch_date_time date_time = watch_rtc_get_date_time();
- totp_state->timestamp = watch_utility_date_time_to_unix_time(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60);
+ totp_state->timestamp = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), movement_timezone_offsets[settings->bit.time_zone] * 60);
totp_face_set_record(totp_state, 0);
}
accelerometer_data_acquisition_record_t record;
watch_date_time date_time = watch_rtc_get_date_time();
- state->starting_timestamp = watch_utility_date_time_to_unix_time(date_time, get_timezone_offset(settings->bit.time_zone, date_time) * 60);
+ state->starting_timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
record.header.info.record_type = ACCELEROMETER_DATA_ACQUISITION_HEADER;
record.header.info.range = ACCELEROMETER_RANGE;
record.header.info.temperature = lis2dw_get_temperature();
if (settings->bit.time_zone > 40) settings->bit.time_zone = 0;
break;
case 7: // daylight savings time
+ if (settings->bit.dst_active) { // deactivate DST
+ date_time.unit.hour = (date_time.unit.hour + 24 - 1) % 24;
+ settings->bit.time_zone = movement_dst_inverse_jump_table[settings->bit.time_zone];
+ } else { // activate DST
+ date_time.unit.hour = (date_time.unit.hour + 1) % 24;
+ settings->bit.time_zone = movement_dst_jump_table[settings->bit.time_zone];
+ }
settings->bit.dst_active = !settings->bit.dst_active;
break;
}
return movement_default_loop_handler(event, settings);
}
- char buf[13];
+ char buf[11];
bool set_leading_zero = false;
-
if (current_page < 3) {
watch_set_colon();
if (settings->bit.clock_mode_24h) {
watch_clear_indicator(WATCH_INDICATOR_PM);
sprintf(buf, "%s %2d%02d%02d", set_time_face_titles[current_page], date_time.unit.year + 20, date_time.unit.month, date_time.unit.day);
} else if (current_page < 7) { // zone
- char dst_char = (settings->bit.dst_active && dst_occurring(watch_rtc_get_date_time())) ? 'd' : ' ';
if (event.subsecond % 2) {
watch_clear_colon();
- sprintf(buf, "%s %c", set_time_face_titles[current_page], dst_char);
+ sprintf(buf, "%s ", set_time_face_titles[current_page]);
} else {
- int16_t tz = get_timezone_offset(settings->bit.time_zone, date_time);
watch_set_colon();
- sprintf(buf, "%s %3d%02d %c", set_time_face_titles[current_page], (int8_t) (tz / 60), (int8_t) (tz % 60) * (tz < 0 ? -1 : 1), dst_char);
+ sprintf(buf, "%s %3d%02d ", set_time_face_titles[current_page], (int8_t) (movement_timezone_offsets[settings->bit.time_zone] / 60), (int8_t) (movement_timezone_offsets[settings->bit.time_zone] % 60) * (movement_timezone_offsets[settings->bit.time_zone] < 0 ? -1 : 1));
}
} else { // daylight savings
watch_clear_colon();
- sprintf(buf, "%s dsT %c", set_time_face_titles[current_page], settings->bit.dst_active ? 'y' : 'n');
+ if (settings->bit.dst_active) sprintf(buf, "%s dsT y", set_time_face_titles[current_page]);
+ else sprintf(buf, "%s dsT n", set_time_face_titles[current_page]);
}
// blink up the parameter we're setting
}
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
if (settings->bit.time_zone > 40) settings->bit.time_zone = 0;
break;
}
-
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
+ 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);
watch_clear_colon();
sprintf(buf, "%s ", set_time_hackwatch_face_titles[current_page]);
} else {
- int16_t tz = get_timezone_offset(settings->bit.time_zone, date_time_settings);
watch_set_colon();
sprintf(buf,
"%s %3d%02d ",
set_time_hackwatch_face_titles[current_page],
- (int8_t)(tz / 60),
- (int8_t)(tz % 60) * (tz < 0 ? -1 : 1));
+ (int8_t)(movement_timezone_offsets[settings->bit.time_zone] / 60),
+ (int8_t)(movement_timezone_offsets[settings->bit.time_zone] % 60) * (movement_timezone_offsets[settings->bit.time_zone] < 0 ? -1 : 1));
}
}
ext_irq_cb_t a2_callback;
ext_irq_cb_t a4_callback;
-static bool dst_skip_rolling_back;
-bool get_dst_skip_rolling_back(void) {
- return dst_skip_rolling_back;
-}
-
-void set_dst_skip_rolling_back(void) {
- dst_skip_rolling_back = true;
-}
-
-void clear_dst_skip_rolling_back(void) {
- dst_skip_rolling_back = false;
-}
-
bool _watch_rtc_is_enabled(void) {
return RTC->MODE2.CTRLA.bit.ENABLE;
}
_sync_rtc(); // Double sync as without it at high Hz faces setting time is unrealiable (specifically, set_time_hackwatch)
RTC->MODE2.CLOCK.reg = date_time.reg;
_sync_rtc();
- clear_dst_skip_rolling_back();
}
watch_date_time watch_rtc_get_date_time(void) {
*/
void watch_rtc_freqcorr_write(int16_t value, int16_t sign);
-/** @brief Returns if we're currently at a point where the we rolled back for DST and need to ignore the next DST segment
- */
-bool get_dst_skip_rolling_back(void);
-void set_dst_skip_rolling_back(void);
-void clear_dst_skip_rolling_back(void);
-
/// @}
#endif
return !(y%4) && ((y%100) || !(y%400));
}
-uint8_t get_dst_status(watch_date_time date_time) {
- watch_date_time dst_start_time;
- watch_date_time dst_end_time;
- uint32_t unix_dst_start_time;
- uint32_t unix_dst_end_time;
- uint32_t unix_curr_time;
-
- dst_start_time.unit.year = date_time.unit.year;
- dst_start_time.unit.month = 3;
- dst_start_time.unit.hour = 2;
- dst_start_time.unit.minute = 0;
- dst_start_time.unit.second = 0;
- dst_start_time.unit.day = 15 - watch_utility_get_iso8601_weekday_number(dst_start_time.unit.year + WATCH_RTC_REFERENCE_YEAR, dst_start_time.unit.month, 1);
- unix_dst_start_time = watch_utility_date_time_to_unix_time(dst_start_time, 0);
-
- dst_end_time.unit.year = date_time.unit.year;
- dst_end_time.unit.month = 11;
- dst_end_time.unit.hour = 2;
- dst_end_time.unit.minute = 0;
- dst_end_time.unit.second = 0;
- dst_end_time.unit.day = 15 - watch_utility_get_iso8601_weekday_number(dst_end_time.unit.year + WATCH_RTC_REFERENCE_YEAR, dst_end_time.unit.month, 1);
- unix_dst_end_time = watch_utility_date_time_to_unix_time(dst_end_time, 0);
-
- unix_curr_time = watch_utility_date_time_to_unix_time(date_time, 0);
- unix_curr_time -= date_time.unit.second;
- if (date_time.unit.second > 45) // In emu, it's been seen that we may trigger at 59sec rather than exactly 0 each time
- unix_curr_time += 60;
-
- if (unix_curr_time == unix_dst_start_time) return DST_STARTING;
- if (unix_curr_time == unix_dst_end_time) return DST_ENDING;
- if (unix_curr_time > unix_dst_end_time || unix_curr_time < unix_dst_start_time) return DST_ENDED;
- return DST_OCCURRING;
-}
-
-bool dst_occurring(watch_date_time date_time) {
- return get_dst_status(date_time) <= DST_OCCURRING;
-}
-
uint16_t watch_utility_days_since_new_year(uint16_t year, uint8_t month, uint8_t day) {
uint16_t DAYS_SO_FAR[] = {
0, // Jan
uint32_t days; // 0-4294967295
} watch_duration_t;
-typedef enum {
- DST_STARTING,
- DST_OCCURRING,
- DST_ENDING,
- DST_ENDED
-} dst_t;
-
/** @brief Returns a two-letter weekday for the given timestamp, suitable for display
* in positions 0-1 of the watch face
* @param date_time The watch_date_time whose weekday you want.
*/
uint8_t is_leap(uint16_t year);
-/** @brief Returns off of dst_t based off if DST is occurring, srted, ended, or none of those.
- * @param date_time The watch_date_time that you wish to convert.
- * @return DST_OCCURRING, DST_HAPPENING, DST_ENDING, DST_ENDED
- */
-uint8_t get_dst_status(watch_date_time date_time);
-
-/** @brief Returns true if it's DST and false otherwise.
- * @param date_time The watch_date_time that you wish to convert.
- */
-bool dst_occurring(watch_date_time date_time);
-
/** @brief Returns the UNIX time (seconds since 1970) for a given date/time in UTC.
* @param date_time The watch_date_time that you wish to convert.
* @param year The year of the date you wish to convert.
ext_irq_cb_t a2_callback;
ext_irq_cb_t a4_callback;
-static bool dst_skip_rolling_back;
-bool get_dst_skip_rolling_back(void) {
- return dst_skip_rolling_back;
-}
-
-void set_dst_skip_rolling_back(void) {
- dst_skip_rolling_back = true;
-}
-
-void clear_dst_skip_rolling_back(void) {
- dst_skip_rolling_back = false;
-}
-
bool _watch_rtc_is_enabled(void) {
return true;
}
const date = new Date(year, month - 1, day, hour, minute, second);
return date - Date.now();
}, date_time.reg);
- clear_dst_skip_rolling_back();
}
watch_date_time watch_rtc_get_date_time(void) {