diff options
| author | Joey Castillo <joeycastillo@utexas.edu> | 2022-01-15 19:21:39 -0500 | 
|---|---|---|
| committer | Joey Castillo <joeycastillo@utexas.edu> | 2022-01-15 19:23:49 -0500 | 
| commit | baf25aaa7a7f8ff673bbe805963b242c0eb52306 (patch) | |
| tree | 80124eb866f4b66153244dd9c1763a4f81efbf29 | |
| parent | 41eaa9c1c03ee70179d8c37c20b436b11dafb8ef (diff) | |
| download | Sensor-Watch-baf25aaa7a7f8ff673bbe805963b242c0eb52306.tar.gz Sensor-Watch-baf25aaa7a7f8ff673bbe805963b242c0eb52306.tar.bz2 Sensor-Watch-baf25aaa7a7f8ff673bbe805963b242c0eb52306.zip  | |
movement: add sunrise/sunset face
| -rw-r--r-- | movement/lib/sunriset/sunriset.c | 326 | ||||
| -rw-r--r-- | movement/lib/sunriset/sunriset.h | 95 | ||||
| -rwxr-xr-x | movement/make/Makefile | 3 | ||||
| -rw-r--r-- | movement/movement_config.h | 1 | ||||
| -rw-r--r-- | movement/watch_faces/complications/sunrise_sunset_face.c | 149 | ||||
| -rw-r--r-- | movement/watch_faces/complications/sunrise_sunset_face.h | 51 | 
6 files changed, 625 insertions, 0 deletions
diff --git a/movement/lib/sunriset/sunriset.c b/movement/lib/sunriset/sunriset.c new file mode 100644 index 00000000..9126c3bc --- /dev/null +++ b/movement/lib/sunriset/sunriset.c @@ -0,0 +1,326 @@ +/* + +SUNRISET.C - computes Sun rise/set times, start/end of twilight, and +             the length of the day at any date and latitude + +Written as DAYLEN.C, 1989-08-16 + +Modified to SUNRISET.C, 1992-12-01 + +(c) Paul Schlyter, 1989, 1992 + +Released to the public domain by Paul Schlyter, December 1992 + +*/ + +#include <stdio.h> +#include <math.h> +#include "sunriset.h" + + +/* A macro to compute the number of days elapsed since 2000 Jan 0.0 */ +/* (which is equal to 1999 Dec 31, 0h UT)                           */ + +#define days_since_2000_Jan_0(y,m,d) \ +    (367L*(y)-((7*((y)+(((m)+9)/12)))/4)+((275*(m))/9)+(d)-730530L) + +/* Some conversion factors between radians and degrees */ + +#ifndef PI + #define PI        3.1415926535897932384 +#endif + +#define RADEG     ( 180.0 / PI ) +#define DEGRAD    ( PI / 180.0 ) + +/* The trigonometric functions in degrees */ + +#define sind(x)  sin((x)*DEGRAD) +#define cosd(x)  cos((x)*DEGRAD) +#define tand(x)  tan((x)*DEGRAD) + +#define atand(x)    (RADEG*atan(x)) +#define asind(x)    (RADEG*asin(x)) +#define acosd(x)    (RADEG*acos(x)) +#define atan2d(y,x) (RADEG*atan2(y,x)) + +/* The "workhorse" function for sun rise/set times */ + +int __sunriset__( int year, int month, int day, double lon, double lat, +                  double altit, int upper_limb, double *trise, double *tset ) +/***************************************************************************/ +/* Note: year,month,date = calendar date, 1801-2099 only.             */ +/*       Eastern longitude positive, Western longitude negative       */ +/*       Northern latitude positive, Southern latitude negative       */ +/*       The longitude value IS critical in this function!            */ +/*       altit = the altitude which the Sun should cross              */ +/*               Set to -35/60 degrees for rise/set, -6 degrees       */ +/*               for civil, -12 degrees for nautical and -18          */ +/*               degrees for astronomical twilight.                   */ +/*         upper_limb: non-zero -> upper limb, zero -> center         */ +/*               Set to non-zero (e.g. 1) when computing rise/set     */ +/*               times, and to zero when computing start/end of       */ +/*               twilight.                                            */ +/*        *rise = where to store the rise time                        */ +/*        *set  = where to store the set  time                        */ +/*                Both times are relative to the specified altitude,  */ +/*                and thus this function can be used to compute       */ +/*                various twilight times, as well as rise/set times   */ +/* Return value:  0 = sun rises/sets this day, times stored at        */ +/*                    *trise and *tset.                               */ +/*               +1 = sun above the specified "horizon" 24 hours.     */ +/*                    *trise set to time when the sun is at south,    */ +/*                    minus 12 hours while *tset is set to the south  */ +/*                    time plus 12 hours. "Day" length = 24 hours     */ +/*               -1 = sun is below the specified "horizon" 24 hours   */ +/*                    "Day" length = 0 hours, *trise and *tset are    */ +/*                    both set to the time when the sun is at south.  */ +/*                                                                    */ +/**********************************************************************/ +{ +      double  d,  /* Days since 2000 Jan 0.0 (negative before) */ +      sr,         /* Solar distance, astronomical units */ +      sRA,        /* Sun's Right Ascension */ +      sdec,       /* Sun's declination */ +      sradius,    /* Sun's apparent radius */ +      t,          /* Diurnal arc */ +      tsouth,     /* Time when Sun is at south */ +      sidtime;    /* Local sidereal time */ + +      int rc = 0; /* Return cde from function - usually 0 */ + +      /* Compute d of 12h local mean solar time */ +      d = days_since_2000_Jan_0(year,month,day) + 0.5 - lon/360.0; + +      /* Compute the local sidereal time of this moment */ +      sidtime = revolution( GMST0(d) + 180.0 + lon ); + +      /* Compute Sun's RA, Decl and distance at this moment */ +      sun_RA_dec( d, &sRA, &sdec, &sr ); + +      /* Compute time when Sun is at south - in hours UT */ +      tsouth = 12.0 - rev180(sidtime - sRA)/15.0; + +      /* Compute the Sun's apparent radius in degrees */ +      sradius = 0.2666 / sr; + +      /* Do correction to upper limb, if necessary */ +      if ( upper_limb ) +            altit -= sradius; + +      /* Compute the diurnal arc that the Sun traverses to reach */ +      /* the specified altitude altit: */ +      { +            double cost; +            cost = ( sind(altit) - sind(lat) * sind(sdec) ) / +                  ( cosd(lat) * cosd(sdec) ); +            if ( cost >= 1.0 ) +                  rc = -1, t = 0.0;       /* Sun always below altit */ +            else if ( cost <= -1.0 ) +                  rc = +1, t = 12.0;      /* Sun always above altit */ +            else +                  t = acosd(cost)/15.0;   /* The diurnal arc, hours */ +      } + +      /* Store rise and set times - in hours UT */ +      *trise = tsouth - t; +      *tset  = tsouth + t; + +      return rc; +}  /* __sunriset__ */ + + + +/* The "workhorse" function */ + + +double __daylen__( int year, int month, int day, double lon, double lat, +                   double altit, int upper_limb ) +/**********************************************************************/ +/* Note: year,month,date = calendar date, 1801-2099 only.             */ +/*       Eastern longitude positive, Western longitude negative       */ +/*       Northern latitude positive, Southern latitude negative       */ +/*       The longitude value is not critical. Set it to the correct   */ +/*       longitude if you're picky, otherwise set to to, say, 0.0     */ +/*       The latitude however IS critical - be sure to get it correct */ +/*       altit = the altitude which the Sun should cross              */ +/*               Set to -35/60 degrees for rise/set, -6 degrees       */ +/*               for civil, -12 degrees for nautical and -18          */ +/*               degrees for astronomical twilight.                   */ +/*         upper_limb: non-zero -> upper limb, zero -> center         */ +/*               Set to non-zero (e.g. 1) when computing day length   */ +/*               and to zero when computing day+twilight length.      */ +/**********************************************************************/ +{ +      double  d,  /* Days since 2000 Jan 0.0 (negative before) */ +      obl_ecl,    /* Obliquity (inclination) of Earth's axis */ +      sr,         /* Solar distance, astronomical units */ +      slon,       /* True solar longitude */ +      sin_sdecl,  /* Sine of Sun's declination */ +      cos_sdecl,  /* Cosine of Sun's declination */ +      sradius,    /* Sun's apparent radius */ +      t;          /* Diurnal arc */ + +      /* Compute d of 12h local mean solar time */ +      d = days_since_2000_Jan_0(year,month,day) + 0.5 - lon/360.0; + +      /* Compute obliquity of ecliptic (inclination of Earth's axis) */ +      obl_ecl = 23.4393 - 3.563E-7 * d; + +      /* Compute Sun's ecliptic longitude and distance */ +      sunpos( d, &slon, &sr ); + +      /* Compute sine and cosine of Sun's declination */ +      sin_sdecl = sind(obl_ecl) * sind(slon); +      cos_sdecl = sqrt( 1.0 - sin_sdecl * sin_sdecl ); + +      /* Compute the Sun's apparent radius, degrees */ +      sradius = 0.2666 / sr; + +      /* Do correction to upper limb, if necessary */ +      if ( upper_limb ) +            altit -= sradius; + +      /* Compute the diurnal arc that the Sun traverses to reach */ +      /* the specified altitude altit: */ +      { +            double cost; +            cost = ( sind(altit) - sind(lat) * sin_sdecl ) / +                  ( cosd(lat) * cos_sdecl ); +            if ( cost >= 1.0 ) +                  t = 0.0;                      /* Sun always below altit */ +            else if ( cost <= -1.0 ) +                  t = 24.0;                     /* Sun always above altit */ +            else  t = (2.0/15.0) * acosd(cost); /* The diurnal arc, hours */ +      } +      return t; +}  /* __daylen__ */ + + +/* This function computes the Sun's position at any instant */ + +void sunpos( double d, double *lon, double *r ) +/******************************************************/ +/* Computes the Sun's ecliptic longitude and distance */ +/* at an instant given in d, number of days since     */ +/* 2000 Jan 0.0.  The Sun's ecliptic latitude is not  */ +/* computed, since it's always very near 0.           */ +/******************************************************/ +{ +      double M,         /* Mean anomaly of the Sun */ +             w,         /* Mean longitude of perihelion */ +                        /* Note: Sun's mean longitude = M + w */ +             e,         /* Eccentricity of Earth's orbit */ +             E,         /* Eccentric anomaly */ +             x, y,      /* x, y coordinates in orbit */ +             v;         /* True anomaly */ + +      /* Compute mean elements */ +      M = revolution( 356.0470 + 0.9856002585 * d ); +      w = 282.9404 + 4.70935E-5 * d; +      e = 0.016709 - 1.151E-9 * d; + +      /* Compute true longitude and radius vector */ +      E = M + e * RADEG * sind(M) * ( 1.0 + e * cosd(M) ); +            x = cosd(E) - e; +      y = sqrt( 1.0 - e*e ) * sind(E); +      *r = sqrt( x*x + y*y );              /* Solar distance */ +      v = atan2d( y, x );                  /* True anomaly */ +      *lon = v + w;                        /* True solar longitude */ +      if ( *lon >= 360.0 ) +            *lon -= 360.0;                   /* Make it 0..360 degrees */ +} + +void sun_RA_dec( double d, double *RA, double *dec, double *r ) +/******************************************************/ +/* Computes the Sun's equatorial coordinates RA, Decl */ +/* and also its distance, at an instant given in d,   */ +/* the number of days since 2000 Jan 0.0.             */ +/******************************************************/ +{ +      double lon, obl_ecl, x, y, z; + +      /* Compute Sun's ecliptical coordinates */ +      sunpos( d, &lon, r ); + +      /* Compute ecliptic rectangular coordinates (z=0) */ +      x = *r * cosd(lon); +      y = *r * sind(lon); + +      /* Compute obliquity of ecliptic (inclination of Earth's axis) */ +      obl_ecl = 23.4393 - 3.563E-7 * d; + +      /* Convert to equatorial rectangular coordinates - x is unchanged */ +      z = y * sind(obl_ecl); +      y = y * cosd(obl_ecl); + +      /* Convert to spherical coordinates */ +      *RA = atan2d( y, x ); +      *dec = atan2d( z, sqrt(x*x + y*y) ); + +}  /* sun_RA_dec */ + + +/******************************************************************/ +/* This function reduces any angle to within the first revolution */ +/* by subtracting or adding even multiples of 360.0 until the     */ +/* result is >= 0.0 and < 360.0                                   */ +/******************************************************************/ + +#define INV360    ( 1.0 / 360.0 ) + +double revolution( double x ) +/*****************************************/ +/* Reduce angle to within 0..360 degrees */ +/*****************************************/ +{ +      return( x - 360.0 * floor( x * INV360 ) ); +}  /* revolution */ + +double rev180( double x ) +/*********************************************/ +/* Reduce angle to within +180..+180 degrees */ +/*********************************************/ +{ +      return( x - 360.0 * floor( x * INV360 + 0.5 ) ); +}  /* revolution */ + + +/*******************************************************************/ +/* This function computes GMST0, the Greenwich Mean Sidereal Time  */ +/* at 0h UT (i.e. the sidereal time at the Greenwhich meridian at  */ +/* 0h UT).  GMST is then the sidereal time at Greenwich at any     */ +/* time of the day.  I've generalized GMST0 as well, and define it */ +/* as:  GMST0 = GMST - UT  --  this allows GMST0 to be computed at */ +/* other times than 0h UT as well.  While this sounds somewhat     */ +/* contradictory, it is very practical:  instead of computing      */ +/* GMST like:                                                      */ +/*                                                                 */ +/*  GMST = (GMST0) + UT * (366.2422/365.2422)                      */ +/*                                                                 */ +/* where (GMST0) is the GMST last time UT was 0 hours, one simply  */ +/* computes:                                                       */ +/*                                                                 */ +/*  GMST = GMST0 + UT                                              */ +/*                                                                 */ +/* where GMST0 is the GMST "at 0h UT" but at the current moment!   */ +/* Defined in this way, GMST0 will increase with about 4 min a     */ +/* day.  It also happens that GMST0 (in degrees, 1 hr = 15 degr)   */ +/* is equal to the Sun's mean longitude plus/minus 180 degrees!    */ +/* (if we neglect aberration, which amounts to 20 seconds of arc   */ +/* or 1.33 seconds of time)                                        */ +/*                                                                 */ +/*******************************************************************/ + +double GMST0( double d ) +{ +      double sidtim0; +      /* Sidtime at 0h UT = L (Sun's mean longitude) + 180.0 degr  */ +      /* L = M + w, as defined in sunpos().  Since I'm too lazy to */ +      /* add these numbers, I'll let the C compiler do it for me.  */ +      /* Any decent C compiler will add the constants at compile   */ +      /* time, imposing no runtime or code overhead.               */ +      sidtim0 = revolution( ( 180.0 + 356.0470 + 282.9404 ) + +                          ( 0.9856002585 + 4.70935E-5 ) * d ); +      return sidtim0; +}  /* GMST0 */
\ No newline at end of file diff --git a/movement/lib/sunriset/sunriset.h b/movement/lib/sunriset/sunriset.h new file mode 100644 index 00000000..f8b97e32 --- /dev/null +++ b/movement/lib/sunriset/sunriset.h @@ -0,0 +1,95 @@ +/* + +SUNRISET.H - computes Sun rise/set times, start/end of twilight, and +             the length of the day at any date and latitude + +Written as DAYLEN.C, 1989-08-16 + +Modified to SUNRISET.C, 1992-12-01 + +(c) Paul Schlyter, 1989, 1992 + +Released to the public domain by Paul Schlyter, December 1992 + +*/ + +#ifndef SUNRISET_H_ +#define SUNRISET_H_ + +/* Function prototypes */ + +double __daylen__( int year, int month, int day, double lon, double lat, +                   double altit, int upper_limb ); + +int __sunriset__( int year, int month, int day, double lon, double lat, +                  double altit, int upper_limb, double *rise, double *set ); + +void sunpos( double d, double *lon, double *r ); + +void sun_RA_dec( double d, double *RA, double *dec, double *r ); + +double revolution( double x ); + +double rev180( double x ); + +double GMST0( double d ); + + +/* Following are some macros around the "workhorse" function __daylen__ */ +/* They mainly fill in the desired values for the reference altitude    */ +/* below the horizon, and also selects whether this altitude should     */ +/* refer to the Sun's center or its upper limb.                         */ + + +/* This macro computes the length of the day, from sunrise to sunset. */ +/* Sunrise/set is considered to occur when the Sun's upper limb is    */ +/* 35 arc minutes below the horizon (this accounts for the refraction */ +/* of the Earth's atmosphere).                                        */ +#define day_length(year,month,day,lon,lat)  \ +        __daylen__( year, month, day, lon, lat, -35.0/60.0, 1 ) + +/* This macro computes the length of the day, including civil twilight. */ +/* Civil twilight starts/ends when the Sun's center is 6 degrees below  */ +/* the horizon.                                                         */ +#define day_civil_twilight_length(year,month,day,lon,lat)  \ +        __daylen__( year, month, day, lon, lat, -6.0, 0 ) + +/* This macro computes the length of the day, incl. nautical twilight.  */ +/* Nautical twilight starts/ends when the Sun's center is 12 degrees    */ +/* below the horizon.                                                   */ +#define day_nautical_twilight_length(year,month,day,lon,lat)  \ +        __daylen__( year, month, day, lon, lat, -12.0, 0 ) + +/* This macro computes the length of the day, incl. astronomical twilight. */ +/* Astronomical twilight starts/ends when the Sun's center is 18 degrees   */ +/* below the horizon.                                                      */ +#define day_astronomical_twilight_length(year,month,day,lon,lat)  \ +        __daylen__( year, month, day, lon, lat, -18.0, 0 ) + + +/* This macro computes times for sunrise/sunset.                      */ +/* Sunrise/set is considered to occur when the Sun's upper limb is    */ +/* 35 arc minutes below the horizon (this accounts for the refraction */ +/* of the Earth's atmosphere).                                        */ +#define sun_rise_set(year,month,day,lon,lat,rise,set)  \ +        __sunriset__( year, month, day, lon, lat, -35.0/60.0, 1, rise, set ) + +/* This macro computes the start and end times of civil twilight.       */ +/* Civil twilight starts/ends when the Sun's center is 6 degrees below  */ +/* the horizon.                                                         */ +#define civil_twilight(year,month,day,lon,lat,start,end)  \ +        __sunriset__( year, month, day, lon, lat, -6.0, 0, start, end ) + +/* This macro computes the start and end times of nautical twilight.    */ +/* Nautical twilight starts/ends when the Sun's center is 12 degrees    */ +/* below the horizon.                                                   */ +#define nautical_twilight(year,month,day,lon,lat,start,end)  \ +        __sunriset__( year, month, day, lon, lat, -12.0, 0, start, end ) + +/* This macro computes the start and end times of astronomical twilight.   */ +/* Astronomical twilight starts/ends when the Sun's center is 18 degrees   */ +/* below the horizon.                                                      */ +#define astronomical_twilight(year,month,day,lon,lat,start,end)  \ +        __sunriset__( year, month, day, lon, lat, -18.0, 0, start, end ) + +#endif // SUNRISET_H_ diff --git a/movement/make/Makefile b/movement/make/Makefile index 4910b102..00a086d0 100755 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -17,6 +17,7 @@ INCLUDES += \    -I../watch_faces/thermistor/ \    -I../watch_faces/demos/ \    -I../lib/TOTP-MCU/ \ +  -I../lib/sunriset/ \  # 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. @@ -27,6 +28,7 @@ INCLUDES += \  SRCS += \    ../lib/TOTP-MCU/sha1.c \    ../lib/TOTP-MCU/TOTP.c \ +  ../lib/sunriset/sunriset.c \    ../movement.c \    ../watch_faces/clock/simple_clock_face.c \    ../watch_faces/clock/world_clock_face.c \ @@ -45,6 +47,7 @@ SRCS += \    ../watch_faces/complications/day_one_face.c \    ../watch_faces/complications/stopwatch_face.c \    ../watch_faces/complications/totp_face.c \ +  ../watch_faces/complications/sunrise_sunset_face.c \  # Leave this line at the bottom of the file; it has all the targets for making your project.  include $(TOP)/rules.mk diff --git a/movement/movement_config.h b/movement/movement_config.h index 7896f050..f1bed942 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -41,6 +41,7 @@  #include "lis2dh_logging_face.h"  #include "demo_face.h"  #include "hello_there_face.h" +#include "sunrise_sunset_face.h"  const watch_face_t watch_faces[] = {      simple_clock_face, diff --git a/movement/watch_faces/complications/sunrise_sunset_face.c b/movement/watch_faces/complications/sunrise_sunset_face.c new file mode 100644 index 00000000..035fd2cf --- /dev/null +++ b/movement/watch_faces/complications/sunrise_sunset_face.c @@ -0,0 +1,149 @@ +/* + * MIT License + * + * Copyright (c) 2022 Joey Castillo + * + * 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. + * + * Sunrise/sunset calculations are public domain code by Paul Schlyter, December 1992 + * + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include "sunrise_sunset_face.h" +#include "watch.h" +#include "watch_utility.h" +#include "sunriset.h" + +static void _sunrise_sunset_face_update() { +    char buf[14]; +    double rise, set, minutes; +    // TODO: allow user to set location, using London for now. +    double lat = 51.509865; +    double lon = -0.118092; +    // TODO: account for time zone, currently only operates in GMT. +    watch_date_time date_time = watch_rtc_get_date_time(); // the current date / time +    watch_date_time scratch_time; // scratchpad, contains different values at different times +    scratch_time.reg = date_time.reg; +         +    for(int i = 0; i < 2; i++) { +        uint8_t result = sun_rise_set(scratch_time.unit.year + WATCH_RTC_REFERENCE_YEAR, scratch_time.unit.month, scratch_time.unit.day, lon, lat, &rise, &set); + +        if (result != 0) { +            watch_clear_colon(); +            watch_clear_indicator(WATCH_INDICATOR_PM); +            watch_clear_indicator(WATCH_INDICATOR_24H); +            sprintf(buf, "%s%d none ", (result == 1) ? "SE" : "rI", scratch_time.unit.day); +            watch_display_string(buf, 0); +            return; +        } + +        watch_set_colon(); +        // TODO: account for user's 12H/24H preference +        watch_set_indicator(WATCH_INDICATOR_24H); + +        minutes = 60.0 * fmod(rise, 1); +        scratch_time.unit.hour = floor(rise); +        scratch_time.unit.minute = floor(minutes); +        scratch_time.unit.second = 60.0 * fmod(minutes, 1); + +        if (date_time.reg < scratch_time.reg) { +            // display today's sunrise, it hasn't happened yet +            sprintf(buf, "rI%2d%2d%02d%02d", scratch_time.unit.day, scratch_time.unit.hour, scratch_time.unit.minute, scratch_time.unit.second); +            watch_display_string(buf, 0); +            return; +        } + +        minutes = 60.0 * fmod(set, 1); +        scratch_time.unit.hour = floor(set); +        scratch_time.unit.minute = floor(minutes); +        scratch_time.unit.second = 60.0 * fmod(minutes, 1); + +        if (date_time.reg < scratch_time.reg) { +            // display today's sunset, it hasn't happened yet +            sprintf(buf, "SE%2d%02d%02d%02d", scratch_time.unit.day, scratch_time.unit.hour, scratch_time.unit.minute, scratch_time.unit.second); +            watch_display_string(buf, 0); +            return; +        } + +        // it's after sunset. we need to display sunrise for tomorrow. +        uint32_t timestamp = watch_utility_date_time_to_unix_time(date_time, 0); +        timestamp += 86400; +        scratch_time = watch_utility_date_time_from_unix_time(timestamp, 0); +    } +} + +void sunrise_sunset_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(sunrise_sunset_state_t)); +        memset(*context_ptr, 0, sizeof(sunrise_sunset_state_t)); +    } +} + +void sunrise_sunset_face_activate(movement_settings_t *settings, void *context) { +    (void) settings; +    sunrise_sunset_state_t *state = (sunrise_sunset_state_t *)context; +    movement_location_t movement_location = (movement_location_t) watch_get_backup_data(1); +    state->latitude = movement_location.bit.latitude; +    state->longitude = movement_location.bit.longitude; +} + +bool sunrise_sunset_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { +    (void) settings; +    (void) context; + +    switch (event.event_type) { +        case EVENT_ACTIVATE: +            break; +        case EVENT_LOW_ENERGY_UPDATE: +        case EVENT_TICK: +            _sunrise_sunset_face_update(); +            break; +        case EVENT_MODE_BUTTON_UP: +            movement_move_to_next_face(); +            break; +        case EVENT_LIGHT_BUTTON_DOWN: +            movement_illuminate_led(); +            break; +        case EVENT_LIGHT_BUTTON_UP: +            break; +        case EVENT_ALARM_BUTTON_UP: +            break; +        case EVENT_ALARM_LONG_PRESS: +            // TODO: settings mode, to set the user's location. +            break; +        case EVENT_TIMEOUT: +            // TODO: return home if we're on a settings page. +        default: +            break; +    } + +    return true; +} + +void sunrise_sunset_face_resign(movement_settings_t *settings, void *context) { +    (void) settings; +    (void) context; + +    movement_request_tick_frequency(1); +} diff --git a/movement/watch_faces/complications/sunrise_sunset_face.h b/movement/watch_faces/complications/sunrise_sunset_face.h new file mode 100644 index 00000000..625a0fe3 --- /dev/null +++ b/movement/watch_faces/complications/sunrise_sunset_face.h @@ -0,0 +1,51 @@ +/* + * MIT License + * + * Copyright (c) 2022 Joey Castillo + * + * 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 SUNRISE_SUNSET_FACE_H_ +#define SUNRISE_SUNSET_FACE_H_ + +#include "movement.h" + +// The Day One face is designed to count upwards from the wearer's date of birth. It also functions as an +// interface for setting the birth date register, which other watch faces can use for various purposes. + +typedef struct { +    uint16_t latitude; +    uint16_t longitude; +} sunrise_sunset_state_t; + +void sunrise_sunset_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr); +void sunrise_sunset_face_activate(movement_settings_t *settings, void *context); +bool sunrise_sunset_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void sunrise_sunset_face_resign(movement_settings_t *settings, void *context); + +static const watch_face_t sunrise_sunset_face = { +    sunrise_sunset_face_setup, +    sunrise_sunset_face_activate, +    sunrise_sunset_face_loop, +    sunrise_sunset_face_resign, +    NULL +}; + +#endif // SUNRISE_SUNSET_FACE_H_  | 
