Beats time app + watch
Use BMP280 code as a base, but stripped down to bare bones. Then added a new 'mode' for the current Swatch Internet Time (aka beats)
This commit is contained in:
		
							parent
							
								
									115c555c4c
								
							
						
					
					
						commit
						b0703ec777
					
				
							
								
								
									
										269
									
								
								apps/beats-time/app.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								apps/beats-time/app.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,269 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
| #include "watch.h" | ||||
| 
 | ||||
| const uint8_t UTC_OFFSET = 4; // set to your current UTC offset to see correct beats time
 | ||||
| 
 | ||||
| typedef enum ApplicationMode { | ||||
|     MODE_CLOCK = 0, // Displays month, day and current time.
 | ||||
|     MODE_BEATS, | ||||
|     MODE_SET,       // (ST) Set time and date
 | ||||
|     NUM_MODES       // Last item in the enum, it's the number of cases.
 | ||||
| } ApplicationMode; | ||||
| 
 | ||||
| 
 | ||||
| typedef struct ApplicationState { | ||||
|     // Internal application state
 | ||||
|     ApplicationMode mode;   // Current mode
 | ||||
|     bool mode_changed;      // Lets us perform one-time setup for a given mode
 | ||||
|     uint16_t mode_ticks;    // Timeout for the mode (returns to clock after timeout expires)
 | ||||
|     uint8_t light_ticks;    // Timeout for the light
 | ||||
|     bool led_on;            // Indicates that the LED is on
 | ||||
|     uint8_t page;           // Tracks the current page in log, prefs or settings.
 | ||||
| } ApplicationState; | ||||
| 
 | ||||
| void do_clock_mode(); | ||||
| void do_beats_mode(); | ||||
| void do_set_time_mode(); | ||||
| void set_time_mode_handle_primary_button(); | ||||
| void set_time_mode_handle_secondary_button(); | ||||
| 
 | ||||
| uint16_t clock2beats(uint16_t, uint16_t, uint16_t, int16_t); | ||||
| 
 | ||||
| void cb_light_pressed(); | ||||
| void cb_mode_pressed(); | ||||
| void cb_alarm_pressed(); | ||||
| void cb_tick(); | ||||
| 
 | ||||
| ApplicationState application_state; | ||||
| char buf[16] = {0}; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Zeroes out the application state struct. | ||||
|  */ | ||||
| void app_init() { | ||||
|     memset(&application_state, 0, sizeof(application_state)); | ||||
| } | ||||
| 
 | ||||
| void app_wake_from_deep_sleep() { | ||||
|     // This app does not support deep sleep mode.
 | ||||
| } | ||||
| 
 | ||||
| void app_setup() { | ||||
|     struct calendar_date_time date_time; | ||||
|     watch_get_date_time(&date_time); | ||||
|     if (date_time.date.year < 2020) { | ||||
|         date_time.date.year = 2020; | ||||
|         watch_set_date_time(date_time); | ||||
|     } | ||||
| 
 | ||||
|     watch_enable_external_interrupts(); | ||||
|     watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_RISING); | ||||
|     watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_RISING); | ||||
|     watch_register_extwake_callback(BTN_ALARM, cb_alarm_pressed, true); | ||||
| 
 | ||||
|     watch_enable_buzzer(); | ||||
|     watch_enable_leds(); | ||||
|     watch_enable_display(); | ||||
| 
 | ||||
|     watch_register_tick_callback(cb_tick); | ||||
| } | ||||
| 
 | ||||
| void app_prepare_for_sleep() { | ||||
| } | ||||
| 
 | ||||
| void app_wake_from_sleep() { | ||||
| } | ||||
| 
 | ||||
| bool app_loop() { | ||||
|     // play a beep if the mode has changed in response to a user's press of the MODE button
 | ||||
|     if (application_state.mode_changed) { | ||||
|         // low note for nonzero case, high note for return to clock
 | ||||
|         watch_buzzer_play_note(application_state.mode ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 100); | ||||
|         application_state.mode_changed = false; | ||||
|     } | ||||
| 
 | ||||
|     // If the user is not in clock mode and the mode timeout has expired, return them to clock mode
 | ||||
|     if (application_state.mode != MODE_CLOCK && application_state.mode_ticks == 0) { | ||||
|         application_state.mode = MODE_CLOCK; | ||||
|         application_state.mode_changed = true; | ||||
|     } | ||||
| 
 | ||||
|     // If the LED is off and should be on, turn it on
 | ||||
|     if (application_state.light_ticks > 0 && !application_state.led_on) { | ||||
|         watch_set_led_green(); | ||||
|         application_state.led_on = true; | ||||
|     } | ||||
| 
 | ||||
|     // if the LED is on and should be off, turn it off
 | ||||
|     if (application_state.led_on && application_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)) { | ||||
|             application_state.light_ticks = 3; | ||||
|         } else { | ||||
|             watch_set_led_off(); | ||||
|             application_state.led_on = false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     switch (application_state.mode) { | ||||
|         case MODE_CLOCK: | ||||
|             do_clock_mode(); | ||||
|             break; | ||||
|         case MODE_BEATS: | ||||
|             do_beats_mode(); | ||||
|             break; | ||||
|         case MODE_SET: | ||||
|             do_set_time_mode(); | ||||
|             break; | ||||
|         case NUM_MODES: | ||||
|             // dummy case, just silences a warning
 | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     application_state.mode_changed = false; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void do_clock_mode() { | ||||
|     struct calendar_date_time date_time; | ||||
|     const char months[12][3] = {"JA", "FE", "MR", "AR", "MA", "JN", "JL", "AU", "SE", "OC", "NO", "dE"}; | ||||
| 
 | ||||
|     watch_get_date_time(&date_time); | ||||
|     watch_display_string((char *)months[date_time.date.month - 1], 0); | ||||
|     sprintf(buf, "%2d%2d%02d%02d", date_time.date.day, date_time.time.hour, date_time.time.min, date_time.time.sec); | ||||
|     watch_display_string(buf, 2); | ||||
|     watch_set_colon(); | ||||
| } | ||||
| 
 | ||||
| void do_beats_mode() { | ||||
|     watch_clear_colon(); | ||||
| 
 | ||||
|     struct calendar_date_time date_time; | ||||
| 
 | ||||
|     watch_get_date_time(&date_time); | ||||
| 
 | ||||
|     uint16_t beats = clock2beats(date_time.time.hour, date_time.time.min, date_time.time.sec, UTC_OFFSET); | ||||
|     sprintf(buf, "bt  %04d  ", beats); | ||||
| 
 | ||||
|     watch_display_string(buf, 0); | ||||
| } | ||||
| 
 | ||||
| uint16_t clock2beats(uint16_t hours, uint16_t minutes, uint16_t seconds, int16_t utc_offset) { | ||||
|     uint32_t beats = seconds; | ||||
|     beats += 60 * minutes; | ||||
|     beats += (uint32_t)hours * 60 * 60; | ||||
|     beats += (utc_offset + 1) * 60 * 60; // offset from utc + 1 since beats in in UTC+1
 | ||||
| 
 | ||||
|     beats /= 86.4; // convert to beats
 | ||||
|     beats %= 1000; // truncate to 3 digits for overflow
 | ||||
| 
 | ||||
|     return (uint16_t) beats; | ||||
| } | ||||
| 
 | ||||
| void do_set_time_mode() { | ||||
|     struct calendar_date_time date_time; | ||||
| 
 | ||||
|     watch_get_date_time(&date_time); | ||||
|     watch_display_string("          ", 0); | ||||
|     switch (application_state.page) { | ||||
|         case 0: // hour
 | ||||
|             sprintf(buf, "ST t%2d", date_time.time.hour); | ||||
|             break; | ||||
|         case 1: // minute
 | ||||
|             sprintf(buf, "ST t  %02d", date_time.time.min); | ||||
|             break; | ||||
|         case 2: // second
 | ||||
|             sprintf(buf, "ST t    %02d", date_time.time.sec); | ||||
|             break; | ||||
|         case 3: // year
 | ||||
|             sprintf(buf, "ST d%2d", date_time.date.year - 2000); | ||||
|             break; | ||||
|         case 4: // month
 | ||||
|             sprintf(buf, "ST d  %02d", date_time.date.month); | ||||
|             break; | ||||
|         case 5: // day
 | ||||
|             sprintf(buf, "ST d    %02d", date_time.date.day); | ||||
|             break; | ||||
|     } | ||||
|     watch_display_string(buf, 0); | ||||
|     watch_set_pixel(1, 12); // required for T in position 1
 | ||||
| } | ||||
| 
 | ||||
| void set_time_mode_handle_primary_button() { | ||||
|     application_state.page++; | ||||
|     if (application_state.page == 6) application_state.page = 0; | ||||
| } | ||||
| 
 | ||||
| void set_time_mode_handle_secondary_button() { | ||||
|     struct calendar_date_time date_time; | ||||
|     watch_get_date_time(&date_time); | ||||
|     const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; | ||||
| 
 | ||||
|     switch (application_state.page) { | ||||
|         case 0: // hour
 | ||||
|             date_time.time.hour = (date_time.time.hour + 1) % 24; | ||||
|             break; | ||||
|         case 1: // minute
 | ||||
|             date_time.time.min = (date_time.time.min + 1) % 60; | ||||
|             break; | ||||
|         case 2: // second
 | ||||
|             date_time.time.sec = 0; | ||||
|             break; | ||||
|         case 3: // year
 | ||||
|             // only allow 2021-2030. fix this sometime next decade
 | ||||
|             date_time.date.year = ((date_time.date.year % 10) + 1) + 2020; | ||||
|             break; | ||||
|         case 4: // month
 | ||||
|             date_time.date.month = ((date_time.date.month + 1) % 12); | ||||
|             break; | ||||
|         case 5: // day
 | ||||
|             date_time.date.day = date_time.date.day + 1; | ||||
|             // can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th.
 | ||||
|             // and it should roll over.
 | ||||
|             if (date_time.date.day > days_in_month[date_time.date.month - 1]) { | ||||
|                 date_time.date.day = 1; | ||||
|             } | ||||
|             break; | ||||
|     } | ||||
|     watch_set_date_time(date_time); | ||||
| } | ||||
| 
 | ||||
| void cb_mode_pressed() { | ||||
|     application_state.mode = (application_state.mode + 1) % NUM_MODES; | ||||
|     application_state.mode_changed = true; | ||||
|     application_state.mode_ticks = 300; | ||||
|     application_state.page = 0; | ||||
| } | ||||
| 
 | ||||
| void cb_light_pressed() { | ||||
|     switch (application_state.mode) { | ||||
|         case MODE_SET: | ||||
|             set_time_mode_handle_secondary_button(); | ||||
|             break; | ||||
|         default: | ||||
|             application_state.light_ticks = 3; | ||||
|             break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void cb_alarm_pressed() { | ||||
|     switch (application_state.mode) { | ||||
|         case MODE_SET: | ||||
|             set_time_mode_handle_primary_button(); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void cb_tick() { | ||||
|     if (application_state.light_ticks > 0) { | ||||
|         application_state.light_ticks--; | ||||
|     } | ||||
|     if (application_state.mode_ticks > 0) { | ||||
|         application_state.mode_ticks--; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								apps/beats-time/make/.gitignore
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								apps/beats-time/make/.gitignore
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @ -0,0 +1 @@ | ||||
| build/ | ||||
							
								
								
									
										24
									
								
								apps/beats-time/make/Makefile
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										24
									
								
								apps/beats-time/make/Makefile
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,24 @@ | ||||
| # 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../ \
 | ||||
| 
 | ||||
| # 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 += \
 | ||||
|   ../app.c \
 | ||||
| 
 | ||||
| # Leave this line at the bottom of the file; it has all the targets for making your project.
 | ||||
| include $(TOP)/rules.mk | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user