Merge branch 'main' of github.com:joeycastillo/Sensor-Watch into main

This commit is contained in:
Joey Castillo 2022-01-15 19:27:24 -05:00
commit 5fccc24c98
6 changed files with 304 additions and 0 deletions

View File

@ -48,6 +48,7 @@ SRCS += \
../watch_faces/complications/stopwatch_face.c \
../watch_faces/complications/totp_face.c \
../watch_faces/complications/sunrise_sunset_face.c \
../watch_faces/complications/countdown_face.c \
# Leave this line at the bottom of the file; it has all the targets for making your project.
include $(TOP)/rules.mk

View File

@ -181,6 +181,18 @@ void movement_schedule_background_task(watch_date_time date_time) {
}
}
void movement_cancel_background_task(void) {
scheduled_tasks[movement_state.current_watch_face].reg = 0;
bool other_tasks_scheduled = false;
for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) {
if (scheduled_tasks[i].reg != 0) {
other_tasks_scheduled = true;
break;
}
}
movement_state.has_scheduled_background_task = other_tasks_scheduled;
}
void movement_play_signal(void) {
watch_buzzer_play_note(BUZZER_NOTE_C8, 75);
watch_buzzer_play_note(BUZZER_NOTE_REST, 100);

View File

@ -282,6 +282,10 @@ void movement_request_tick_frequency(uint8_t freq);
// movement will associate the scheduled task with the currently active face.
void movement_schedule_background_task(watch_date_time date_time);
// note: watch faces can only cancel their background task when in the foreground, since
// movement will associate the scheduled task with the currently active face.
void movement_cancel_background_task(void);
void movement_play_signal(void);
void movement_play_alarm(void);

View File

@ -42,6 +42,7 @@
#include "demo_face.h"
#include "hello_there_face.h"
#include "sunrise_sunset_face.h"
#include "countdown_face.h"
const watch_face_t watch_faces[] = {
simple_clock_face,

View File

@ -0,0 +1,217 @@
/*
* MIT License
*
* Copyright (c) 2022 Wesley Ellis
*
* 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 "countdown_face.h"
#include "watch.h"
#include "watch_utility.h"
#define CD_SELECTIONS 2
static uint32_t offset_date_time(uint32_t now, int8_t hours, int8_t minutes, int8_t seconds) {
uint32_t new = now;
new += hours * 60 * 60;
new += minutes * 60;
new += seconds;
return new;
}
static inline int32_t get_tz_offset(movement_settings_t *settings) {
return movement_timezone_offsets[settings->bit.time_zone] * 60;
}
static void start(countdown_state_t *state, movement_settings_t *settings) {
watch_date_time now = watch_rtc_get_date_time();
state->mode = cd_running;
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
state->target_ts = offset_date_time(state->now_ts, 0, state->minutes, state->seconds);
watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
movement_schedule_background_task(target_dt);
watch_set_indicator(WATCH_INDICATOR_BELL);
}
static void draw(countdown_state_t *state, uint8_t subsecond) {
char buf[16];
uint32_t delta;
div_t result;
uint8_t min, sec;
switch (state->mode) {
case cd_running:
delta = state->target_ts - state->now_ts;
result = div(delta, 60);
min = result.quot;
sec = result.rem;
sprintf(buf, "CD %2d%02d", min, sec);
break;
case cd_waiting:
sprintf(buf, "CD %2d%02d", state->minutes, state->seconds);
break;
case cd_setting:
sprintf(buf, "CD %2d%02d", state->minutes, state->seconds);
if (subsecond % 2) {
switch(state->selection) {
case 0:
buf[6] = buf[7] = ' ';
break;
case 1:
buf[8] = buf[9] = ' ';
break;
default:
break;
}
}
break;
}
watch_display_string(buf, 0);
}
static void reset(countdown_state_t *state) {
state->mode = cd_waiting;
movement_cancel_background_task();
watch_clear_indicator(WATCH_INDICATOR_BELL);
}
static void ring(countdown_state_t *state) {
movement_play_signal();
reset(state);
}
static void settings_increment(countdown_state_t *state) {
switch(state->selection) {
case 0:
state->minutes = (state->minutes + 1) % 100;
break;
case 1:
state->seconds = (state->seconds + 1) % 60;
break;
default:
// should never happen
break;
}
return;
}
void countdown_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(countdown_state_t));
countdown_state_t *state = (countdown_state_t *)*context_ptr;
memset(*context_ptr, 0, sizeof(countdown_state_t));
state->minutes = 3;
}
}
void countdown_face_activate(movement_settings_t *settings, void *context) {
(void) settings;
countdown_state_t *state = (countdown_state_t *)context;
if(state->mode == cd_running) {
watch_date_time now = watch_rtc_get_date_time();
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
}
}
bool countdown_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
(void) settings;
countdown_state_t *state = (countdown_state_t *)context;
switch (event.event_type) {
case EVENT_ACTIVATE:
draw(state, event.subsecond);
break;
case EVENT_TICK:
if (state->mode == cd_running) {
state->now_ts++;
}
draw(state, event.subsecond);
break;
case EVENT_MODE_BUTTON_UP:
movement_move_to_next_face();
break;
case EVENT_LIGHT_BUTTON_UP:
switch(state->mode) {
case cd_running:
movement_illuminate_led();
break;
case cd_waiting:
state->mode = cd_setting;
movement_request_tick_frequency(4);
break;
case cd_setting:
state->selection++;
if(state->selection >= CD_SELECTIONS) {
state->selection = 0;
state->mode = cd_waiting;
movement_request_tick_frequency(1);
}
break;
}
draw(state, event.subsecond);
break;
case EVENT_ALARM_BUTTON_UP:
switch(state->mode) {
case cd_running:
reset(state);
break;
case cd_waiting:
start(state, settings);
break;
case cd_setting:
settings_increment(state);
break;
}
draw(state, event.subsecond);
break;
case EVENT_BACKGROUND_TASK:
ring(state);
break;
case EVENT_ALARM_LONG_PRESS:
break;
case EVENT_TIMEOUT:
movement_move_to_face(0);
break;
case EVENT_LOW_ENERGY_UPDATE:
default:
break;
}
return true;
}
void countdown_face_resign(movement_settings_t *settings, void *context) {
(void) settings;
(void) context;
movement_request_tick_frequency(1);
}

View File

@ -0,0 +1,69 @@
/*
* MIT License
*
* Copyright (c) 2022 Wesley Ellis
*
* 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 COUNTDOWN_FACE_H_
#define COUNTDOWN_FACE_H_
#include "movement.h"
/*
A countdown/timer face
Max countdown is 99 minutes and 59 seconds since we have to prevent the watch
from going to deep sleep using movement_schedule_background_task
*/
typedef enum {
cd_waiting,
cd_running,
cd_setting
} countdown_mode_t;
typedef struct {
uint32_t target_ts;
uint32_t now_ts;
uint8_t minutes;
uint8_t seconds;
uint8_t selection;
countdown_mode_t mode;
} countdown_state_t;
void countdown_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
void countdown_face_activate(movement_settings_t *settings, void *context);
bool countdown_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
void countdown_face_resign(movement_settings_t *settings, void *context);
static const watch_face_t countdown_face = {
countdown_face_setup,
countdown_face_activate,
countdown_face_loop,
countdown_face_resign,
NULL
};
#endif // COUNTDOWN_FACE_H_