wip: late-night untested launcher app musings
This commit is contained in:
		
							parent
							
								
									15ae7ab84b
								
							
						
					
					
						commit
						624ff19580
					
				
							
								
								
									
										142
									
								
								launcher/launcher.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								launcher/launcher.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										74
									
								
								launcher/launcher.h
									
									
									
									
									
										Normal 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_
 | ||||||
							
								
								
									
										13
									
								
								launcher/launcher_config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								launcher/launcher_config.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										1
									
								
								launcher/make/.gitignore
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | build/ | ||||||
							
								
								
									
										26
									
								
								launcher/make/Makefile
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										26
									
								
								launcher/make/Makefile
									
									
									
									
									
										Executable 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 | ||||||
							
								
								
									
										24
									
								
								launcher/widgets/fake_widget.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								launcher/widgets/fake_widget.c
									
									
									
									
									
										Normal 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; | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								launcher/widgets/fake_widget.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								launcher/widgets/fake_widget.h
									
									
									
									
									
										Normal 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_
 | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user