From 121e6fd165a03f9249100e73bdf658e545e10d25 Mon Sep 17 00:00:00 2001 From: Wesley Ellis Date: Tue, 23 Nov 2021 21:32:43 -0500 Subject: optimize totp face and add countdown --- movement/watch_faces/complications/totp_face.c | 110 ++++++------------------- movement/watch_faces/complications/totp_face.h | 9 +- 2 files changed, 35 insertions(+), 84 deletions(-) (limited to 'movement') diff --git a/movement/watch_faces/complications/totp_face.c b/movement/watch_faces/complications/totp_face.c index 2e8b5f66..017a774b 100644 --- a/movement/watch_faces/complications/totp_face.c +++ b/movement/watch_faces/complications/totp_face.c @@ -1,114 +1,58 @@ /** - * * TODO: - * - this ONLY works if watch is set to UTC, probably worth including a TZ offset setting since it can be used by beats as well - * - show how long code is valid for in upper right corner of LCD - * - optimize code so that we don't calculating a new unix timestamp every second AND a new TOTP code + * - Add support for UTC offset in settings? * - Support for multiple codes */ #include #include #include "totp_face.h" #include "watch.h" +#include "watch_utility.h" #include "TOTP.h" // test key: JBSWY3DPEHPK3PXP // Use https://cryptii.com/pipes/base32-to-hex to convert base32 to hex // Use https://totp.danhersam.com/ to generate test codes for verification -uint8_t hmacKey[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0xde, 0xad, 0xbe, 0xef}; // Secret key +static uint8_t hmacKey[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0xde, 0xad, 0xbe, 0xef}; // Secret key + + +static const uint8_t UTC_OFFSET = 5; // set to your current UTC offset +static const uint32_t TIMESTEP = 30; void totp_face_setup(movement_settings_t *settings, void ** context_ptr) { (void) settings; - (void) context_ptr; - TOTP(hmacKey, sizeof(hmacKey), 30); + if (*context_ptr == NULL) *context_ptr = malloc(sizeof(totp_state_t)); + TOTP(hmacKey, sizeof(hmacKey), TIMESTEP); } void totp_face_activate(movement_settings_t *settings, void *context) { (void) settings; - (void) context; -} - -/** - * @brief Get unix timestamp from component parts - * - * @param year - * @param month - * @param day - * @param hour - * @param minute - * @param second - * @return uint32_t - * - * Based on code by Josh Haberman for upb - * from https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html - * - * Essentially we need to calculate how many days have occured since year 0 - * including leap years! The following code does some clever calculations - * of the number of february's then offsets based on how many leap years - * there have been - * - * Once we have the number of days in the year, it's easy enough to add how - * many days have happened in the current year, then convert that to seconds - */ -uint32_t current_unix_time(uint32_t year, uint32_t month, uint32_t day, - uint32_t hour, uint32_t minute, uint32_t second) { - uint16_t DAYS_SO_FAR[] = { - 0, // Jan - 31, // Feb - 59, // March - 90, // April - 120, // May - 151, // June - 181, // July - 212, // August - 243, // September - 273, // October - 304, // November - 334 // December - }; - - - uint32_t year_adj = year + 4800; - uint32_t febs = year_adj - (month <= 2 ? 1 : 0); /* Februaries since base. */ - uint32_t leap_days = 1 + (febs / 4) - (febs / 100) + (febs / 400); - uint32_t days = 365 * year_adj + leap_days + DAYS_SO_FAR[month - 1] + day - 1; - days -= 2472692; /* Adjust to Unix epoch. */ - - uint32_t timestamp = days * 86400; - timestamp += hour * 3600; - timestamp += minute * 60; - timestamp += second; - - return timestamp; -} - -uint32_t current_unix_time_from_rtc() { - watch_date_time date_time = watch_rtc_get_date_time(); - return current_unix_time( - date_time.unit.year + 2020, // year is stored starting in 2020 - date_time.unit.month, - date_time.unit.day, - date_time.unit.hour, - date_time.unit.minute, - date_time.unit.second - ); + memset(context, 0, sizeof(totp_state_t)); + totp_state_t *totp_state = (totp_state_t *)context; + totp_state->timestamp = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), UTC_OFFSET); + totp_state->current_code = getCodeFromTimestamp(totp_state->timestamp); } bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { (void) settings; - (void) context; + totp_state_t *totp_state = (totp_state_t *)context; char buf[14]; - watch_date_time date_time = watch_rtc_get_date_time(); + uint8_t valid_for; + div_t result; - uint32_t ts; - uint32_t code; switch (event.event_type) { - case EVENT_ACTIVATE: case EVENT_TICK: - ts = current_unix_time_from_rtc(); - code = getCodeFromTimestamp(ts); - sprintf(buf, "2f %lu", code); + totp_state->timestamp++; + // fall through + case EVENT_ACTIVATE: + result = div(totp_state->timestamp, TIMESTEP); + if (result.quot != totp_state->steps) { + totp_state->current_code = getCodeFromTimestamp(totp_state->timestamp); + totp_state->steps = result.quot; + } + valid_for = TIMESTEP - result.rem; + sprintf(buf, "2f%2d%lu", valid_for, totp_state->current_code); watch_display_string(buf, 0); break; @@ -134,4 +78,4 @@ bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void void totp_face_resign(movement_settings_t *settings, void *context) { (void) settings; (void) context; -} \ No newline at end of file +} diff --git a/movement/watch_faces/complications/totp_face.h b/movement/watch_faces/complications/totp_face.h index 1fecb82a..0527627a 100644 --- a/movement/watch_faces/complications/totp_face.h +++ b/movement/watch_faces/complications/totp_face.h @@ -3,6 +3,13 @@ #include "movement.h" +typedef struct { + uint32_t timestamp; + uint8_t steps; + uint32_t current_code; + +} totp_state_t; + void totp_face_setup(movement_settings_t *settings, void ** context_ptr); void totp_face_activate(movement_settings_t *settings, void *context); bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void *context); @@ -16,4 +23,4 @@ static const watch_face_t totp_face = { NULL }; -#endif // TOTP_FACE_H_ \ No newline at end of file +#endif // TOTP_FACE_H_ -- cgit v1.2.3