]> git.earman.xyz Git - sensor-watch.git/commitdiff
optimize totp face and add countdown
authorWesley Ellis <tahnok@gmail.com>
Wed, 24 Nov 2021 02:32:43 +0000 (21:32 -0500)
committerWesley Ellis <tahnok@gmail.com>
Wed, 24 Nov 2021 02:40:27 +0000 (21:40 -0500)
movement/watch_faces/complications/totp_face.c
movement/watch_faces/complications/totp_face.h

index 2e8b5f668d9d692d3ca42db6e095b78d16b9a38a..017a774b0af419384d05688c20a0c03521ea051d 100644 (file)
 /**
- * 
  * 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 <stdlib.h>
 #include <string.h>
 #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
+}
index 1fecb82aaa20eb6b89263d084d6f86a6ab972d9b..0527627aae38e3e2ec909757d3a657e5a3c47046 100644 (file)
@@ -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_