summaryrefslogtreecommitdiffstats
path: root/movement
diff options
context:
space:
mode:
authorWesley Ellis <tahnok@gmail.com>2021-11-22 21:20:57 -0500
committerWesley Ellis <tahnok@gmail.com>2021-11-22 21:37:21 -0500
commitb7ed9adb6c41089da75d258d7148fa87d2f76d20 (patch)
tree6cfe28b0652d193d46e36590cd831db68fc8fb85 /movement
parent7817e6696e438c8af74342ef10b576975a0e5448 (diff)
downloadSensor-Watch-b7ed9adb6c41089da75d258d7148fa87d2f76d20.tar.gz
Sensor-Watch-b7ed9adb6c41089da75d258d7148fa87d2f76d20.tar.bz2
Sensor-Watch-b7ed9adb6c41089da75d258d7148fa87d2f76d20.zip
Add initial TOTP watch face impl
Vendor code from https://github.com/Netthaw/TOTP-MCU to do the heavy lifting of computing SHA-1 and HMAC and the rest of TOTP Also implement a date_time to unix timestamp method
Diffstat (limited to 'movement')
m---------movement/lib/TOTP-MCU0
-rwxr-xr-xmovement/make/Makefile4
-rw-r--r--movement/movement_config.h1
-rw-r--r--movement/watch_faces/complications/totp_face.c137
-rw-r--r--movement/watch_faces/complications/totp_face.h19
5 files changed, 161 insertions, 0 deletions
diff --git a/movement/lib/TOTP-MCU b/movement/lib/TOTP-MCU
new file mode 160000
+Subproject 646474a8757e1fca490792e81082b2ad89b966a
diff --git a/movement/make/Makefile b/movement/make/Makefile
index b595d2dd..4c895322 100755
--- a/movement/make/Makefile
+++ b/movement/make/Makefile
@@ -16,6 +16,7 @@ INCLUDES += \
-I../watch_faces/complications/ \
-I../watch_faces/thermistor/ \
-I../watch_faces/demos/ \
+ -I../lib/TOTP-MCU/ \
# If you add any other source files you wish to compile, add them after ../app.c
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
@@ -24,6 +25,8 @@ INCLUDES += \
# ../drivers/lis2dh.c \
# ../watch_faces/fitness/step_count_face.c
SRCS += \
+ ../lib/TOTP-MCU/sha1.c \
+ ../lib/TOTP-MCU/TOTP.c \
../movement.c \
../watch_faces/clock/simple_clock_face.c \
../watch_faces/settings/preferences_face.c \
@@ -37,6 +40,7 @@ SRCS += \
../watch_faces/complications/beats_face.c \
../watch_faces/complications/day_one_face.c \
../watch_faces/complications/stopwatch_face.c \
+ ../watch_faces/complications/totp_face.c \
# Leave this line at the bottom of the file; it has all the targets for making your project.
include $(TOP)/rules.mk
diff --git a/movement/movement_config.h b/movement/movement_config.h
index fa5ddf18..8802883d 100644
--- a/movement/movement_config.h
+++ b/movement/movement_config.h
@@ -12,6 +12,7 @@
#include "day_one_face.h"
#include "voltage_face.h"
#include "stopwatch_face.h"
+#include "totp_face.h"
const watch_face_t watch_faces[] = {
simple_clock_face,
diff --git a/movement/watch_faces/complications/totp_face.c b/movement/watch_faces/complications/totp_face.c
new file mode 100644
index 00000000..2e8b5f66
--- /dev/null
+++ b/movement/watch_faces/complications/totp_face.c
@@ -0,0 +1,137 @@
+/**
+ *
+ * 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
+ * - Support for multiple codes
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "totp_face.h"
+#include "watch.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
+
+void totp_face_setup(movement_settings_t *settings, void ** context_ptr) {
+ (void) settings;
+ (void) context_ptr;
+ TOTP(hmacKey, sizeof(hmacKey), 30);
+}
+
+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
+ );
+}
+
+bool totp_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
+ (void) settings;
+ (void) context;
+
+ char buf[14];
+ watch_date_time date_time = watch_rtc_get_date_time();
+
+ 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);
+
+ watch_display_string(buf, 0);
+ break;
+ case EVENT_MODE_BUTTON_UP:
+ movement_move_to_next_face();
+ break;
+ case EVENT_LIGHT_BUTTON_DOWN:
+ movement_illuminate_led();
+ break;
+ case EVENT_TIMEOUT:
+ // go home
+ break;
+ case EVENT_ALARM_BUTTON_DOWN:
+ case EVENT_ALARM_BUTTON_UP:
+ case EVENT_ALARM_LONG_PRESS:
+ default:
+ break;
+ }
+
+ return true;
+}
+
+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
new file mode 100644
index 00000000..1fecb82a
--- /dev/null
+++ b/movement/watch_faces/complications/totp_face.h
@@ -0,0 +1,19 @@
+#ifndef TOTP_FACE_H_
+#define TOTP_FACE_H_
+
+#include "movement.h"
+
+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);
+void totp_face_resign(movement_settings_t *settings, void *context);
+
+static const watch_face_t totp_face = {
+ totp_face_setup,
+ totp_face_activate,
+ totp_face_loop,
+ totp_face_resign,
+ NULL
+};
+
+#endif // TOTP_FACE_H_ \ No newline at end of file