Fix missing documentation for many clock faces:

* Move from .c to .h as needed for consistency.
* When missing from both, copy from pull request or wiki.
* When missing entirely, infer functionality from source code.
This commit is contained in:
Alex Utter 2023-11-27 20:06:19 -08:00 committed by GitHub
parent 3487d742f1
commit 7802994854
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
91 changed files with 1405 additions and 592 deletions

View File

@ -1,3 +1,27 @@
/*
* MIT License
*
* Copyright (c) 2023 Wesley Ellis <https://github.com/tahnok>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include "beats_face.h"

View File

@ -1,6 +1,41 @@
/*
* MIT License
*
* Copyright (c) 2023 Wesley Ellis <https://github.com/tahnok>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef BEATS_FACE_H_
#define BEATS_FACE_H_
/*
* BEATS TIME face
*
* The Beat Time face displays the current Swatch Internet Time, or .beat time.
* This is a decimal time system that divides the day into 1000 beats.
*
* The three large digits in the bottom row indicate the current beat, and the
* two smaller digits (normally the seconds in Simple Clock) indicate the
* fractional beat; so for example you can read 67214 as beat 672.14.
*/
#include "movement.h"
typedef struct {

View File

@ -25,10 +25,8 @@
#ifndef DECIMAL_TIME_FACE_H_
#define DECIMAL_TIME_FACE_H_
#include "movement.h"
/*
* DECIMAL TIME FACE
* DECIMAL TIME face
*
* This face presents the current time as hours and hundredths of an hour. Every hundreth of an hour, or "centihour",
* occurs every 36 seconds. Because they range from 0 to 99, centihours, in the seventies range, will be displayed with a lowercase 7.
@ -46,9 +44,10 @@
* https://hr.colostate.edu/minute-to-decimal-conversion-chart/
*
* Many thanks go to Joey Castillo for making this project happen.
*
*/
#include "movement.h"
typedef struct {
bool chime_enabled; // did the user enable hourly chime for this face?
uint8_t features_to_show : 2 ; // what features are to be displayed?

View File

@ -25,6 +25,32 @@
#ifndef MARS_TIME_FACE_H_
#define MARS_TIME_FACE_H_
/*
* MARS TIME face
*
* This watch face is dedicated to Martian timekeeping.
* It has several modes, and can display either a time or a date.
*
* Pressing the ALARM button cycles through different time zones on Mars:
* MC - Mars Coordinated Time, the time at Airy-0 Crater on the Martian prime meridian
* ZH - Local mean solar time for the Zhurong rover
* PE - LMST for the Perseverance rover
* IN - LMST for the Insight lander
* CU - LMST for the Curiosity rover
*
* Press the LIGHT button to toggle between displaying time and date:
* MC S - the Mars Sol Date, Martian days since December 29, 1873
* ZH Sol - Mission sol for the Zhurong rover
* PE Sol - Mission sol for the Perseverance rover
* IN S - Mission sol for the InSight lander
* CU S - Mission sol for the Curiosity rover
*
* Note that where the mission sol is below 1000, this watch face displays
* the word Sol on the bottom line. When the mission sol is over 1000, the
* word Sol will not fit and so it displays a stylized letter S at the top
* right.
*/
#include "movement.h"
typedef enum {

View File

@ -25,9 +25,9 @@
#ifndef REPETITION_MINUTE_FACE_H_
#define REPETITION_MINUTE_FACE_H_
#include "movement.h"
/*
* REPETITION MINUTE face
*
* A hopefully useful complication for friendly neighbors in the dark
*
* Originating from 1676 from reverend and mechanician Edward Barlow, and
@ -40,7 +40,6 @@
* before widespread artificial illumination, to allow the time to be determined
* in the dark, and were also used by the visually impaired.
*
*
* How to use it :
*
* Long press the light button to get an auditive reading of the time like so :
@ -51,9 +50,10 @@
* Prerequisite : a watch with a working buzzer
*
* ~ Only in the darkness can you see the stars. - Martin Luther King ~
*
*/
#include "movement.h"
typedef struct {
uint32_t previous_date_time;
uint8_t last_battery_check;

View File

@ -25,9 +25,9 @@
#ifndef SIIMPLE_CLOCK_BIN_LED_FACE_H_
#define SIIMPLE_CLOCK_BIN_LED_FACE_H_
#include "movement.h"
/*
* BINARY LED CLOCK FACE
*
* A "fork" of the simple clock face, which provides the functionality of showing
* the current time by flashing the LED using binary representation.
*
@ -49,6 +49,8 @@
* represents 1.
*/
#include "movement.h"
typedef struct {
uint32_t previous_date_time;
uint8_t last_battery_check;

View File

@ -25,6 +25,15 @@
#ifndef SIMPLE_CLOCK_FACE_H_
#define SIMPLE_CLOCK_FACE_H_
/*
* SIMPLE CLOCK FACE
*
* Displays the current time, matching the original operation of the watch.
* This is the default display mode in most watch configurations.
*
* Long-press ALARM to toggle the hourly chime.
*/
#include "movement.h"
typedef struct {

View File

@ -25,6 +25,14 @@
#ifndef WEEKNUMBER_CLOCK_FACE_H_
#define WEEKNUMBER_CLOCK_FACE_H_
/*
* WEEK-NUMBER WATCH FACE
*
* Same as simple clock, but has iso 8601 week number instead of seconds counter.
*
* Long-press ALARM to toggle the hourly chime.
*/
#include "movement.h"
typedef struct {

View File

@ -23,79 +23,6 @@
* SOFTWARE.
*/
/*
* World Clock 2
* =============
*
* This is an alternative world clock face that allows the user to cycle
* through a list of selected time zones. It extends the original
* implementation by Joey Castillo. The face has two modes *display mode*
* and *settings mode*.
*
* ### Settings mode
*
* When the clock face is activated for the first time, it enters
* *settings mode*. Here, the user can select the time zones they want to
* display. The face shows a summary of the current time zone:
*
* - The top of the face displays the first two letters of the time zone
* abbreviation, such as "PS" for Pacific Standard Time or CE for
* "Central European Time".
*
* - The upper-right corner shows the index number of the time zone. This
* helps avoid confusion when multiple time zones have the same
* two-letter abbreviation.
*
* - The main display shows the offset from UTC, with a "+" indicating a
* positive offset and a "-" indicating a negative offset. For example,
* the offset for Japanese Standard Time is displayed as "+9:00".
*
* The user can navigate through the time zones and select them using the
* following buttons:
*
* - The *alarm button* moves forward to the next time zone, while the
* *light button* moves backward to the previous zone. This way, the
* user can cycle through all 41 supported time zones.
*
* - A *long press* on the *light button* selects the current time zone,
* and the signal indicator appears at the top left. Another *long
* press* of the *light button* deselects the time zone.
*
* - A *long press* on the *alarm button* exits settings mode and returns
* to display mode.
*
* ### Display mode
*
* In the display mode, the face shows the time of the currently selected
* time zone. The face includes the following components:
*
* - The top of the face displays the first two letters of the time zone
* abbreviation, such as "PS" for Pacific Standard Time or "CE" for
* Central European Time.
*
* - The upper-right corner shows the current day of the month, which
* helps indicate time zones that cross the international date line
* with respect to the local time.
*
* - The main display shows the time in the selected time zone in either
* 12-hour or 24-hour form. There is no timeout, allowing users to keep
* the chosen time zone displayed for as long as they wish.
*
* The user can navigate through the selected time zones using the
* following buttons:
*
* - The *alarm button* moves to the next selected time zone, while the
* light button moves to the *previous zone*. If no time zone is
* selected, the face simply shows UTC.
*
* - A *long press* on the *alarm button* enters settings mode and
* enables the user to re-configure the selected time zones.
*
* - A *long press* on the *light button* activates the LED illumination
* of the watch.
*
*/
#include <stdlib.h>
#include <string.h>
#include "world_clock2_face.h"

View File

@ -26,6 +26,65 @@
#ifndef WORLD_CLOCK2_FACE_H_
#define WORLD_CLOCK2_FACE_H_
/*
* WORLD CLOCK 2
*
* This is an alternative world clock face that allows the user to cycle
* through a list of selected time zones. It extends the original
* implementation by Joey Castillo. The face has two modes: display mode
* and settings mode.
*
* Settings mode
*
* When the clock face is activated for the first time, it enters settings
* mode. Here, the user can select the time zones they want to display. The
* face shows a summary of the current time zone:
* * The top of the face displays the first two letters of the time zone
* abbreviation, such as "PS" for Pacific Standard Time or CE for
* "Central European Time".
* * The upper-right corner shows the index number of the time zone. This
* helps avoid confusion when multiple time zones have the same two-letter
* abbreviation.
* * The main display shows the offset from UTC, with a "+" indicating a
* positive offset and a "-" indicating a negative offset. For example,
* the offset for Japanese Standard Time is displayed as "+9:00".
*
* The user can navigate through the time zones and select them using the
* following buttons:
* * The ALARM button moves forward to the next time zone, while the LIGHT
* button moves backward to the previous zone. This way, the user can
* cycle through all 41 supported time zones.
* * A long press on the LIGHT button selects the current time zone, and
* the signal indicator appears at the top left. Another long press of
* the LIGHT button deselects the time zone.
* * A long press on the ALARM button exits settings mode and returns to
* display mode.
*
* Display mode
*
* In the display mode, the face shows the time of the currently selected
* time zone. The face includes the following components:
* * The top of the face displays the first two letters of the time zone
* abbreviation, such as "PS" for Pacific Standard Time or "CE" for
* Central European Time.
* * The upper-right corner shows the current day of the month, which helps
* indicate time zones that cross the international date line with respect
* to the local time.
* * The main display shows the time in the selected time zone in either
* 12-hour or 24-hour form. There is no timeout, allowing users to keep
* the chosen time zone displayed for as long as they wish.
*
* The user can navigate through the selected time zones using the following
* buttons:
* * The ALARM button moves to the next selected time zone, while the LIGHT
* button moves to the previous zone. If no time zone is selected, the
* face simply shows UTC.
* * A long press on the ALARM button enters settings mode and enables the
* user to re-configure the selected time zones.
* * A long press on the LIGHT button activates the LED illumination of the
* watch.
*/
/* Number of zones. See movement_timezone_offsets. */
#define NUM_TIME_ZONES 41

View File

@ -25,7 +25,29 @@
#ifndef WORLD_CLOCK_FACE_H_
#define WORLD_CLOCK_FACE_H_
/*
* WORLD CLOCK FACE
*
* The World Clock watch face looks similar to the Simple Clock watch face,
* but youll notice that at first launch the day of week indicators are blank.
* Thats because this watch face does not display the day of the week.
* Instead, you may customize these letters to display the name of a time zone
* of your choosing.
*
* To customize this watch face, press and hold the ALARM button. The first
* letter in the top row will begin flashing. Press the ALARM button repeatedly
* to advance through the available letters in the first slot, then press the
* LIGHT button to move to the second letter. Finally, press LIGHT again to move
* to the time zone setting, and press ALARM to cycle through the available time
* zones. Press LIGHT one last time to return to the world clock display.
*
* Note that the second slot cannot display all letters or numbers. Also note
* that at this time, time zones do not automatically update for daylight saving
* time; you will need to manually adjust this field each spring and fall.
*/
#include "movement.h"
typedef union {
struct {
uint8_t char_0;

View File

@ -25,15 +25,32 @@
#ifndef WYOSCAN_FACE_H_
#define WYOSCAN_FACE_H_
#include "movement.h"
/*
* A DESCRIPTION OF YOUR WATCH FACE
* WYOSCAN .5 hz watchface
*
* and a description of how use it
* This is a recreation of the Wyoscan watch, which was a $175 watch in 2014.
* It was an f-91w pcb replacement.
*
* Video: https://user-images.githubusercontent.com/1795778/252550124-e07f0ed1-e328-4337-a654-fa1ee65d883f.mp4
* Background information: https://artmetropole.com/shop/11460
* Demo of what it looks like: https://www.o-r-g.com/apps/wyoscan
*
* 8 frames per number * 6 numbers + the trailing 16 frames = 64 frames
* at 32 frames per second, this is a 2-second cycle time or 0.5 Hz.
*
* It is giving me a stack overflow after about 2.5 cycles of the time display
* in the emulator, but it works fine on the watch.
*
* I'd like to make something for the low energy mode, but I haven't thought
* about how that might work, right now it just freezes in low energy mode
* until you press the 12-24HR button.
*
* There are no controls; it simply animates as long as the page is active.
*
*/
#include "movement.h"
#define MAX_ILLUMINATED_SEGMENTS 16
typedef struct {

View File

@ -25,10 +25,8 @@
#ifndef ACTIVITY_FACE_H_
#define ACTIVITY_FACE_H_
#include "movement.h"
/*
* ACTIVITY WATCH FACE
* ACTIVITY watch face
*
* The Activity face lets you record activities like you would do with a fitness watch.
* It supports different activities like running, biking, rowing etc., and for each recorded activity
@ -69,9 +67,10 @@
*
* See the top of activity_face.c for some customization options. What you most likely want to do
* is reduce the list of activities shown on the first screen to the ones you are regularly doing.
*
*/
#include "movement.h"
void activity_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
void activity_face_activate(movement_settings_t *settings, void *context);
bool activity_face_loop(movement_event_t event, movement_settings_t *settings, void *context);

View File

@ -22,8 +22,6 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
@ -32,31 +30,6 @@
#include "watch_utility.h"
#include "watch_private_display.h"
/*
Implements 16 alarm slots on the sensor watch
Usage:
- In normal mode, the alarm button cycles through all 16 alarms.
- Pressing the alarm button long in normal mode toggles the corresponding alarm on or off.
(Whereas pressing the alarm button extra long brings you back to alarm no. 1.)
- Pressing the light button enters setting mode and cycles through the settings of each alarm.
(Long pressing the light button enters setting mode without illuminating the led.)
- In setting mode an alarm slot is selected by pressing the alarm button when the slot number
in the upper right corner is blinking.
- For each alarm slot, you can select the day. These are the day modes:
- ED = the alarm rings every day
- 1t = the alarm fires only one time and is erased afterwards
- MF = the alarm fires Mondays to Fridays
- WN = the alarm fires on weekends (Sa/Su)
- MO to SU = the alarm fires only on the given day of week
- You can fast cycle through hour or minute setting via long press of the alarm button.
- You can select the tone in which the alarm is played. (Three pitch levels available.)
- You can select how many "beep rounds" are played for each alarm. 1 to 9 rounds, plus extra
long ('L') and extra short ('o') alarms.
- The simple watch face indicates if any alarm is set within the next 24h by showing the signal
indicator.
*/
typedef enum {
alarm_setting_idx_alarm,
alarm_setting_idx_day,

View File

@ -27,11 +27,34 @@
#ifndef ALARM_FACE_H_
#define ALARM_FACE_H_
#include "movement.h"
/*
A face for setting various alarms
*/
* ALARM face
*
* Implements up to 16 alarm slots on the sensor watch
*
* Usage:
* - In normal mode, the alarm button cycles through all 16 alarms.
* - Pressing the alarm button long in normal mode toggles the corresponding alarm on or off.
* (Whereas pressing the alarm button extra long brings you back to alarm no. 1.)
* - Pressing the light button enters setting mode and cycles through the settings of each alarm.
* (Long pressing the light button enters setting mode without illuminating the led.)
* - In setting mode an alarm slot is selected by pressing the alarm button when the slot number
* in the upper right corner is blinking.
* - For each alarm slot, you can select the day. These are the day modes:
* - ED = the alarm rings every day
* - 1t = the alarm fires only one time and is erased afterwards
* - MF = the alarm fires Mondays to Fridays
* - WN = the alarm fires on weekends (Sa/Su)
* - MO to SU = the alarm fires only on the given day of week
* - You can fast cycle through hour or minute setting via long press of the alarm button.
* - You can select the tone in which the alarm is played. (Three pitch levels available.)
* - You can select how many "beep rounds" are played for each alarm. 1 to 9 rounds, plus extra
* long ('L') and extra short ('o') alarms.
* - The simple watch face indicates if any alarm is set within the next 24h by showing the signal
* indicator.
*/
#include "movement.h"
#define ALARM_ALARMS 16 // no of available alarm slots (be aware: only 4 bits reserved for this value in struct below)
#define ALARM_DAY_STATES 11 // no of different day settings

View File

@ -25,6 +25,47 @@
#ifndef ASTRONOMY_FACE_H_
#define ASTRONOMY_FACE_H_
/*
* ASTRONOMY face
*
* The Astronomy watch face is among the most complex watch faces in the
* Movement collection. It allows you to calculate the locations of celestial
* bodies in the sky, as well as distance in astronomical units (or, in the
* case of the Moon, distance in kilometers).
*
* When you arrive at the Astronomy watch face, youll see its name (Astro)
* and an animation of two objects orbiting each other. You will also see SO
* (for Sol) flashing in the top left. The flashing letters indicate the
* currently selected celestial body. Short press Alarm to advance through
* the available celestial bodies:
*
* SO - Sol, the sun
* ME - Mercury
* VE - Venus
* LU - Luna, the Earths moon
* MA - Mars
* JU - Jupiter
* SA - Saturn
* UR - Uranus
* NE - Neptune
*
* Once youve selected the celestial body whose parameters you wish to
* calculate, long press the Alarm button and release it. The letter C will
* flash while the calculation is performed.
*
* When the calculation is complete, the screen will display the altitude
* (aL) of the celestial body. You can cycle through the available parameters
* with repeated short presses on the Alarm button:
*
* aL - Altitude (in degrees), the elevation over the horizon. If negative, it is below the horizon.
* aZ - Azimuth (in degrees), the cardinal direction relative to true north.
* rA - Right Ascension (in hours/minutes/seconds)
* dE - Declination (in degrees/minutes/seconds)
* di - Distance (the digits in the top right will display either aU for astronomical units, or K for kilometers)
*
* Long press on the Alarm button to select another celestial body.
*/
#include "movement.h"
#include "astrolib.h"

View File

@ -25,6 +25,32 @@
#ifndef BLINKY_FACE_H_
#define BLINKY_FACE_H_
/*
* BLINKY LIGHT face
*
* The blinky light watch face was designed as a tutorial for making a watch
* face in Movement, but it actually might be useful to have a blinking light
* in a pinch.
*
* The screen displays the name of the watch face (BL), as well as an S at
* the top right for slow blink or an F for fast blink. The bottom line selects
* the color: green, red or yellow. You can change the speed of the blinking
* light by pressing the Alarm button, and change the color with the Light
* button. A long press on the Alarm button starts the blinking light, and
* another long press stops it.
*
* Note that this will chew through your battery! The green LED uses about
* 450µA at full brightness, which is 45 times the normal power consumption of
* the watch. The red LED is an order of magnitude less efficient (4500 µA),
* and the yellow setting lights both LEDs, which chews through nearly
* 5 milliamperes. This means that one hour of yellow blinking is likely to
* eat up between 2 and 3 percent of the batterys usable life!
*
* Still, if you need to signal your location to someone in a dark forest,
* this watch face could come in handy. Just try to use the green LED as much
* as you can.
*/
#include "movement.h"
typedef struct {

View File

@ -25,6 +25,17 @@
#ifndef BREATHING_FACE_H_
#define BREATHING_FACE_H_
/*
* BOXED BREATHING face
*
* Breathing is a complication for guiding boxed breathing sessions.
* Boxed breathing is a technique to help you stay calm and improve
* concentration in stressful situations.
*
* Usage: Timed messages will cycle as long as this face is active.
* Press ALARM to toggle sound.
*/
#include "movement.h"
void breathing_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -23,27 +23,12 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
#include "countdown_face.h"
#include "watch.h"
#include "watch_utility.h"
/*
Slight extension of the original countdown face by Wesley Ellis.
- Press the light button to enter setting mode and adjust the
countdown timer.
- Start and pause the countdown using the alarm button, similar to the
stopwatch face.
- When paused or terminated, press the light button to restore the
last entered countdown.
*/
#define CD_SELECTIONS 3
#define DEFAULT_MINUTES 3

View File

@ -22,22 +22,27 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#ifndef COUNTDOWN_FACE_H_
#define COUNTDOWN_FACE_H_
#include "movement.h"
/*
A countdown/timer face
Max countdown is 23 hours, 59 minutes and 59 seconds.
Note: we have to prevent the watch from going to deep sleep using
movement_schedule_background_task() while the timer is running.
*/
* COUNTDOWN TIMER face
*
* Slight extension of the original countdown face by Wesley Ellis.
* - Press the light button to enter setting mode and adjust the
* countdown timer.
* - Start and pause the countdown using the alarm button, similar
* to the stopwatch face.
* - When paused or terminated, press the light button to restore the
* last entered countdown.
*
* Max countdown is 23 hours, 59 minutes and 59 seconds.
*
* Note: we have to prevent the watch from going to deep sleep using
* movement_schedule_background_task() while the timer is running.
*/
#include "movement.h"
typedef enum {
cd_paused,

View File

@ -25,9 +25,19 @@
#ifndef COUNTER_FACE_H_
#define COUNTER_FACE_H_
/*
* COUNTER face
*
* Counter face is designed to count the number of running laps during exercises.
*
* Usage:
* Short-press ALARM to increment the counter (loops at 99)
* Long-press ALARM to reset the counter.
* Long-press LIGHT to toggle sound.
*/
#include "movement.h"
// Counter face is designed to count the number of running laps during excercises.
typedef struct {
uint8_t counter_idx;
bool beep_on;

View File

@ -20,8 +20,6 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Displays some pre-defined data that you might want to remember. Math constants, birthdays, phone numbers...
*/
#include <stdlib.h>
@ -96,12 +94,8 @@ bool databank_face_loop(movement_event_t event, movement_settings_t *settings, v
case EVENT_ACTIVATE:
display();
case EVENT_TICK:
// on activate and tick, if we are animating,
break;
case EVENT_LIGHT_BUTTON_UP:
// when the user presses 'light', we illuminate the LED. We could override this if
// our UI needed an additional button for input, consuming the light button press
// but not illuminating the LED.
databank_state.current_word = (databank_state.current_word + max_words - 1) % max_words;
display();
break;
@ -116,8 +110,6 @@ bool databank_face_loop(movement_event_t event, movement_settings_t *settings, v
display();
break;
case EVENT_ALARM_BUTTON_UP:
// when the user presses 'alarm', we toggle the state of the animation. If animating,
// we stop; if stopped, we resume.
databank_state.current_word = (databank_state.current_word + 1) % max_words;
display();
break;

View File

@ -25,6 +25,23 @@
#ifndef DATABANK_FACE_H_
#define DATABANK_FACE_H_
/*
* DATABANK face
*
* Displays some pre-defined data that you might want to remember
* Math constants, birthdays, phone numbers...
*
* Usage: Edit the global variable `pi_data` in "databank_face.c"
* to the define the data that will be displayed. Each "item" contains
* a two-letter label (using the day-of-week display), then a longer
* string that will be displayed one "word" (six characters) at a time.
*
* Short-press ALARM to display the next word.
* Short-press LIGHT to display the previous word.
* Long-press ALARM to display the next item.
* Long-press LIGHT to display the previous item.
*/
#include "movement.h"
void databank_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -25,10 +25,29 @@
#ifndef DAY_ONE_FACE_H_
#define DAY_ONE_FACE_H_
#include "movement.h"
/*
* DAY ONE face
*
* This watch face displays the number of days since a given date.
* It was originally designed to display the number of days youve been alive,
* but technically it can count up from any date in the 20th century or the
* 21st century, so far.
*
* Long press on the Alarm button to enter customization mode. The text YR
* will appear, and will allow you to set the year starting from 1959. Press
* Alarm repeatedly to advance the year. If your birthday is before 1959,
* advance beyond the current year and it will wrap around to 1900.
*
* Once you have set the year, press Light to set the month (MO) and
* day (DA), advancing the value by pressing Alarm repeatedly.
*
* Note that at this time, the Day One face does not display the sleep
* indicator in sleep mode, which may make the watch appear to be
* unresponsive in sleep mode. You can still press the Alarm button to
* wake the watch. This UI quirk will be addressed in a future update.
*/
// The Day One face is designed to count upwards from the wearer's date of birth. It also functions as an
// interface for setting the birth date register, which other watch faces can use for various purposes.
#include "movement.h"
typedef struct {
uint8_t current_page;

View File

@ -1,7 +1,7 @@
#include <stdlib.h>
#include <string.h>
#include "discgolf_face.h"
#include "watch.h" // Remember to change number of courses in this file
#include "watch.h" // Remember to change number of courses in this file
#include "watch_utility.h"
/*

View File

@ -22,9 +22,12 @@
* SOFTWARE.
*/
/////////////////////////////////////////////////////////////////////////////////////
#ifndef DISCGOLF_FACE_H_
#define DISCGOLF_FACE_H_
/*
* DISC GOLF face
*
* Keep track of scores in discgolf or golf!
* The watch face operates in three different modes:
*
@ -58,10 +61,6 @@
* lowest score for that course, and saved if it is better.
*/
#ifndef DISCGOLF_FACE_H_
#define DISCGOLF_FACE_H_
#include "movement.h"
#define courses 11

View File

@ -26,16 +26,6 @@
#ifndef DUAL_TIMER_FACE_H_
#define DUAL_TIMER_FACE_H_
#include "movement.h"
/*
* IMPORTANT: This watch face uses the same TC2 callback counter as the Stock Stopwatch
* watch-face. It works through calling a global handler function. The two watch-faces
* therefore can't coexist within the same firmware. If you want to compile this watch-face
* then you need to remove the line <../watch_faces/complication/stock_stopwatch_face.c \>
* from the Makefile.
*/
/*
* DUAL TIMER
* ==========
@ -70,8 +60,15 @@
* the timers. In this case LONG PRESSING MODE will move to the next face instead of moving
* back to the default watch face.
*
* IMPORTANT: This watch face uses the same TC2 callback counter as the Stock Stopwatch
* watch-face. It works through calling a global handler function. The two watch-faces
* therefore can't coexist within the same firmware. If you want to compile this watch-face
* then you need to remove the line <../watch_faces/complication/stock_stopwatch_face.c \>
* from the Makefile.
*/
#include "movement.h"
typedef struct {
uint8_t centiseconds : 7; // 0-59
uint8_t seconds : 6; // 0-59

View File

@ -25,9 +25,9 @@
#ifndef FLASHLIGHT_FACE_H_
#define FLASHLIGHT_FACE_H_
#include "movement.h"
/*
* FLASHLIGHT face
*
* A flashlight for use with the Flashlight sensor board.
*
* When the watch face appears, the display will show "FL" in the top two positions.
@ -35,6 +35,8 @@
*
*/
#include "movement.h"
typedef struct {
// Anything you need to keep track of, put it here!
uint8_t unused;

View File

@ -25,10 +25,8 @@
#ifndef GEOMANCY_FACE_H_
#define GEOMANCY_FACE_H_
#include "movement.h"
/*
* GEOMANCY WATCH FACE
* GEOMANCY watch face
*
* A simple and straightforward watch face for the ancient Eastern geomantic divination system
* of I Ching and the western system of "Geomancy". It is an optional addition to the Toss Up
@ -65,6 +63,8 @@
*
*/
#include "movement.h"
typedef struct {
uint8_t bits : 4;
} nibble_t;

View File

@ -25,8 +25,6 @@
#ifndef HABIT_FACE_H_
#define HABIT_FACE_H_
#include "movement.h"
/*
* Habit tracking face
*
@ -36,6 +34,8 @@
*
*/
#include "movement.h"
void habit_face_setup(movement_settings_t *settings, uint8_t watch_face_index,
void **context_ptr);
void habit_face_activate(movement_settings_t *settings, void *context);

View File

@ -22,8 +22,6 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
@ -33,57 +31,6 @@
#include "watch_private_display.h"
#include "watch_buzzer.h"
/*
This face brings 9 customizable interval timers to the sensor watch,
to be used as hiit training device and/or for time management techniques.
- There are 9 interval timer slots, you can cycle through these with the
alarm button (short press). For each timer slot, a short "slideshow"
displaying the relevant details (like length of each phase - see below)
is shown.
- To start an interval timer, press and hold the alarm button.
- To pause a running timer, press the alarm button (short press).
- To completely abort a running timer, press and hold the alarm button.
- Press and hold the light button to enter settings mode for each interval
timer slot.
- Each interval timer has 1 to 4 phases of customizable length like so:
(1) prepare/warum up --> (2) work --> (3) break --> (4) cool down.
When setting up or running a timer, each of these phases is displayed by
the letters "PR" (prepare), "WO" (work), "BR" (break), "CD" (cool down).
- Each of these phases is optional, you can set the corresponding
minutes and seconds to zero. But at least one phase needs to be set, if
you want to use the timer.
- You can define the number of rounds either only for the work
phase and/or for the combination of work + break phase. Let's say you
want an interval timer that counts 3 rounds of 30 seconds work,
followed by 20 seconds rest:
work 30s --> work 30s --> work 30s --> break 20s
You can do this by setting 30s for the "WO"rk phase and setting a 3
in the lower right hand corner of the work page. The "LAP" indicator
lights up at this position, to explain that we are setting laps here.
After that, set the "BR"eak phase to 20s and leave the rest as it is.
- If you want to set up a certain number of "full rounds", consisting
of work phase(s) plus breaks, you can do so at the "BR"eak page. The
number in the lower right hand corner determines the number of full
rounds to be counted. A "-" means, that there is no limit and the
timer keeps alternating between work and break phases.
- This watch face comes with several pre-defined interval timers,
suitable for hiit training (timer slots 1 to 4) as well as doing
work according to the pomodoro principle (timer slots 5 to 6).
Feel free to adjust the timer slots to your own needs (or completely
wipe them ;-)
*/
typedef enum {
interval_setting_0_timer_idx,
interval_setting_1_clear_yn,

View File

@ -22,16 +22,62 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#ifndef INTERVAL_FACE_H_
#define INTERVAL_FACE_H_
#include "movement.h"
/*
A face for customizable interval timers
*/
* INTERVAL TIMER face
*
* This face brings 9 customizable interval timers to the sensor watch,
* to be used as hiit training device and/or for time management techniques.
*
* - There are 9 interval timer slots, you can cycle through these with the
* alarm button (short press). For each timer slot, a short "slideshow"
* displaying the relevant details (like length of each phase - see below)
* is shown.
*
* - To start an interval timer, press and hold the alarm button.
*
* - To pause a running timer, press the alarm button (short press).
*
* - To completely abort a running timer, press and hold the alarm button.
*
* - Press and hold the light button to enter settings mode for each interval
* timer slot.
*
* - Each interval timer has 1 to 4 phases of customizable length like so:
* (1) prepare/warum up --> (2) work --> (3) break --> (4) cool down.
* When setting up or running a timer, each of these phases is displayed by
* the letters "PR" (prepare), "WO" (work), "BR" (break), "CD" (cool down).
*
* - Each of these phases is optional, you can set the corresponding
* minutes and seconds to zero. But at least one phase needs to be set, if
* you want to use the timer.
*
* - You can define the number of rounds either only for the work
* phase and/or for the combination of work + break phase. Let's say you
* want an interval timer that counts 3 rounds of 30 seconds work,
* followed by 20 seconds rest:
* work 30s --> work 30s --> work 30s --> break 20s
* You can do this by setting 30s for the "WO"rk phase and setting a 3
* in the lower right hand corner of the work page. The "LAP" indicator
* lights up at this position, to explain that we are setting laps here.
* After that, set the "BR"eak phase to 20s and leave the rest as it is.
*
* - If you want to set up a certain number of "full rounds", consisting
* of work phase(s) plus breaks, you can do so at the "BR"eak page. The
* number in the lower right hand corner determines the number of full
* rounds to be counted. A "-" means, that there is no limit and the
* timer keeps alternating between work and break phases.
*
* - This watch face comes with several pre-defined interval timers,
* suitable for hiit training (timer slots 1 to 4) as well as doing
* work according to the pomodoro principle (timer slots 5 to 6).
* Feel free to adjust the timer slots to your own needs (or completely
* wipe them ;-)
*/
#include "movement.h"
#define INTERVAL_TIMERS 9 // no of available customizable timers (be aware: only 4 bits reserved for this value in struct below)

View File

@ -25,8 +25,6 @@
#ifndef INVADERS_FACE_H_
#define INVADERS_FACE_H_
#include "movement.h"
/*
* Remake of the "famous" Casio Number Invaders Game
*
@ -60,6 +58,8 @@
*
*/
#include "movement.h"
typedef struct {
uint16_t highscore;
bool sound_on;

View File

@ -25,6 +25,30 @@
#ifndef MOON_PHASE_FACE_H_
#define MOON_PHASE_FACE_H_
/*
* MOON PHASE face
*
* The Moon Phase face is similar to the Sunrise/Sunset face: it displays the
* current phase of the moon, along with the day of the month and a graphical
* representation of the moon on the top row.
*
* This graphical representation is a bit abstract. The segments that turn on
* represent the shape of the moon, waxing from the bottom right and waning at
* the top left. A small crescent at the bottom right will grow into a larger
* crescent, then add lines in the center for a quarter and half moon. All
* segments are on during a full moon. Then gradually the segments at the
* bottom right will turn off, until all that remains is a small waning
* crescent at the top left.
*
* All segments turn off during a new moon.
*
* On this screen you may press the Alarm button repeatedly to move forward
* in time: the day of the month at the top right will advance by one day for
* each button press, and both the text and the graphical representation will
* display the moon phase for that day. Try pressing the Alarm button 27 times
* now, just to visualize what the moon will look like over the next month.
*/
#include "movement.h"
typedef struct {

View File

@ -22,89 +22,6 @@
* SOFTWARE.
*/
/*
## Morse-code-based RPN calculator
The calculator is operated by first composing a **token** in Morse code, then submitting it to the calculator. A token specifies either a calculator operation or a float value.
These two parts of the codebase are totally independent:
1. The Morse-code reader (`mc.h`, `mc.c`)
2. The RPN calculator (`calc.h`, `calc.c`, `calc_fn.h`, `calc_fn.c`, `small_strtod.c`)
The user interface (`morsecalc_face.h`, `morsecalc_face.c`) lets you talk to the RPN calculator through Morse code.
## Controls
- `light` is dash
- `alarm` is dot
- `mode` is "finish character"
- long-press `mode` or submit a blank token to switch faces
- long-press `alarm` to show stack
- long-press `light` to toggle the light
## Morse code token entry
As you enter `.`s and `-`s, the morse code char you've entered will appear in the top center digit.
At the top right is the # of morse code `.`/`-` you've input so far. The character resets at the 6th `.`/`-`.
Once you have the character you want to enter, push `mode` to enter it.
The character will be appended to the current token, whose 6 trailing chars are shown on the main display.
Once you've typed in the token you want, enter a blank Morse code character and then push `mode`.
This submits it to the calculator.
Special characters:
- Backspace is `(` (`-.--.`).
- Clear token input without submitting to calculator is `Start transmission` (`-.-.-`).
## Writing commands
First the calculator will try to interpret the token as a command/stack operation.
Commands are defined in `calc_dict[]` in `movement/lib/morsecalc/calc_fns.h`.
If the command doesn't appear in the dictionary, the calculator tries to interpret the token as a number.
## Writing numbers
Numbers are written like floating point strings.
Entering a number pushes it to the top of the stack if there's room.
This can get long, so for convenience numerals can also be written in binary with .- = 01.
0 1 2 3 4 5 6 7 8 9
. - -. -- -.. -.- --. --- -... -..-
e t n m d k g o b x
- Exponent signs must be entered as "p".
- Decimal place "." can be entered as "h" (code ....)
- Sign "-" can be entered as "Ch digraph" (code ----)
For example: "4.2e-3" can be entered directly, or as "4h2pC3"
similarly, "0.0042" can also be entered as "eheedn"
Once you submit a number to the watch face, it pushes it to the top of the stack if there's room.
## Number display
After a command runs, the top of the stack is displayed in this format:
- Main 4 digits = leading 4 digits
- Last 2 digits = exponent
- Top middle = [Stack location, Sign of number]
- Top right = [Stack exponent, Sign of exponent]
Blank sign digit means positive.
So for example, the watch face might look like this:
[ 0 -5]
[4200 03]
... representing `+4.200e-3` is in stack location 0 (the top) and it's one of five items in the stack.
## Looking at the stack
To show the top of the stack, push and hold `light`/`alarm` or submit a blank token by pushing `mode` a bunch of times.
To show the N-th stack item (0 through 9):
- Put in the Morse code for N without pushing the mode button.
- Push and hold `alarm`.
To show the memory register, use `m` instead of a number.
To see all the calculator operations and their token aliases, see the `calc_dict[]` struct in `calc_fns.h`
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>

View File

@ -25,6 +25,96 @@
#ifndef MORSECALC_FACE_H_
#define MORSECALC_FACE_H_
/*
* MORSECALC face
* Morse-code-based RPN calculator
*
* The calculator is operated by first composing a **token** in Morse code,
* then submitting it to the calculator. A token specifies either a calculator
* operation or a float value.
*
* These two parts of the codebase are totally independent:
* 1. The Morse-code reader (`mc.h`, `mc.c`)
* 2. The RPN calculator (`calc.h`, `calc.c`, `calc_fn.h`, `calc_fn.c`, `small_strtod.c`)
*
* The user interface (`morsecalc_face.h`, `morsecalc_face.c`) lets you talk
* to the RPN calculator through Morse code.
*
* ## Controls
* - `light` is dash
* - `alarm` is dot
* - `mode` is "finish character"
* - long-press `mode` or submit a blank token to switch faces
* - long-press `alarm` to show stack
* - long-press `light` to toggle the light
*
* ## Morse code token entry
* As you enter `.`s and `-`s, the morse code char you've entered will
* appear in the top center digit. At the top right is the # of morse code
* `.`/`-` you've input so far. The character resets at the 6th `.`/`-`.
*
* Once you have the character you want to enter, push `mode` to enter it.
*
* The character will be appended to the current token, whose 6 trailing
* chars are shown on the main display. Once you've typed in the token you
* want, enter a blank Morse code character and then push `mode`.
* This submits it to the calculator.
*
* Special characters:
* - Backspace is `(` (`-.--.`).
* - Clear token input without submitting to calculator is `Start
* transmission` (`-.-.-`).
*
* ## Writing commands
* First the calculator will try to interpret the token as a command/stack operation.
* Commands are defined in `calc_dict[]` in `movement/lib/morsecalc/calc_fns.h`.
* If the command doesn't appear in the dictionary, the calculator tries to interpret the token as a number.
*
* ## Writing numbers
* Numbers are written like floating point strings.
* Entering a number pushes it to the top of the stack if there's room.
* This can get long, so for convenience numerals can also be written in binary with .- = 01.
*
* 0 1 2 3 4 5 6 7 8 9
* . - -. -- -.. -.- --. --- -... -..-
* e t n m d k g o b x
*
* - Exponent signs must be entered as "p".
* - Decimal place "." can be entered as "h" (code ....)
* - Sign "-" can be entered as "Ch digraph" (code ----)
*
* For example: "4.2e-3" can be entered directly, or as "4h2pC3"
* similarly, "0.0042" can also be entered as "eheedn"
* Once you submit a number to the watch face, it pushes it to the top of the stack if there's room.
*
* ## Number display
* After a command runs, the top of the stack is displayed in this format:
*
* - Main 4 digits = leading 4 digits
* - Last 2 digits = exponent
* - Top middle = [Stack location, Sign of number]
* - Top right = [Stack exponent, Sign of exponent]
*
* Blank sign digit means positive.
* So for example, the watch face might look like this:
*
* [ 0 -5]
* [4200 03]
*
* ... representing `+4.200e-3` is in stack location 0 (the top) and it's one of five items in the stack.
*
* ## Looking at the stack
* To show the top of the stack, push and hold `light`/`alarm` or submit a blank token by pushing `mode` a bunch of times.
* To show the N-th stack item (0 through 9):
*
* - Put in the Morse code for N without pushing the mode button.
* - Push and hold `alarm`.
*
* To show the memory register, use `m` instead of a number.
*
* To see all the calculator operations and their token aliases, see the `calc_dict[]` struct in `calc_fns.h`
*/
#define MORSECALC_TOKEN_LEN 32
#define MORSECODE_LEN 5

View File

@ -20,7 +20,6 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include <stdlib.h>

View File

@ -25,6 +25,48 @@
#ifndef ORRERY_FACE_H_
#define ORRERY_FACE_H_
/*
* ORRERY face
*
* The Orrery watch face is similar to the Astronomy watch face in that it
* calculates properties of the planets, but instead of calculating their
* positions in the sky, this watch face calculates their absolute locations
* in the solar system. This is only useful if you want to plot the planets
* on graph paper, but hey, you never know!
*
* The controls are identical to the Astronomy watch face: while the title
* screen (Orrery) is displayed, you can advance through the available
* planets with repeated short presses on the Alarm button. The available
* planets:
*
* ME - Mercury
* VE - Venus
* EA - Earth
* LU - Luna, the Earths moon
* MA - Mars
* JU - Jupiter
* SA - Saturn
* UR - Uranus
* NE - Neptune
*
* Note that the sun is not available in this menu, as the sun is always at
* (0,0,0) in this calculation.
*
* Long press on the Alarm button to calculate the planets location, and
* after a flashing C (for Calculating), you will be presented with the
* planets X coordinate in astronomical units. Short press Alarm to cycle
* through the X, Y and Z coordinates, and then long press Alarm to return
* to planet selection.
*
* The large numbers represent the whole number part, and the two smaller
* numbers (in the seconds place) represent the decimal portion. So if you
* see SA X 736 and SA Y -662, you can read that as an X coordinate of
* 7.36 AU and a Y coordinate of -6.62 AU. You can literally draw a dot at
* (0, 0) to represent the sun, and a dot at (7.36, -6.62) to represent
* Saturn. (The Z coordinates tend to be pretty close to zero, as the
* planets largely orbit on a single plane, the ecliptic.)
*/
#include "movement.h"
typedef enum {

View File

@ -26,12 +26,11 @@
#ifndef planetary_hours_face_H_
#define planetary_hours_face_H_
#include "movement.h"
#include "sunrise_sunset_face.h"
/*
* BACKGROUND
* PLANETARY HOURS face
*
* Background
*
* Both the 24 hour day and the order of our weekdays have quite esoteric roots.
* The ancient Egyptians divided the day up into 12 hours of sunlight and 12 hours
* of night time. Obviously the length of these hours varied throughout the year.
@ -74,6 +73,9 @@
* watch face to work properly!)
*/
#include "movement.h"
#include "sunrise_sunset_face.h"
typedef struct {
// Anything you need to keep track of, put it here!
uint32_t planetary_hours[24];

View File

@ -26,12 +26,11 @@
#ifndef planetary_time_face_H_
#define planetary_time_face_H_
#include "movement.h"
#include "sunrise_sunset_face.h"
/*
* PLANETARY TIME face
*
* BACKGROUND
*
* Both the 24 hour day and the order of our weekdays have quite esoteric roots.
* The ancient Egyptians divided the day up into 12 hours of sunlight and 12 hours
* of night time. Obviously the length of these hours varied throughout the year.
@ -77,6 +76,9 @@
* watch face to work properly!)
*/
#include "movement.h"
#include "sunrise_sunset_face.h"
typedef struct {
// Anything you need to keep track of, put it here!
uint32_t phase_start;

View File

@ -25,6 +25,18 @@
#ifndef PROBABILITY_FACE_H_
#define PROBABILITY_FACE_H_
/*
* PROBABILITY face
*
* This face is a dice-rolling random number generator.
* Supports dice with 2, 4, 6, 8, 10, 12, 20, or 100 sides.
*
* Press LIGHT to cycle through die type.
* The current die size is indicated on the left ("C" for 100)
*
* Press ALARM to roll the selected die.
*/
#include "movement.h"
typedef struct {

View File

@ -25,6 +25,33 @@
#ifndef PULSOMETER_FACE_H_
#define PULSOMETER_FACE_H_
/*
* PULSOMETER face
*
* The Pulsometer is an implementation of a sort of a classic mechanical
* watch complication. A classic pulsometer complication involves a
* chronograph with a scale calibrated for counting a certain number of
* heartbeats (often 30). You start it and begin counting heartbeats, and
* stop it after counting the specified number of beats. Once stopped,
* the needle will point to your heart rate.
*
* The pulsometer on Sensor Watch flashes its instructions at launch:
* Hold Alarm + count 30 beats. Using the hand on the side where you wear
* your watch, touch your carotid artery (in your neck) and feel for your
* pulse. Once you find it, use your other hand to press and hold the Alarm
* button, and count your heartbeats. When you reach 30 beats, release the
* Alarm button. The display will show a number such as 60 bpm; this is
* your heart rate in beats per minute.
*
* Two notes:
* o For the first few seconds of a measurement, the display will read Hi.
* This indicates that its too early for the measured value to be a valid
* heart rate. Once the measurement is below 240 bpm, the display will update.
* o If you hold the button down for more than 45 seconds, the display will
* read Lo. If it took this long for you to count 30 heartbeats, this
* indicates that your heart rate is below 40 beats per minute.
*/
#include "movement.h"
typedef struct {

View File

@ -25,11 +25,8 @@
#ifndef RANDONAUT_FACE_H_
#define RANDONAUT_FACE_H_
#include "movement.h"
#include "place_face.h"
/*
* RANDONAUT FACE
* RANDONAUT face
* ==============
*
* Randonauting is a way to turn the world around you into an adventure and get the user outside
@ -71,6 +68,9 @@
*
*/
#include "movement.h"
#include "place_face.h"
typedef struct {
uint8_t mode :3;
uint8_t location_format :3;

View File

@ -25,6 +25,16 @@
#ifndef RATEMETER_FACE_H_
#define RATEMETER_FACE_H_
/*
* RATE METER face
*
* The rate meter shows the rate per minute at which the ALARM button is
* being pressed. This is particularly useful in sports where cadence
* tracking is useful. For instance, rowing coaches often use a dedicated
* rate meter - clicking the rate button each time the crew puts their oars
* in the water to see the rate (strokes per minute) on the rate meter.
*/
#include "movement.h"
typedef struct {

View File

@ -22,39 +22,6 @@
* SOFTWARE.
*/
/* RPN Calculator alternate face.
*
* Operations appear in the 'day' section; ALARM changes between operations when operation is flashing.
* LIGHT executes current operation.
*
* This is the alternate face because it has a non-traditional number entry system which
* I call 'guess a number'. In number entry mode, the watch tries to guess which number you
* want, and you respond with 'smaller' (left - MODE) or larger (right - ALARM). This means
* that when you _are_ entering a number, MODE will no longer move between faces!
*
* Example of entering the number 27
* - select the NO operation (probably unnecessary, as this is the default),
* and execute it by hitting LIGHT.
* - you are now in number entry mode; you know this because nothing is flashing.
* - Watch displays 10; you hit ALARM to say you want a larger number.
* - Watch displays 100; you hit MODE to say you want a smaller number.
* - Continuing: 50 -> MODE -> 30 -> MODE -> 20 -> ALARM -> 27
* - Hit LIGHT to add the number to the stack (and now 'NO' is flashing
* again, indicating you're back in operation selection mode).
*
* One other thing to watch out for is how quickly it will switch into scientific notation
* due to the limitations of the display when you have large numbers or non-integer values.
* In this mode, the 'colon' serves at the decimal point, and the numbers in the top right
* are the exponent.
*
* As with the main movement firmware, this has the concept of 'secondary' functions which
* you can jump to by a long hold of ALARM on NO. These are functions to do with stack
* manipulation (pop, swap, dupe, clear, size (le)). If you're _not_ on NO, a long
* hold will take you back to it.
*
* See 'functions' below for names of all operations.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>

View File

@ -25,6 +25,40 @@
#ifndef CALCULATOR_FACE_H_
#define CALCULATOR_FACE_H_
/*
* RPN Calculator alternate face.
*
* Operations appear in the 'day' section; ALARM changes between operations when
* operation is flashing. LIGHT executes current operation.
*
* This is the alternate face because it has a non-traditional number entry system which
* I call 'guess a number'. In number entry mode, the watch tries to guess which number you
* want, and you respond with 'smaller' (left - MODE) or larger (right - ALARM). This means
* that when you _are_ entering a number, MODE will no longer move between faces!
*
* Example of entering the number 27
* - select the NO operation (probably unnecessary, as this is the default),
* and execute it by hitting LIGHT.
* - you are now in number entry mode; you know this because nothing is flashing.
* - Watch displays 10; you hit ALARM to say you want a larger number.
* - Watch displays 100; you hit MODE to say you want a smaller number.
* - Continuing: 50 -> MODE -> 30 -> MODE -> 20 -> ALARM -> 27
* - Hit LIGHT to add the number to the stack (and now 'NO' is flashing
* again, indicating you're back in operation selection mode).
*
* One other thing to watch out for is how quickly it will switch into scientific notation
* due to the limitations of the display when you have large numbers or non-integer values.
* In this mode, the 'colon' serves at the decimal point, and the numbers in the top right
* are the exponent.
*
* As with the main movement firmware, this has the concept of 'secondary' functions which
* you can jump to by a long hold of ALARM on NO. These are functions to do with stack
* manipulation (pop, swap, dupe, clear, size (le)). If you're _not_ on NO, a long
* hold will take you back to it.
*
* See 'functions' in "rpn_calculator_alt_face.c" for names of all operations.
*/
#include "movement.h"
#define CALC_MAX_STACK_SIZE 20

View File

@ -25,6 +25,15 @@
#ifndef RPN_CALCULATOR_FACE_H_
#define RPN_CALCULATOR_FACE_H_
/*
* RPN CALCULATOR face
*
* A calculator face using reverse polish notation (RPN).
*
* For usage instructions, please refer to the wiki:
* https://www.sensorwatch.net/docs/watchfaces/complication/#rpn-calculator
*/
#include "movement.h"
#define RPN_CALCULATOR_STACK_SIZE 4

View File

@ -24,45 +24,12 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
#include "sailing_face.h"
#include "watch.h"
#include "watch_utility.h"
/*
Implements a sailing timer.
Usage:
Waiting mode: Light button enters settings, alarm button starts the timer (sailing mode).
Sailing mode:
Alarm button switches to next programmed start signal, long press on light button
resets timer and enters waiting mode. Countdown to zero, then switch to counting mode.
Counting mode:
After the start signal (0s), the duration of the race is counted (like a stopwatch timer).
Alarm button increases the lap counter, alarm long press resets lap counter.
Long press on light button resets timer and enters waiting mode.
Setting mode:
Alarm button increases active (blinking) signal. Goes to 0 if upper boundary
(11 or whatever the signal left to the active one is set to) is met.
10 is printed vertically (letter o plus top segment).
Alarm button long press resets to default minutes (5-4-1-0).
Light button cycles through the signals.
Long press on light button cycles through sound modes:
- Bell indicator: Sound at start (0s) only.
- Signal indicator: Sound at each programmed signal and at start.
- Bell+Signal: Sound at each minute, at 30s and at 10s countdown.
- No indicator: No sound.
*/
#define sl_SELECTIONS 6
#define DEFAULT_MINUTES { 5,4,1,0,0,0 }

View File

@ -24,17 +24,43 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#ifndef SAILING_FACE_H_
#define SAILING_FACE_H_
#include "movement.h"
/*
A sailing sailing/timer face
*/
* SAILING face
* Implements a sailing timer.
*
* Usage:
*
* Waiting mode:
* LIGHT button enters settings
* ALARM button starts the timer (sailing mode).
*
* Sailing mode:
* ALARM button switches to next programmed start signal.
* Long press on LIGHT button resets timer and enters waiting mode.
* Countdown to zero, then switch to counting mode.
*
* Counting mode:
* After the start signal (0s), the duration of the race is counted (like a stopwatch timer).
* ALARM button increases the lap counter, ALARM long press resets lap counter.
* Long press on LIGHT button resets timer and enters waiting mode.
*
* Setting mode:
* ALARM button increases active (blinking) signal. Goes to 0 if upper boundary
* (11 or whatever the signal left to the active one is set to) is met.
* 10 is printed vertically (letter o plus top segment).
* ALARM button long press resets to default minutes (5-4-1-0).
* LIGHT button cycles through the signals.
* Long press on LIGHT button cycles through sound modes:
* - Bell indicator: Sound at start (0s) only.
* - Signal indicator: Sound at each programmed signal and at start.
* - Bell+Signal: Sound at each minute, at 30s and at 10s countdown.
* - No indicator: No sound.
*/
#include "movement.h"
typedef enum {
sl_waiting,

View File

@ -25,9 +25,8 @@
#ifndef SHIPS_BELL_FACE_H_
#define SHIPS_BELL_FACE_H_
#include "movement.h"
/*
* SHIP'S BELL face
* A ship's bell complication.
*
* See: https://en.wikipedia.org/wiki/Ship%27s_bell#Simpler_system
@ -45,6 +44,8 @@
* - long press Alarm button: Cycle through the watches (All/1/2/3)
*/
#include "movement.h"
typedef struct {
bool bell_enabled;
uint8_t on_watch;

View File

@ -25,12 +25,34 @@
#ifndef STOCK_STOPWATCH_FACE_H_
#define STOCK_STOPWATCH_FACE_H_
#include "movement.h"
/*
* STOCK STOPWATCH face
*
* The Stock Stopwatch face implements the original F-91W stopwatch
* functionality, including counting hundredths of seconds and lap timing.
*
* Use the ALARM button to start and stop the stopwatch.
* Press the LIGHT button while the stopwatch is running to view the lap time.
* (The stopwatch continues running in the background, indicated by a blinking colon.)
* Press the LIGHT button again to switch back to the running stopwatch.
* Press the LIGHT button when the timekeeping is stopped to reset the stopwatch.
*
* There are two improvements compared to the original F-91W:
* o When the stopwatch reaches 59:59, the counter does not simply jump back
* to zero but keeps track of hours in the upper right-hand corner
* (up to 24 hours).
* o Long-press the light button to toggle the LED behavior.
* It either turns on with each button press or remains off.
*
* NOTE:
* This watch face relies heavily on static vars in stock_stopwatch.c.
* The disadvantage is that you cannot use more than one instance of this
* watch face on your custom firmware - but then again, who would want that?
* The advantage is that accessing vars is more direct and faster, and we
* can save some precious cpu cycles. :-)
*/
// This watch face relies heavily on static vars in stock_stopwatch.c.
// The disadvantage is that you cannot use more than one instance of this watch face on
// your custom firmware - but then again, who would want that? The advantage is that accessing
// vars is more direct and faster, and we can save some precious cpu cycles :-)
#include "movement.h"
typedef struct {
bool light_on_button; // determines whether the light button actually triggers the led

View File

@ -26,6 +26,17 @@
#ifndef STOPWATCH_FACE_H_
#define STOPWATCH_FACE_H_
/*
* STOPWATCH FACE
*
* The Stopwatch face provides basic stopwatch functionality: you can start
* and stop the stopwatch with the alarm button. Pressing the light button
* when the timer is stopped resets it.
*
* This face does not count sub-seconds.
* See also: "stock_stopwatch_face.h"
*/
#include "movement.h"
typedef struct {

View File

@ -25,10 +25,18 @@
#ifndef SUNRISE_SUNSET_FACE_H_
#define SUNRISE_SUNSET_FACE_H_
#include "movement.h"
/*
* SUNRISE & SUNSET FACE
*
* The Sunrise/Sunset face is designed to display the next sunrise or sunset
* for a given location. It also functions as an interface for setting the
* location register, which other watch faces can use for various purposes.
*
* Refer to the wiki for usage instructions:
* https://www.sensorwatch.net/docs/watchfaces/complication/#sunrisesunset
*/
// The Sunrise/Sunset face is designed to display the next sunrise or sunset for a given location.
// TODO: It also functions as an interface for setting the location register, which other watch faces can use for various purposes.
#include "movement.h"
typedef struct {
uint8_t sign: 1; // 0-1

View File

@ -25,6 +25,49 @@
#ifndef TACHYMETER_FACE_H_
#define TACHYMETER_FACE_H_
/*
* TACHYMETER face
*
* The Tachymeter complication emulates the tachymeter function often
* present in watches, that computes the average speed in [units per hour]
* for a given distance given in [units].
*
* Use case:
* User sets the distance
* User starts the tachymeter when the trip begins
* User stops the tachymeter when the trip ends
* The watch presents the average speed and trip duration in seconds
*
* Usage:
* Go to tachymeter face, TC is shown in the Weekday Digits
* A steady d in the Day Digits indicates the distance to be used.
* To edit the distance:
* Long-press the Alarm button, the distance edition page (d will blink)
* Use the Light button to change the editing (blinking) digit, and press Alarm to increase its value
* Once done, long-press the Alarm button to exit the distance edition page
* Press the Alarm button to start the tachymeter.
* A running animation will appear in the Day Digits
* Press the Alarm button to stop the tachymeter
* The average speed and total time information will alternate.
* The average speed will be shown alongside /h in the Day Digits;
* and the total time will be shown alongside t in the Day Digits.
* Long press the Light button to return to the distance d page,
* and restart the tachymeter from there.
* Long-press the light button in the steady distance page to reset
* the distance to 1.00
*
* Pending design points
* o movement_request_tick_frequency(4) is used to obtain a 4Hz ticking, thus
* having a time resolution of 250 ms. Not sure if using event.subsecond`
* is the proper way to get the fractions of second for the start and
* final times.
* o For distance and average speed, the Second Digits (position 8 and 9)
* can be seen as decimals, thus possible to show distances as short as
* 0.01 km (or miles) and speeds as low as 0.01 km/h (or mph). However,
* if the same idea is used for the total time (showing hundredths),
* this limits the display to 9999.99 seconds (~2h:45m).
*/
#include "movement.h"
typedef struct {

View File

@ -25,11 +25,17 @@
#ifndef TALLY_FACE_H_
#define TALLY_FACE_H_
#include "movement.h"
/*
* TALLY face
*
* Tally face is designed to act as a tally counter.
* Based on the counter_face watch face by Shogo Okamoto.
*
* To advance the counter, press the ALARM button.
* To reset, long press the ALARM button.
*/
// Tally face is designed to act as a tally counter.
// Based on the counter_face watch face by Shogo Okamoto.
// To advance the counter, press the Alarm button. To reset, long press the Alarm button.
#include "movement.h"
typedef struct {
uint32_t tally_idx;

View File

@ -25,10 +25,8 @@
#ifndef TAROT_FACE_H_
#define TAROT_FACE_H_
#include "movement.h"
/*
* Tarot card watch face
* TAROT CARD watch face
*
* Draw from a deck of tarot cards. Can choose between major arcana only or
* entire deck.
@ -62,6 +60,8 @@
* - Light button (long press): go back to Draw screen, for choosing different draw parameters.
*/
#include "movement.h"
#define MAX_CARDS_TO_DRAW 10
typedef struct {

View File

@ -20,11 +20,6 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Gathers temperature statistics in a chart form. Statistics bins are per hour / per 0.5°C.
* Saved to file every day at 00:00. Can help improve watch precision in the future.
* If you can gather statistics over few months, and then send tempchart.ini to 3@14.by - it
* will help future generations of precision quartz watches.
*/
#include <stdlib.h>

View File

@ -25,6 +25,19 @@
#ifndef TEMPCHART_FACE_H_
#define TEMPCHART_FACE_H_
/*
* TEMPERATURE CHART face
*
* Gathers temperature statistics in a chart form.
* Statistics bins are per hour / per 0.5°C.
*
* Saved to file every day at 00:00.
* Can help improve watch precision in the future.
*
* If you can gather statistics over few months, and then send "tempchart.ini"
* to "3@14.by", it will help future generations of precision quartz watches.
*/
#include "movement.h"
void tempchart_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -25,9 +25,9 @@
#ifndef TIME_LEFT_FACE_H_
#define TIME_LEFT_FACE_H_
#include "movement.h"
/*
* TIME LEFT face
*
* The Time Left Face helps you to visualize how far you have proceeded in a certain
* time span. Much like the Day One Face, you can set your beginning date. In addition
* to that, you also set your target or destination date. You can then use the face
@ -65,6 +65,8 @@
*
*/
#include "movement.h"
typedef struct {
uint8_t current_page;
uint16_t current_year;

View File

@ -22,8 +22,6 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
#include "timer_face.h"

View File

@ -22,14 +22,11 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#ifndef TIMER_FACE_H_
#define TIMER_FACE_H_
#include "movement.h"
/*
* TIMER face
* Advanced timer/countdown face with pre-set timer lengths
*
* This watch face provides the functionality of starting a countdown by choosing
@ -53,6 +50,8 @@
*
*/
#include "movement.h"
#define TIMER_SLOTS 9 // offer 9 timer slots
typedef enum {

View File

@ -25,6 +25,26 @@
#ifndef TOMATO_FACE_H_
#define TOMATO_FACE_H_
/*
* TOMATO TIMER face
*
* Add a "tomato" timer watch face that alternates between 25 and 5 minute
* timers as in the Pomodoro Technique.
* https://en.wikipedia.org/wiki/Pomodoro_Technique
*
* The top right letter shows mode (f for focus or b for break).
* The bottom right shows how many focus sessions you've completed.
* (You can reset the count with a long press of alarm)
*
* When you show up and it says 25 minutes, you can start it (alarm),
* switch to 5 minute (light) mode or leave (mode).
*
* When it's running you can reset (alarm), or leave (mode).
*
* When it's done, we beep and go back to step 1, changing switching
* mode from focus to break (or break to focus)
*/
#include "movement.h"
typedef enum {

View File

@ -25,10 +25,8 @@
#ifndef TOSS_UP_FACE_H_
#define TOSS_UP_FACE_H_
#include "movement.h"
/*
* TOSS UP FACE
* TOSS UP face
* ============
*
* Playful watch face for games of chance or divination using coins or dice.
@ -75,6 +73,8 @@
*
*/
#include "movement.h"
typedef struct {
// Anything you need to keep track of, put it here!
uint32_t entropy;

View File

@ -1,3 +1,27 @@
/*
* MIT License
*
* Copyright (c) 2022 Wesley Ellis (https://github.com/tahnok)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include "totp_face.h"
@ -5,15 +29,6 @@
#include "watch_utility.h"
#include "TOTP.h"
// Use https://cryptii.com/pipes/base32-to-hex to convert base32 to hex
// Use https://github.com/susam/mintotp to generate test codes for verification
// Available algorothms:
// SHA1 (most TOTP codes use this)
// SHA224
// SHA256
// SHA384
// SHA512
////////////////////////////////////////////////////////////////////////////////
// Enter your TOTP key data below
static const uint8_t num_keys = 2;

View File

@ -1,6 +1,58 @@
/*
* MIT License
*
* Copyright (c) 2022 Wesley Ellis (https://github.com/tahnok)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef TOTP_FACE_H_
#define TOTP_FACE_H_
/*
* TOTP face
* Time-based one-time password (TOTP) generator
*
* Generate one-time passwords often used for two-factor authentication.
* The secret key must be set by hand, by editing "totp_face.c".
*
* Available algorithms:
* o SHA1 (most TOTP codes use this)
* o SHA224
* o SHA256
* o SHA384
* o SHA512
*
* Instructions:
* o Find your secret key(s) and convert them to the required format.
* o Use https://cryptii.com/pipes/base32-to-hex to convert base32 to hex
* o Use https://github.com/susam/mintotp to generate test codes for verification
* o Edit global variables in "totp_face.c" to configure your stored keys:
* o "keys", "key_sizes", "timesteps", and "algorithms" set the
* cryptographic parameters for each secret key.
* o "labels" sets the two-letter label for each key
* (This replaces the day-of-week indicator)
* o Once finished, remove the two provided examples.
*
* If you have more than one secret key, press ALARM to cycle through them.
*/
#include "movement.h"
typedef struct {

View File

@ -1,3 +1,27 @@
/*
* MIT License
*
* Copyright (c) 2022 Wesley Ellis (https://github.com/tahnok)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
@ -11,24 +35,6 @@
#include "totp_face_lfs.h"
/* Reads from a file totp_uris.txt where each line is what's in a QR code:
* e.g.
* otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example
* otpauth://totp/ACME%20Co:john.doe@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30
* This is also the same as what Aegis exports in plain-text format.
*
* Minimal sanitisation of input, however.
*
* At the moment, to get the records onto the filesystem, start a serial connection and do:
* echo otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example > totp_uris.txt
* echo otpauth://totp/ACME%20Co:john.doe@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30 >> totp_uris.txt
* (note the double >> in the second one)
*
* You may want to customise the characters that appear to identify the 2FA code. These are just the first two characters of the issuer,
* and it's fine to modify the URI.
*/
#define MAX_TOTP_RECORDS 20
#define MAX_TOTP_SECRET_SIZE 48
#define TOTP_FILE "totp_uris.txt"

View File

@ -1,6 +1,54 @@
/*
* MIT License
*
* Copyright (c) 2022 Wesley Ellis (https://github.com/tahnok)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef TOTP_FACE_LFS_H_
#define TOTP_FACE_LFS_H_
/*
* TOTP-LFS face
* Time-based one-time password (TOTP) generator using LFS
*
* Reads from a file "totp_uris.txt", containing a single secret key in a
* series of URLs. Each line is what's in a QR code, e.g.:
* otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example
* otpauth://totp/ACME%20Co:john.doe@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30
*
* This is also the same as what Aegis exports in plain-text format.
* This face performs minimal sanitisation of input, however.
*
* At the moment, to get the records onto the filesystem, start a serial connection and do:
* echo otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example > totp_uris.txt
* echo otpauth://totp/ACME%20Co:john.doe@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30 >> totp_uris.txt
* (note the double >> in the second one)
*
* You may want to customise the characters that appear to identify the 2FA
* code. These are just the first two characters of the issuer, and it's fine
* to modify the URI.
*
* If you have more than one secret key, press ALARM to cycle through them.
*/
#include "movement.h"
typedef struct {

View File

@ -22,24 +22,12 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
// #include <threads.h>
#include "wake_face.h"
#include "watch.h"
#include "watch_utility.h"
/*
UI Notes
º Light advances hour by 1
º Light long press advances hour by 6
º Alarm advances minute by 10
º Alarm long press cycles through signal modes (just one at the moment)
*/
//
// Private
//

View File

@ -22,11 +22,24 @@
* SOFTWARE.
*/
//-----------------------------------------------------------------------------
#ifndef WAKE_FACE_H_
#define WAKE_FACE_H_
/*
* WAKE daily alarm face
*
* Basic daily alarm clock face. Seems useful if nothing else in the interest
* of feature parity with the F-91Ws OEM module, 593.
*
* Also experiments with caret-free UI: One button cycles hours, the other
* minutes, so theres no toggling between display and adjust modes and no
* cycling the caret through the UI.
* º LIGHT advances hour by 1
* º LIGHT long press advances hour by 6
* º ALARM advances minute by 10
* º ALARM long press cycles through signal modes (just one at the moment)
*/
#include "movement.h"
typedef struct {

View File

@ -25,6 +25,17 @@
#ifndef CHARACTER_SET_FACE_H_
#define CHARACTER_SET_FACE_H_
/*
* CHARACTER SET FACE
*
* This watch face displays all of the characters in the Sensor Watch character
* set. You can advance from one character to the next with a short press of the
* ALARM button.
*
* This watch face may be useful to watch face developers, in that it can help
* them to understand which characters will work in different positions.
*/
#include "movement.h"
void character_set_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -25,8 +25,6 @@
#ifndef CHIRPY_DEMO_FACE_H_
#define CHIRPY_DEMO_FACE_H_
#include "movement.h"
/*
* CHIRPY DEMO FACE
*
@ -50,9 +48,10 @@
*
* To record and decode a chirpy transmission on your computer, you can use the web app here:
* https://jealousmarkup.xyz/off/chirpy/rx/
*
*/
#include "movement.h"
void chirpy_demo_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
void chirpy_demo_face_activate(movement_settings_t *settings, void *context);
bool chirpy_demo_face_loop(movement_event_t event, movement_settings_t *settings, void *context);

View File

@ -25,6 +25,17 @@
#ifndef DEMO_FACE_H_
#define DEMO_FACE_H_
/*
* DEMO FACE
*
* This watch was designed for the Crowd Supply marketing team, so they could
* photograph the various functions of Sensor Watch. The Alarm button advances
* through static screens that simulate different watch faces.
*
* This watch face may only be useful to you if you need to photograph Sensor
* Watch, i.e. for a blog post.
*/
#include "movement.h"
void demo_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -25,6 +25,18 @@
#ifndef FREQUENCY_CORRECTION_FACE_H_
#define FREQUENCY_CORRECTION_FACE_H_
/*
* FREQUENCY CORRECTION FACE
*
* While active, this face generates a square-wave on pin A1 of the 9-pin
* connector. The output frequency is adjustable from 64 Hz to 0.5 Hz.
* Long-press ALARM to cycle through available frequencies.
*
* This face also displays the value of the watch's frequency-correction
* register. This setting varies from -127 to +127. Press LIGHT to increment
* or ALARM to decrement the setting.
*/
#include "movement.h"
typedef struct {

View File

@ -25,6 +25,13 @@
#ifndef HELLO_THERE_FACE_H_
#define HELLO_THERE_FACE_H_
/*
* HELLO THERE FACE
*
* A simple demo that displays the word "Hello" and then the word "there",
* on an endless loop. Press ALARM to pause or resume the animation.
*/
#include "movement.h"
typedef struct {

View File

@ -25,6 +25,14 @@
#ifndef LIS2DW_LOGGING_FACE_H_
#define LIS2DW_LOGGING_FACE_H_
/*
* LIS2DW Accelerometer Data Logger
*
* This is an experimental watch face for logging data on the Sensor Watch
* Motion Express board. I will add more documentation for this watch face
* once this sensor board is more widely available.
*/
#include "movement.h"
#include "watch.h"

View File

@ -25,6 +25,17 @@
#ifndef VOLTAGE_FACE_H_
#define VOLTAGE_FACE_H_
/*
* VOLTAGE face
*
* This watch face is very simple and has no controls to speak of. It displays
* the battery voltage as measured by the SAM L22s ADC.
*
* Note that the Simple Clock watch face includes a low battery warning, so you
* dont technically need to this watch face unless you want to track the
* battery level.
*/
#include "movement.h"
void voltage_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -25,6 +25,12 @@
#ifndef ACCELEROMETER_DATA_ACQUISITION_FACE_H_
#define ACCELEROMETER_DATA_ACQUISITION_FACE_H_
/*
* ACCELEROMETER DATA ACQUISITION
*
* TODO: Add description here, including controls.
*/
#include "movement.h"
#define ACCELEROMETER_DATA_ACQUISITION_INVALID ((uint64_t)(0b11)) // all bits are 1 when the flash is erased

View File

@ -22,37 +22,6 @@
* SOFTWARE.
*/
/* Aperture-priority Light Meter Face
*
* Tested with the "Q3Q-SWAB-A1-00 Temperature + Test Points + OPT3001" flexboard.
* This flexboard could use a revision:
*
* - The thermistor components should be moved west a mm or flipped to the backside
* to avoid stressing the flexboard against the processor so much.
* - The 'no connect' pad falls off easily.
*
* Controls:
*
* - Trigger a measurement by long-pressing Alarm.
* Sensor integration is happening when the Signal indicator is on.
*
* - ISO setting can be cycled by long-pressing Light.
* During integration the current ISO setting will be displayed.
*
* - EV measurement in the top right: "LAP" indicates "half stop".
* So "LAP -1" means EV = -1.5. Likewise "LAP 13" means EV = +13.5
*
* - Aperture in the bottom right: the last 3 main digits are the f-stop.
* Adjust this number in half-stop increments using Alarm = +1/2 and Light = -1/2.
*
* - Best shutter speed in the bottom left: the first 3 digits are the shutter speed.
* Some special chars are needed here: "-" = seconds, "h" = extra half second, "K" = thousands.
* "HI" or "LO" if there's no shutter in the dictionary within 0.5 stops of correct exposure.
*
* - Mode long-press changes the main digits to show raw sensor lux measurements.
*
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>

View File

@ -25,6 +25,37 @@
#ifndef LIGHTMETER_FACE_H_
#define LIGHTMETER_FACE_H_
/*
* Aperture-priority Light Meter Face
*
* Tested with the "Q3Q-SWAB-A1-00 Temperature + Test Points + OPT3001" flexboard.
* This flexboard could use a revision:
*
* - The thermistor components should be moved west a mm or flipped to the backside
* to avoid stressing the flexboard against the processor so much.
* - The 'no connect' pad falls off easily.
*
* Controls:
*
* - Trigger a measurement by long-pressing Alarm.
* Sensor integration is happening when the Signal indicator is on.
*
* - ISO setting can be cycled by long-pressing Light.
* During integration the current ISO setting will be displayed.
*
* - EV measurement in the top right: "LAP" indicates "half stop".
* So "LAP -1" means EV = -1.5. Likewise "LAP 13" means EV = +13.5
*
* - Aperture in the bottom right: the last 3 main digits are the f-stop.
* Adjust this number in half-stop increments using Alarm = +1/2 and Light = -1/2.
*
* - Best shutter speed in the bottom left: the first 3 digits are the shutter speed.
* Some special chars are needed here: "-" = seconds, "h" = extra half second, "K" = thousands.
* "HI" or "LO" if there's no shutter in the dictionary within 0.5 stops of correct exposure.
*
* - Mode long-press changes the main digits to show raw sensor lux measurements.
*/
#include "movement.h"
#include "opt3001.h"

View File

@ -25,6 +25,34 @@
#ifndef THERMISTOR_LOGGING_FACE_H_
#define THERMISTOR_LOGGING_FACE_H_
/*
* THERMISTOR LOGGING (aka Temperature Log)
*
* This watch face automatically logs the temperature once an hour, and
* maintains a 36-hour log of readings. This watch face is admittedly rather
* complex, and bears some explanation.
*
* The main display shows the letters TL in the top left, indicating the
* name of the watch face. At the top right, it displays the index of the
* reading; 0 represents the most recent reading taken, 1 represents one
* hour earlier, etc. The bottom line in this mode displays the logged
* temperature.
*
* A short press of the Alarm button advances to the next oldest reading;
* you will see the number at the top right advance from 0 to 1 to 2, all
* the way to 35, the oldest reading available.
*
* A short press of the Light button will briefly display the timestamp
* of the reading. The letters at the top left will display the word At,
* and the main line will display the timestamp of the currently displayed
* data point. The number in the top right will display the day of the month
* for the given data point; for example, you can read At 22 3:00 PM as
* At 3:00 PM on the 22nd.
*
* If you need to illuminate the LED to read the data point, long press the
* Light button and release it.
*/
#include "movement.h"
#include "watch.h"

View File

@ -25,6 +25,29 @@
#ifndef THERMISTOR_READOUT_FACE_H_
#define THERMISTOR_READOUT_FACE_H_
/*
* THERMISTOR READOUT (aka Temperature Display)
*
* This watch face is designed to work with either the Temperature + GPIO
* sensor board or the Temperature + Light sensor board. It reads the current
* temperature from the thermistor voltage divider on the sensor board, and
* displays the current temperature in degrees Celsius.
*
* When the watch is on your wrist, your body heat interferes with an ambient
* temperature reading, but if you set it on a bedside table, strap it to your
* bike handlebars or place it outside of your tent while camping, this watch
* face can act as a digital thermometer for displaying ambient conditions.
*
* The temperature sensor watch face automatically samples the temperature
* once every five seconds, and it illuminates the Signal indicator just
* before taking a reading.
*
* Pressing the ALARM button toggles the unit display from Celsius to
* Fahrenheit. Technically this sets the global Metric / Imperial flag, so
* any other watch face that displays localizable units will display them in
* the system selected here.
*/
#include "movement.h"
void thermistor_readout_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -28,11 +28,6 @@
#include "thermistor_driver.h"
#include "watch.h"
// This watch face is designed for testing temperature sensor boards.
// It displays temperature readings at a relatively fast rate of 8 Hz,
// and disables low energy mode so my testing device doesn't sleep.
// You more than likely want to use thermistor_readout_face instead.
static void _thermistor_testing_face_update_display(bool in_fahrenheit) {
thermistor_driver_enable();
float temperature_c = thermistor_driver_get_temperature();

View File

@ -25,6 +25,17 @@
#ifndef THERMISTOR_TESTING_FACE_H_
#define THERMISTOR_TESTING_FACE_H_
/*
* THERMISTOR TESTING FACE
*
* This watch face is designed for testing temperature sensor boards.
* It displays temperature readings at a relatively fast rate of 8 Hz,
* and disables low energy mode so my testing device doesn't sleep.
* You more than likely want to use thermistor_readout_face instead.
*
* Press ALARM to toggle display of metric vs. imperial units.
*/
#include "movement.h"
void thermistor_testing_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -20,21 +20,6 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* FineTune face allows to align watch with sub-second precision in 25/250ms accuracy.
* Counts time since previous finetune, and allows to calculate & apply ppm correction for nanosec.
*
* Main screen - adjust delay (light/alarm)
* Long mode press - show hours since previous finetune
* Long mode press - show calculated ppm correction. You can apply it with long light, or just reset finetune timer with long alarm.
*
* Finetune will apply crystal aging correction on every finetune save (as aging is calculated since "last finetune" timestamp) - but you should worry
* about aging only on second/third years of watch calibration (if you are really looking at less than 10 seconds per year of error).
*
* Warning, do not use at the first second of a month, as you might stay at the same month and it will surprise you.
* Just wait 1 second...We are not fully replicating RTC timer behavior when RTC is off.
* Simulating months and years is... too much complexity.
*
*/
#include <stdlib.h>

View File

@ -25,6 +25,34 @@
#ifndef FINETUNE_FACE_H_
#define FINETUNE_FACE_H_
/*
* FINETUNE face
*
* FineTune face allows to align watch with sub-second precision in 25/250ms
* accuracy. Counts time since previous finetune, and allows to calculate &
* apply ppm correction for nanosec.
*
* Best used in conjunction with the NANOSEC face.
*
* Main screen - adjust delay (light/alarm)
* Long MODE press - show hours since previous finetune
* Long MODE press - show calculated ppm correction.
* You can apply it with long LIGHT, or just reset finetune timer with long ALARM.
*
* Finetune will apply crystal aging correction on every finetune save
* (as aging is calculated since "last finetune" timestamp); but you should
* worry about aging only on second/third years of watch calibration (if you
* are really looking at less than 10 seconds per year of error).
*
* Warning, do not use at the first second of a month, as you might stay at
* the same month and it will surprise you. Just wait 1 second...We are not
* fully replicating RTC timer behavior when RTC is off.
* Simulating months and years is... too much complexity.
*
* For full usage instructions, please refer to the wiki:
* https://www.sensorwatch.net/docs/watchfaces/nanosec/
*/
#include "movement.h"
typedef struct {

View File

@ -22,33 +22,6 @@
* SOFTWARE.
*/
/*
* The goal of nanosec face is dramatic improvement of SensorWatch accuracy.
* Minimum goal is <60 seconds of error per year. Full success is if we can reach <15 seconds per year (<0.47ppm error).
*
* It implements temperature correction using tempco from datasheet (and allows to adjust these)
* and allows to introduce offset fix. Therefore requires temperature sensor board.
*
* Most users will need to apply profile 3 ("default") or 2("conservative datasheet"), and tune first parameter -
* static offset (as it's different for every crystal sample).
*
* Frequency correction is dithered over 31 correction intervals (31x10 minutes or ~5 hours), to allow <0.1ppm correction resolution.
* 1ppm is 0.0864 sec per day.
* 0.1ppm is 0.00864 sec per day.
*
* To stay under 1ppm error you would need calibration of your specific instance of quartz crystal after some "burn-in" (ideally 1 year).
*
* Should improve TOTP experience.
*
* Default funing fork tempco: -0.034 ppm/°C², centered around 25°C
* We add optional cubic coefficient, which was measured in practice on my sample.
*
* Cadence (CD) - how many minutes between corrections. Default 10 minutes.
* Every minute might be too much. Every hour - slightly less power consumption but also less precision.
*
* Can compensate crystal aging (ppm/year) - but you really should be worrying about it on second/third years of watch calibration. *
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>

View File

@ -25,6 +25,47 @@
#ifndef NANOSEC_FACE_H_
#define NANOSEC_FACE_H_
/*
* NANOSEC face
*
* The goal of nanosec face is dramatic improvement of SensorWatch accuracy.
* Minimum goal is <60 seconds of error per year. Full success is if we can
* reach <15 seconds per year (<0.47ppm error).
*
* Best used in conjunction with the FINETUNE face.
*
* It implements temperature correction using tempco from datasheet (and
* allows to adjust these) and allows to introduce offset fix. Therefore
* requires temperature sensor board.
*
* Most users will need to apply profile 3 ("default") or 2 ("conservative
* datasheet"), and tune first parameter "static offset" (as it's different
* for every crystal sample).
*
* Frequency correction is dithered over 31 correction intervals (31x10
* minutes or ~5 hours), to allow <0.1ppm correction resolution.
* * 1ppm is 0.0864 sec per day.
* * 0.1ppm is 0.00864 sec per day.
*
* To stay under 1ppm error you would need calibration of your specific
* instance of quartz crystal after some "burn-in" (ideally 1 year).
*
* Should improve TOTP experience.
*
* Default funing fork tempco: -0.034 ppm/°C², centered around 25°C
* We add optional cubic coefficient, which was measured in practice on my sample.
*
* Cadence (CD) - how many minutes between corrections. Default 10 minutes.
* Every minute might be too much. Every hour - slightly less power
* consumption but also less precision.
*
* Can compensate crystal aging (ppm/year) - but you really should be worrying
* about it on second/third years of watch calibration.
*
* For full usage instructions, please refer to the wiki:
* https://www.sensorwatch.net/docs/watchfaces/nanosec/
*/
#include "movement.h"
#define nanosec_profile_count 5

View File

@ -25,6 +25,57 @@
#ifndef PREFERENCES_FACE_H_
#define PREFERENCES_FACE_H_
/*
* PREFERENCES face
*
* The Preferences watch face allows you to configure various options on your
* Sensor Watch. Like all other screens, you advance the field youre setting
* with the Light button, and advance its value with the Alarm button. The
* Preferences watch face labels each setting with a two-letter code on the
* top row; the following list describes each setting and their options:
*
* CL - Clock mode.
* This setting allows you to select a 12-or 24-hour clock display. All
* watch faces that support displaying the time will respect this setting;
* for example, both Simple Clock, World Clock and Sunrise/Sunset will
* display the time in 24 hour format if the 24 hour clock is selected here.
*
* BT - Button tone.
* This setting is only relevant if you installed the buzzer connector,
* and it toggles the beep when changing modes. If Y, the buzzer will
* sound a tone when Mode is pressed. Change to N to make the Mode
* button silent.
*
* TO - Timeout.
* Sets the time until screens that time out (like Settings and Time Set)
* snap back to the first screen. 60 seconds is a good default for the
* stock firmware, but if you choose a custom firmware with faces that
* youd like to keep on screen for longer, you can set that here.
*
* LE - Low Energy mode.
* Sets the time until the watch enters its low energy sleep mode.
* Options range from 1 hour to 7 days, or Never. The more often Sensor
* Watch goes to sleep, the longer its battery will last but you will
* lose the seconds indicator while it is asleep. This setting allows
* you to make a tradeoff between the devices responsiveness and its
* longevity.
*
* LT - Light.
* This setting has three screens.
* The first lets you choose how long the LED should stay lit when the
* LIGHT button is pressed. Options are 1 second, 3 seconds and 5
* seconds, or No LED to disable the LED entirely.
* The second screen, titled blu or grn, sets the intensity of the
* blue or green LED depending on the target Sensor Board hardware.
* Values range from 0 (off) to 15 (full intensity).
* The third screen, red, sets the intensity of the red LED, again
* from 0 to 15.
* On the last two screens, the LED remains on so that you can see the
* effect of mixing the two LED colors. On the Special Edition boards,
* youll have red, blue and a variety of shades of pink and purple to
* experiment with!
*/
#include "movement.h"
void preferences_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -25,6 +25,23 @@
#ifndef SET_TIME_FACE_H_
#define SET_TIME_FACE_H_
/*
* SET TIME face
*
* The default method for adjusting Sensor Watch time.
*
* The Time Set watch face allows you to set the time on Sensor Watch. Use
* the LIGHT button to advance through the field you are setting, and the
* ALARM button to change the value in that field. The fields are, in order:
* Hour, Minute, Second, Year, Month, Day and Time Zone.
*
* For features like World Clock and Sunrise/Sunset to work correctly, you
* must set the time to your local time, and the time zone to your local time
* zone. This allows Sensor Watch to correctly offset the time. This also
* means that when daylight savings time starts or ends, you must update
* both the time and the time zone on this screen.
*/
#include "movement.h"
void set_time_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);

View File

@ -21,21 +21,6 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*
* This is an extended version of set_time face which allow setting seconds precisely.
* To achieve that - press and hold alarm button few seconds before 00 and release exaclty as reference clock turns 00.
* All settings can go up, or down (long alarm press).
*
* The challenge is that SensorWatch display is delayed 0.5 seconds vs hardware RTC clock. It is caused by interrupts being generated by raising
* edge of counter. It means there is no way to precisely trigger at 0.5s, as events at different frequencies slightly mismatch.
* This watch face achieves this approximately by triggering at 15th out of 32Hz events.
*
* If you are <30 seconds when setting seconds - you will stay in the same minute. Otherwise - you will go to next minute.
*
* Note that changing anything will slightly delay subseconds counter. This is why this face sets seconds last
* to achiveve best precision. Still, best possible precision is achieved with finetune face.
*/
#include <stdlib.h>

View File

@ -25,6 +25,29 @@
#ifndef SET_TIME_HACKWATCH_FACE_H_
#define SET_TIME_HACKWATCH_FACE_H_
/*
* SET TIME HACKWATCH
*
* This is an extended version of set_time face which allow setting seconds
* precisely. To achieve that - press and hold alarm button few seconds before
* 00 and release exaclty as reference clock turns 00.
*
* All settings can go up, or down (long alarm press).
*
* The challenge is that SensorWatch display is delayed 0.5 seconds vs hardware
* RTC clock. It is caused by interrupts being generated by raising edge of
* counter. It means there is no way to precisely trigger at 0.5s, as events
* at different frequencies slightly mismatch. This watch face achieves this
* approximately by triggering at 15th out of 32Hz events.
*
* If you are <30 seconds when setting seconds - you will stay in the same
* minute. Otherwise - you will go to next minute.
*
* Note that changing anything will slightly delay subseconds counter. This
* is why this face sets seconds last to achiveve best precision. Still,
* best possible precision is achieved with finetune face.
*/
#include "movement.h"
void set_time_hackwatch_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);