Merge branch 'main' into day_one_face
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, you’ll 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 Earth’s moon
|
||||
* MA - Mars
|
||||
* JU - Jupiter
|
||||
* SA - Saturn
|
||||
* UR - Uranus
|
||||
* NE - Neptune
|
||||
*
|
||||
* Once you’ve 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"
|
||||
|
||||
|
||||
@@ -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 battery’s 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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
267
movement/watch_faces/complication/couch_to_5k_face.c
Normal file
267
movement/watch_faces/complication/couch_to_5k_face.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Ekaitz Zarraga <ekaitz@elenq.tech>
|
||||
*
|
||||
* 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 "couch_to_5k_face.h"
|
||||
|
||||
// They go: Warmup, Run, Walk, Run, Walk, Run, Walk ... , End (0)
|
||||
// Time is defined in seconds
|
||||
// Maybe do /10 to reduce memory usage?
|
||||
// (i don't want to use floats)
|
||||
|
||||
// uint16_t C25K_WEEK_TEST[] = {10, 10, 10, 0};
|
||||
uint16_t C25K_WEEK_1[] = {300, 60, 90, 60, 90, 60, 90, 60, 90, 60, 90, 60,
|
||||
90, 60, 90, 60, 90, 0};
|
||||
uint16_t C25K_WEEK_2[] = {300, 90, 120, 90, 120, 90, 120, 90, 120, 90, 120,
|
||||
90, 120, 0};
|
||||
uint16_t C25K_WEEK_3[] = {300, 90, 90, 180, 180, 90, 90, 180, 180, 0};
|
||||
uint16_t C25K_WEEK_4[] = {300, 180, 90, 300, 150, 180, 90, 300, 0};
|
||||
uint16_t C25K_WEEK_5_1[] = {300, 300, 180, 300, 180, 300, 0 };
|
||||
uint16_t C25K_WEEK_5_2[] = {300, 480, 300, 480 , 0};
|
||||
uint16_t C25K_WEEK_5_3[] = {300, 1200, 0};
|
||||
uint16_t C25K_WEEK_6_1[] = {300, 300, 180, 480, 180, 300, 0 };
|
||||
uint16_t C25K_WEEK_6_2[] = {300, 600, 180, 600 , 0};
|
||||
uint16_t C25K_WEEK_6_3[] = {300, 1500, 0};
|
||||
uint16_t C25K_WEEK_7[] = {300, 1500, 0};
|
||||
uint16_t C25K_WEEK_8[] = {300, 1680, 0};
|
||||
uint16_t C25K_WEEK_9[] = {300, 1800, 0};
|
||||
|
||||
|
||||
#define C25K_SESSIONS_LENGTH 3*9
|
||||
uint16_t *C25K_SESSIONS[C25K_SESSIONS_LENGTH];
|
||||
|
||||
static inline bool _finished(couch_to_5k_state_t *state){
|
||||
return state->exercise_type == C25K_FINISHED;
|
||||
}
|
||||
static inline bool _cleared(couch_to_5k_state_t *state){
|
||||
return state->timer == C25K_SESSIONS[state->session][0]
|
||||
&& state->exercise == 0;
|
||||
}
|
||||
static inline void _next_session(couch_to_5k_state_t *state){
|
||||
if (++state->session >= C25K_SESSIONS_LENGTH){
|
||||
state->session = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _assign_exercise_type(couch_to_5k_state_t *state){
|
||||
if (state->exercise == 0){
|
||||
state->exercise_type = C25K_WARMUP;
|
||||
} else if (state->exercise % 2 == 1){
|
||||
state->exercise_type = C25K_RUN;
|
||||
} else {
|
||||
state->exercise_type = C25K_WALK;
|
||||
}
|
||||
}
|
||||
|
||||
static void _next_exercise(couch_to_5k_state_t *state){
|
||||
state->exercise++;
|
||||
state->timer = C25K_SESSIONS[state->session][state->exercise];
|
||||
// If the new timer starts in zero, it's finished
|
||||
if (state->timer == 0){
|
||||
movement_play_alarm_beeps(7, BUZZER_NOTE_C8);
|
||||
state->exercise_type = C25K_FINISHED;
|
||||
return;
|
||||
}
|
||||
movement_play_alarm_beeps(4, BUZZER_NOTE_A7);
|
||||
_assign_exercise_type(state);
|
||||
}
|
||||
|
||||
static void _init_session(couch_to_5k_state_t *state){
|
||||
state->exercise = 0; // Restart exercise counter
|
||||
state->timer = C25K_SESSIONS[state->session][state->exercise];
|
||||
_assign_exercise_type(state);
|
||||
}
|
||||
|
||||
static char *_exercise_type_to_str(exercise_type_t t){
|
||||
switch (t){
|
||||
case C25K_WARMUP:
|
||||
return "WU";
|
||||
case C25K_RUN:
|
||||
return "RU";
|
||||
case C25K_WALK:
|
||||
return "WA";
|
||||
case C25K_FINISHED:
|
||||
return "--";
|
||||
default:
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
static void _display(couch_to_5k_state_t *state, char *buf){
|
||||
// TODO only repaint needed parts
|
||||
uint8_t seconds = state->timer % 60;
|
||||
sprintf(buf, "%s%2d%2d%02d%02d",
|
||||
_exercise_type_to_str(state->exercise_type),
|
||||
(state->session + 1) % 100,
|
||||
((state->timer - seconds) / 60) % 100,
|
||||
seconds,
|
||||
(state->exercise + 1) % 100);
|
||||
watch_display_string(buf, 0);
|
||||
}
|
||||
|
||||
|
||||
void couch_to_5k_face_setup(movement_settings_t *settings, uint8_t
|
||||
watch_face_index, void ** context_ptr) {
|
||||
(void) settings;
|
||||
(void) watch_face_index;
|
||||
if (*context_ptr == NULL) {
|
||||
*context_ptr = malloc(sizeof(couch_to_5k_state_t));
|
||||
memset(*context_ptr, 0, sizeof(couch_to_5k_state_t));
|
||||
// Do any one-time tasks in here; the inside of this conditional
|
||||
// happens only at boot.
|
||||
// C25K_SESSIONS[0] = C25K_WEEK_TEST;
|
||||
C25K_SESSIONS[0] = C25K_WEEK_1;
|
||||
C25K_SESSIONS[1] = C25K_WEEK_1;
|
||||
C25K_SESSIONS[2] = C25K_WEEK_1;
|
||||
C25K_SESSIONS[3] = C25K_WEEK_2;
|
||||
C25K_SESSIONS[4] = C25K_WEEK_2;
|
||||
C25K_SESSIONS[5] = C25K_WEEK_2;
|
||||
C25K_SESSIONS[6] = C25K_WEEK_3;
|
||||
C25K_SESSIONS[7] = C25K_WEEK_3;
|
||||
C25K_SESSIONS[8] = C25K_WEEK_3;
|
||||
C25K_SESSIONS[9] = C25K_WEEK_4;
|
||||
C25K_SESSIONS[10] = C25K_WEEK_4;
|
||||
C25K_SESSIONS[11] = C25K_WEEK_4;
|
||||
C25K_SESSIONS[12] = C25K_WEEK_5_1;
|
||||
C25K_SESSIONS[13] = C25K_WEEK_5_2;
|
||||
C25K_SESSIONS[14] = C25K_WEEK_5_3;
|
||||
C25K_SESSIONS[15] = C25K_WEEK_6_1;
|
||||
C25K_SESSIONS[16] = C25K_WEEK_6_2;
|
||||
C25K_SESSIONS[17] = C25K_WEEK_6_3;
|
||||
C25K_SESSIONS[18] = C25K_WEEK_7;
|
||||
C25K_SESSIONS[19] = C25K_WEEK_7;
|
||||
C25K_SESSIONS[20] = C25K_WEEK_7;
|
||||
C25K_SESSIONS[21] = C25K_WEEK_8;
|
||||
C25K_SESSIONS[22] = C25K_WEEK_8;
|
||||
C25K_SESSIONS[23] = C25K_WEEK_8;
|
||||
C25K_SESSIONS[24] = C25K_WEEK_9;
|
||||
C25K_SESSIONS[25] = C25K_WEEK_9;
|
||||
C25K_SESSIONS[26] = C25K_WEEK_9;
|
||||
}
|
||||
// Do any pin or peripheral setup here; this will be called whenever the
|
||||
// watch wakes from deep sleep.
|
||||
}
|
||||
|
||||
void couch_to_5k_face_activate(movement_settings_t *settings, void *context) {
|
||||
(void) settings;
|
||||
(void) context;
|
||||
// Handle any tasks related to your watch face coming on screen.
|
||||
watch_set_colon();
|
||||
}
|
||||
|
||||
|
||||
bool couch_to_5k_face_loop(movement_event_t event, movement_settings_t *settings,
|
||||
void *context) {
|
||||
couch_to_5k_state_t *state = (couch_to_5k_state_t *)context;
|
||||
static char buf[11];
|
||||
static bool paused = true;
|
||||
|
||||
switch (event.event_type) {
|
||||
case EVENT_ACTIVATE:
|
||||
// Show your initial UI here.
|
||||
movement_request_tick_frequency(1);
|
||||
_init_session(state);
|
||||
paused = true;
|
||||
_display(state, buf);
|
||||
break;
|
||||
case EVENT_TICK:
|
||||
if ( !paused && !_finished(state) ) {
|
||||
if (state->timer == 0){
|
||||
_next_exercise(state);
|
||||
} else {
|
||||
state->timer--;
|
||||
}
|
||||
}
|
||||
_display(state, buf);
|
||||
break;
|
||||
case EVENT_LIGHT_BUTTON_UP:
|
||||
// This is the next-exercise / reset button.
|
||||
|
||||
// When finished move to the next session and leave it paused
|
||||
if ( _finished(state) ){
|
||||
_next_session(state);
|
||||
_init_session(state);
|
||||
paused = true;
|
||||
break;
|
||||
}
|
||||
// When paused and cleared move to next, when only paused, clear
|
||||
if ( paused ) {
|
||||
if ( _cleared(state) ){
|
||||
_next_session(state);
|
||||
}
|
||||
_init_session(state);
|
||||
}
|
||||
break;
|
||||
case EVENT_ALARM_BUTTON_UP:
|
||||
if (settings->bit.button_should_sound) {
|
||||
watch_buzzer_play_note(BUZZER_NOTE_C8, 50);
|
||||
}
|
||||
paused = !paused;
|
||||
break;
|
||||
case EVENT_TIMEOUT:
|
||||
// Your watch face will receive this event after a period of
|
||||
// inactivity. If it makes sense to resign,
|
||||
movement_move_to_face(0);
|
||||
break;
|
||||
case EVENT_LOW_ENERGY_UPDATE:
|
||||
// If you did not resign in EVENT_TIMEOUT, you can use this event
|
||||
// to update the display once a minute. Avoid displaying
|
||||
// fast-updating values like seconds, since the display won't
|
||||
// update again for 60 seconds. You should also consider starting
|
||||
// the tick animation, to show the wearer that this is sleep mode:
|
||||
// watch_start_tick_animation(500);
|
||||
break;
|
||||
default:
|
||||
// Movement's default loop handler will step in for any cases you
|
||||
// don't handle above:
|
||||
// * EVENT_LIGHT_BUTTON_DOWN lights the LED
|
||||
// * EVENT_MODE_BUTTON_UP moves to the next watch face in the list
|
||||
// * EVENT_MODE_LONG_PRESS returns to the first watch face (or
|
||||
// skips to the secondary watch face, if configured)
|
||||
// You can override any of these behaviors by adding a case for
|
||||
// these events to this switch statement.
|
||||
return movement_default_loop_handler(event, settings);
|
||||
}
|
||||
|
||||
// return true if the watch can enter standby mode. Generally speaking, you
|
||||
// should always return true.
|
||||
// Exceptions:
|
||||
// * If you are displaying a color using the low-level watch_set_led_color
|
||||
// function, you should return false.
|
||||
// * If you are sounding the buzzer using the low-level
|
||||
// watch_set_buzzer_on function, you should return false.
|
||||
// Note that if you are driving the LED or buzzer using Movement functions
|
||||
// like movement_illuminate_led or movement_play_alarm, you can still
|
||||
// return true. This guidance only applies to the low-level watch_
|
||||
// functions.
|
||||
return true;
|
||||
}
|
||||
|
||||
void couch_to_5k_face_resign(movement_settings_t *settings, void *context) {
|
||||
(void) settings;
|
||||
(void) context;
|
||||
|
||||
// handle any cleanup before your watch face goes off-screen.
|
||||
}
|
||||
|
||||
87
movement/watch_faces/complication/couch_to_5k_face.h
Normal file
87
movement/watch_faces/complication/couch_to_5k_face.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Ekaitz Zarraga <ekaitz@elenq.tech>
|
||||
*
|
||||
* 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 COUCHTO5K_FACE_H_
|
||||
#define COUCHTO5K_FACE_H_
|
||||
|
||||
#include "movement.h"
|
||||
|
||||
/*
|
||||
* Couch To 5k;
|
||||
*
|
||||
*
|
||||
* The program is designed to train 3 times a week. Each training is a
|
||||
* *session*. Each of the rounds you have in the training is an *exercise*.
|
||||
*
|
||||
* The training goes like this:
|
||||
* 5min warm-up walk -> Run X minutes -> Walk Y minutes -> ... -> Stop
|
||||
*
|
||||
* The watch face shows it like this: The weekday indicator shows if you need
|
||||
* to Warm Up (`WU`), run (`rU`), walk (`WA`) or stop (`--`).
|
||||
*
|
||||
* The month-day indicator shows the session you are in (from 1 to 27).
|
||||
*
|
||||
* The timer shows the time you have left in the exercise and the exercise you
|
||||
* are doing (MM:SS:ee). When an exercise finishes you are notified with an
|
||||
* alarm. When the whole session finishes, a different tone is played for a
|
||||
* longer period.
|
||||
*
|
||||
* Pressing the ALARM button pauses/resumes the clock.
|
||||
*
|
||||
* Pressing the LIGHT button does nothing if the timer is not paused. When it
|
||||
* is paused it clears the current session (it restarts it to the beginning)
|
||||
* and if it was already cleared or the current session was finished moves to
|
||||
* the next session.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
C25K_WARMUP,
|
||||
C25K_RUN,
|
||||
C25K_WALK,
|
||||
C25K_FINISHED
|
||||
} exercise_type_t;
|
||||
|
||||
typedef struct {
|
||||
// Anything you need to keep track of, put it here!
|
||||
uint8_t session;
|
||||
uint8_t exercise;
|
||||
exercise_type_t exercise_type;
|
||||
uint16_t timer;
|
||||
} couch_to_5k_state_t;
|
||||
|
||||
void couch_to_5k_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||
void couch_to_5k_face_activate(movement_settings_t *settings, void *context);
|
||||
bool couch_to_5k_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||
void couch_to_5k_face_resign(movement_settings_t *settings, void *context);
|
||||
|
||||
#define couch_to_5k_face ((const watch_face_t){ \
|
||||
couch_to_5k_face_setup, \
|
||||
couch_to_5k_face_activate, \
|
||||
couch_to_5k_face_loop, \
|
||||
couch_to_5k_face_resign, \
|
||||
NULL, \
|
||||
})
|
||||
|
||||
#endif // COUCHTO5K_FACE_H_
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 or until a given date.
|
||||
* It was originally designed to display the number of days you’ve 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 the days since or until a given date. 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 enum {
|
||||
PAGE_DISPLAY,
|
||||
|
||||
@@ -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"
|
||||
|
||||
/*
|
||||
|
||||
@@ -22,21 +22,24 @@
|
||||
* 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:
|
||||
*
|
||||
* - dg_setting: Select a course
|
||||
* Enter this mode by holding down the light button. The screen will display
|
||||
* the label for the hole and the lowest score since last boot.
|
||||
* Press alarm to loop through the holes. Press the light button to make a
|
||||
* the label for the hole and the lowest score since last boot.
|
||||
* Press alarm to loop through the holes. Press the light button to make a
|
||||
* selection. This will reset all scores and start a new game in dg_idle mode.
|
||||
*
|
||||
* -dg_idle: We're playing a hole
|
||||
* This either shows your current score relative to par, or the score for a
|
||||
* particular hole.
|
||||
* particular hole.
|
||||
* At the start of a game, press alarm to loop through the holes and leave it
|
||||
* your starting hole. For optimal experience, play the course linearly after that
|
||||
* If you're viewing the hole you're supposed to be playing, the watch face will
|
||||
@@ -49,19 +52,15 @@
|
||||
* -dg_scoring: Input score for a hole
|
||||
* In this mode, if the score is 0 (hasn't been entered during this round),
|
||||
* it will blink, indicating we're in scoring mode. Press the alarm button
|
||||
* to increment the score up until 15, in which case it loops back to 0.
|
||||
* to increment the score up until 15, in which case it loops back to 0.
|
||||
* Press the light button to save the score for that hole, advance one hole
|
||||
* if you're not editing an already input score, and returning to idle mode.
|
||||
*
|
||||
* When all scores have been entered, the LAP indicator turns on. At that point, if we enter
|
||||
* dg_setting to select a course, the score for that round is evaluated against the current
|
||||
* When all scores have been entered, the LAP indicator turns on. At that point, if we enter
|
||||
* dg_setting to select a course, the score for that round is evaluated against the current
|
||||
* 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
|
||||
|
||||
@@ -75,7 +74,7 @@ typedef struct {
|
||||
uint8_t course; // Index for course selection, from 0
|
||||
uint8_t hole; // Index for current hole, from 1
|
||||
uint8_t playing; // Current hole
|
||||
int scores[18]; // Scores for each played hole
|
||||
int scores[18]; // Scores for each played hole
|
||||
discgolf_mode_t mode; // Watch face mode
|
||||
} discgolf_state_t;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,7 +124,7 @@
|
||||
/*
|
||||
* MC International Morse Code binary tree
|
||||
* Levels of the tree are concatenated.
|
||||
* '.' = 0 and '-' = 1.
|
||||
* '.' = 0 and '-' = 1.
|
||||
*
|
||||
* Capitals denote special characters:
|
||||
* C = Ch digraph
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 Earth’s 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 planet’s location, and
|
||||
* after a flashing “C” (for Calculating), you will be presented with the
|
||||
* planet’s 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 {
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 it’s 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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -22,15 +22,13 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "timer_face.h"
|
||||
#include "watch.h"
|
||||
#include "watch_utility.h"
|
||||
|
||||
static const uint16_t _default_timer_values[] = {0x200, 0x500, 0xA00, 0x1400, 0x2D02}; // default timers: 2 min, 5 min, 10 min, 20 min, 2 h 45 min
|
||||
static const uint32_t _default_timer_values[] = {0x000200, 0x000500, 0x000A00, 0x001400, 0x002D02}; // default timers: 2 min, 5 min, 10 min, 20 min, 2 h 45 min
|
||||
|
||||
// sound sequence for a single beeping sequence
|
||||
static const int8_t _sound_seq_beep[] = {BUZZER_NOTE_C8, 3, BUZZER_NOTE_REST, 3, -2, 2, BUZZER_NOTE_C8, 5, BUZZER_NOTE_REST, 25, 0};
|
||||
@@ -199,7 +197,7 @@ void timer_face_setup(movement_settings_t *settings, uint8_t watch_face_index, v
|
||||
timer_state_t *state = (timer_state_t *)*context_ptr;
|
||||
memset(*context_ptr, 0, sizeof(timer_state_t));
|
||||
state->watch_face_index = watch_face_index;
|
||||
for (uint8_t i = 0; i < sizeof(_default_timer_values) / sizeof(uint16_t); i++) {
|
||||
for (uint8_t i = 0; i < sizeof(_default_timer_values) / sizeof(uint32_t); i++) {
|
||||
state->timers[i].value = _default_timer_values[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
140
movement/watch_faces/complication/tuning_tones_face.c
Normal file
140
movement/watch_faces/complication/tuning_tones_face.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Per Waagø
|
||||
*
|
||||
* 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 "tuning_tones_face.h"
|
||||
|
||||
/*
|
||||
|
||||
This face plays a tone that can be used as a reference when tuning
|
||||
musical instrument.
|
||||
|
||||
- The alarm button (short press) starts and stops the tone
|
||||
- The light button (short press) changes which note is played. The name
|
||||
of the note is shown in the display.
|
||||
|
||||
*/
|
||||
|
||||
typedef struct Note {
|
||||
BuzzerNote note;
|
||||
char * name;
|
||||
} Note;
|
||||
|
||||
static Note notes[] = {
|
||||
{ .note = BUZZER_NOTE_C5, .name = "C " },
|
||||
{ .note = BUZZER_NOTE_C5SHARP_D5FLAT, .name = "Db" },
|
||||
{ .note = BUZZER_NOTE_D5, .name = "D " },
|
||||
{ .note = BUZZER_NOTE_D5SHARP_E5FLAT, .name = "Eb" },
|
||||
{ .note = BUZZER_NOTE_E5, .name = "E " },
|
||||
{ .note = BUZZER_NOTE_F5, .name = "F " },
|
||||
{ .note = BUZZER_NOTE_F5SHARP_G5FLAT, .name = "Gb" },
|
||||
{ .note = BUZZER_NOTE_G5, .name = "G " },
|
||||
{ .note = BUZZER_NOTE_G5SHARP_A5FLAT, .name = "Ab" },
|
||||
{ .note = BUZZER_NOTE_A5, .name = "A " },
|
||||
{ .note = BUZZER_NOTE_A5SHARP_B5FLAT, .name = "Bb" },
|
||||
{ .note = BUZZER_NOTE_B5, .name = "B " },
|
||||
};
|
||||
|
||||
static size_t note_count = sizeof notes / sizeof *notes;
|
||||
|
||||
static void draw(tuning_tones_state_t *state)
|
||||
{
|
||||
watch_display_string(notes[state->note_ind].name, 8);
|
||||
}
|
||||
|
||||
void tuning_tones_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||
(void) settings;
|
||||
(void) watch_face_index;
|
||||
if (*context_ptr == NULL) {
|
||||
tuning_tones_state_t *state = malloc(sizeof *state);
|
||||
memset(state, 0, sizeof *state);
|
||||
state->note_ind = 9;
|
||||
*context_ptr = state;
|
||||
}
|
||||
}
|
||||
|
||||
void tuning_tones_face_activate(movement_settings_t *settings, void *context) {
|
||||
(void) settings;
|
||||
(void) context;
|
||||
}
|
||||
|
||||
static void update_buzzer(const tuning_tones_state_t *state)
|
||||
{
|
||||
if (state->playing) {
|
||||
watch_set_buzzer_off();
|
||||
watch_set_buzzer_period(NotePeriods[notes[state->note_ind].note]);
|
||||
watch_set_buzzer_on();
|
||||
}
|
||||
}
|
||||
|
||||
bool tuning_tones_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
||||
tuning_tones_state_t *state = (tuning_tones_state_t *)context;
|
||||
|
||||
switch (event.event_type) {
|
||||
case EVENT_ACTIVATE:
|
||||
draw(state);
|
||||
break;
|
||||
case EVENT_TICK:
|
||||
break;
|
||||
case EVENT_LIGHT_BUTTON_DOWN:
|
||||
state->note_ind++;
|
||||
if (state->note_ind == note_count) {
|
||||
state->note_ind = 0;
|
||||
}
|
||||
update_buzzer(state);
|
||||
draw(state);
|
||||
break;
|
||||
case EVENT_LIGHT_BUTTON_UP:
|
||||
break;
|
||||
case EVENT_ALARM_BUTTON_DOWN:
|
||||
state->playing = !state->playing;
|
||||
if (!state->playing) {
|
||||
watch_set_buzzer_off();
|
||||
} else {
|
||||
update_buzzer(state);
|
||||
}
|
||||
case EVENT_ALARM_BUTTON_UP:
|
||||
break;
|
||||
case EVENT_TIMEOUT:
|
||||
movement_move_to_face(0);
|
||||
break;
|
||||
case EVENT_LOW_ENERGY_UPDATE:
|
||||
break;
|
||||
default:
|
||||
return movement_default_loop_handler(event, settings);
|
||||
}
|
||||
|
||||
return !state->playing;
|
||||
}
|
||||
|
||||
void tuning_tones_face_resign(movement_settings_t *settings, void *context) {
|
||||
(void) settings;
|
||||
tuning_tones_state_t *state = (tuning_tones_state_t *)context;
|
||||
|
||||
if (state->playing) {
|
||||
state->playing = false;
|
||||
watch_set_buzzer_off();
|
||||
}
|
||||
}
|
||||
57
movement/watch_faces/complication/tuning_tones_face.h
Normal file
57
movement/watch_faces/complication/tuning_tones_face.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Per Waagø
|
||||
*
|
||||
* 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 TUNING_TONES_FACE_H_
|
||||
#define TUNING_TONES_FACE_H_
|
||||
|
||||
#include "movement.h"
|
||||
|
||||
/*
|
||||
* A DESCRIPTION OF YOUR WATCH FACE
|
||||
*
|
||||
* and a description of how use it
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
// Anything you need to keep track of, put it here!
|
||||
bool playing;
|
||||
size_t note_ind;
|
||||
} tuning_tones_state_t;
|
||||
|
||||
void tuning_tones_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||
void tuning_tones_face_activate(movement_settings_t *settings, void *context);
|
||||
bool tuning_tones_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||
void tuning_tones_face_resign(movement_settings_t *settings, void *context);
|
||||
|
||||
#define tuning_tones_face ((const watch_face_t){ \
|
||||
tuning_tones_face_setup, \
|
||||
tuning_tones_face_activate, \
|
||||
tuning_tones_face_loop, \
|
||||
tuning_tones_face_resign, \
|
||||
NULL, \
|
||||
})
|
||||
|
||||
#endif // TUNING_TONES_FACE_H_
|
||||
|
||||
@@ -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
|
||||
//
|
||||
|
||||
@@ -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-91W’s OEM module, 593.
|
||||
*
|
||||
* Also experiments with caret-free UI: One button cycles hours, the other
|
||||
* minutes, so there’s 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 {
|
||||
|
||||
Reference in New Issue
Block a user