wip: late-night untested launcher app musings

This commit is contained in:
Joey Castillo 2021-09-28 01:06:37 -04:00
parent 15ae7ab84b
commit 624ff19580
7 changed files with 298 additions and 0 deletions

142
launcher/launcher.c Normal file
View File

@ -0,0 +1,142 @@
#include <stdio.h>
#include <string.h>
#include "watch.h"
#include "launcher.h"
#include "launcher_config.h"
LauncherState launcher_state;
void * widget_contexts[LAUNCHER_NUM_WIDGETS];
void app_init() {
memset(&launcher_state, 0, sizeof(launcher_state));
}
void app_wake_from_deep_sleep() {
// This app does not support deep sleep mode.
}
void app_setup() {
watch_enable_external_interrupts();
watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_BOTH);
watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_BOTH);
watch_register_interrupt_callback(BTN_ALARM, cb_alarm_pressed, INTERRUPT_TRIGGER_BOTH);
watch_enable_buzzer();
watch_enable_leds();
watch_enable_display();
watch_register_tick_callback(cb_tick);
for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) {
widgets[i].setup(&launcher_state.launcherSettings, widget_contexts[i]);
}
}
void app_prepare_for_sleep() {
}
void app_wake_from_sleep() {
}
LauncherEvent event;
bool app_loop() {
// play a beep if the widget has changed in response to a user's press of the MODE button
if (launcher_state.widget_changed) {
// low note for nonzero case, high note for return to clock
watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 100);
launcher_state.widget_changed = false;
}
// If the LED is off and should be on, turn it on
if (launcher_state.light_ticks > 0 && !launcher_state.led_on) {
watch_set_led_green();
launcher_state.led_on = true;
}
// if the LED is on and should be off, turn it off
if (launcher_state.led_on && launcher_state.light_ticks == 0) {
// unless the user is holding down the LIGHT button, in which case, give them more time.
if (watch_get_pin_level(BTN_LIGHT)) {
launcher_state.light_ticks = 3;
} else {
watch_set_led_off();
launcher_state.led_on = false;
}
}
if (event) {
event = 0;
bool can_sleep = widgets[launcher_state.current_widget].loop(event, &launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]);
if (can_sleep) return true;
event = EVENT_LOOP;
return false;
}
return true;
}
void move_to_next_widget() {
launcher_state.widget_changed = true;
widgets[launcher_state.current_widget].enter_background(&launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]);
launcher_state.current_widget = (launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS;
widgets[launcher_state.current_widget].enter_foreground(&launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]);
}
void move_to_first_widget() {
launcher_state.widget_changed = true;
widgets[launcher_state.current_widget].enter_background(&launcher_state.launcherSettings, widget_contexts[launcher_state.current_widget]);
launcher_state.current_widget = 0;
widgets[0].enter_foreground(&launcher_state.launcherSettings, widget_contexts[0]);
}
void illuminate_led() {
launcher_state.light_ticks = 3;
}
void cb_light_pressed() {
struct calendar_date_time date_time;
watch_get_date_time(&date_time);
if (launcher_state.light_down_timestamp) {
uint8_t diff = (61 + date_time.time.sec) - launcher_state.light_down_timestamp;
if (diff > 1) event = EVENT_LIGHT_LONG_PRESS;
else event = EVENT_LIGHT_BUTTON_UP;
launcher_state.light_down_timestamp = 0;
} else {
launcher_state.light_down_timestamp = date_time.time.sec + 1;
event = EVENT_LIGHT_BUTTON_DOWN;
}
}
void cb_mode_pressed() {
struct calendar_date_time date_time;
watch_get_date_time(&date_time);
if (launcher_state.mode_down_timestamp) {
uint8_t diff = (61 + date_time.time.sec) - launcher_state.mode_down_timestamp;
if (diff > 1) event = EVENT_MODE_LONG_PRESS;
else event = EVENT_MODE_BUTTON_UP;
launcher_state.mode_down_timestamp = 0;
} else {
launcher_state.mode_down_timestamp = date_time.time.sec + 1;
event = EVENT_MODE_BUTTON_DOWN;
}
}
void cb_alarm_pressed() {
struct calendar_date_time date_time;
watch_get_date_time(&date_time);
if (launcher_state.alarm_down_timestamp) {
uint8_t diff = (61 + date_time.time.sec) - launcher_state.alarm_down_timestamp;
if (diff > 1) event = EVENT_ALARM_LONG_PRESS;
else event = EVENT_ALARM_BUTTON_UP;
launcher_state.alarm_down_timestamp = 0;
} else {
launcher_state.alarm_down_timestamp = date_time.time.sec + 1;
event = EVENT_ALARM_BUTTON_DOWN;
}
}
void cb_tick() {
event = EVENT_TICK;
}

74
launcher/launcher.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef LAUNCHER_H_
#define LAUNCHER_H_
#include <stdio.h>
#include <stdbool.h>
// TODO: none of this is implemented
typedef union {
struct {
uint32_t reserved : 1;
uint32_t clock_mode_24h : 1; // determines whether display should use 12 or 24 hour mode.
uint32_t signal_should_sound : 1; // if true, a double beep is played at the top of each hour.
uint32_t alarm_should_sound : 1; // if true, the alarm interrupt plays a song.
uint32_t note_index : 7; // the index of the tone to play, or 0x7F for no tone.
uint32_t snapback_enabled : 1; // if true, snaps back to the main screen after 5 minutes
uint32_t sleep_interval : 3; // 0 to disable sleep, or a number of days to sleep after.
uint32_t sleep_blanks_screen : 1; // blank screen or display "SLEEP" when asleep
uint32_t led_red_color : 8; // for general purpose illumination, the red LED value
uint32_t led_green_color : 8; // for general purpose illumination, the green LED value
} bit;
uint32_t value;
} LauncherSettings;
typedef enum LauncherEvent {
EVENT_NONE = 0, // There is no event to report.
EVENT_ACTIVATE, // Your widget is entering the foreground.
EVENT_TICK, // Most common event type. Your widget is being called from the tick callback.
EVENT_LOOP, // The app did not sleep, and is going into another invocation of the run loop.
EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released.
EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released.
EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released.
EVENT_MODE_BUTTON_DOWN, // The mode button has been pressed, but not yet released.
EVENT_MODE_BUTTON_UP, // The mode button was pressed and released.
EVENT_MODE_LONG_PRESS, // The mode button was held for >2 seconds, and released.
EVENT_ALARM_BUTTON_DOWN, // The alarm button has been pressed, but not yet released.
EVENT_ALARM_BUTTON_UP, // The alarm button was pressed and released.
EVENT_ALARM_LONG_PRESS, // The alarm button was held for >2 seconds, and released.
} LauncherEvent;
typedef void (*launcher_widget_setup)(LauncherSettings *settings, void ** context_ptr);
typedef void (*launcher_widget_enter_foreground)(LauncherSettings *settings, void *context);
typedef bool (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context);
typedef void (*launcher_widget_enter_background)(LauncherSettings *settings, void *context);
typedef struct WatchWidget {
launcher_widget_setup setup;
launcher_widget_enter_foreground enter_foreground;
launcher_widget_loop loop;
launcher_widget_enter_background enter_background;
} WatchWidget;
typedef struct LauncherState {
// properties stored in BACKUP register
LauncherSettings launcherSettings;
// transient properties
int16_t current_widget;
bool widget_changed;
// LED stuff
uint8_t light_ticks;
bool led_on;
// button tracking for long press
uint8_t light_down_timestamp;
uint8_t mode_down_timestamp;
uint8_t alarm_down_timestamp;
} LauncherState;
void cb_mode_pressed();
void cb_light_pressed();
void cb_alarm_pressed();
void cb_tick();
#endif // LAUNCHER_H_

View File

@ -0,0 +1,13 @@
#ifndef LAUNCHER_CONFIG_H_
#define LAUNCHER_CONFIG_H_
#include "fake_widget.h"
#define LAUNCHER_NUM_WIDGETS 1
WatchWidget widgets[LAUNCHER_NUM_WIDGETS] = {
fake_widget
};
#endif // LAUNCHER_CONFIG_H_

1
launcher/make/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
build/

26
launcher/make/Makefile Executable file
View File

@ -0,0 +1,26 @@
# Leave this line at the top of the file; it has all the watch library sources and includes.
TOP = ../..
include $(TOP)/make.mk
# If you add any other subdirectories with header files you wish to include, add them after ../
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
# INCLUDES += \
# -I../ \
# -I../drivers/ \
# -I../utils/
INCLUDES += \
-I../ \
-I../widgets/ \
# If you add any other source files you wish to compile, add them after ../app.c
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
# SRCS += \
# ../app.c \
# ../drivers/bmp280.c \
# ../utils/temperature.c
SRCS += \
../launcher.c \
../widgets/fake_widget.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

@ -0,0 +1,24 @@
#include "fake_widget.h"
void fake_widget_setup(LauncherSettings *settings, void ** context_ptr) {
(void) settings;
*context_ptr = NULL;
}
void fake_widget_enter_foreground(LauncherSettings *settings, void *context) {
(void) settings;
(void) context;
}
bool fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context) {
(void) event;
(void) settings;
(void) context;
return true;
}
void fake_widget_enter_background(LauncherSettings *settings, void *context) {
(void) settings;
(void) context;
}

View File

@ -0,0 +1,18 @@
#ifndef FAKE_WIDGET_H_
#define FAKE_WIDGET_H_
#include "launcher.h"
void fake_widget_setup(LauncherSettings *settings, void ** context_ptr);
void fake_widget_enter_foreground(LauncherSettings *settings, void *context);
bool fake_widget_loop(LauncherEvent event, LauncherSettings *settings, void *context);
void fake_widget_enter_background(LauncherSettings *settings, void *context);
#define fake_widget { \
fake_widget_setup, \
fake_widget_enter_foreground, \
fake_widget_loop, \
fake_widget_enter_background, \
}
#endif // FAKE_WIDGET_H_