summaryrefslogtreecommitdiffstats
path: root/stm32/app/time_fn.c
diff options
context:
space:
mode:
Diffstat (limited to 'stm32/app/time_fn.c')
-rw-r--r--stm32/app/time_fn.c650
1 files changed, 650 insertions, 0 deletions
diff --git a/stm32/app/time_fn.c b/stm32/app/time_fn.c
new file mode 100644
index 0000000..825d90f
--- /dev/null
+++ b/stm32/app/time_fn.c
@@ -0,0 +1,650 @@
+#include <math.h>
+#include "project.h"
+
+static int is_leap (unsigned year)
+{
+ if (year % 4)
+ return 0;
+
+ if (year % 100)
+ return 1;
+
+ if (year % 400)
+ return 0;
+
+ return 1;
+}
+
+EPOCH time_epoch_sub (EPOCH a, EPOCH b)
+{
+ EPOCH ret;
+
+ ret.ns = a.ns - b.ns;
+ ret.s = a.s - b.s;
+
+ if (!ret.s) return ret;
+
+ if (ret.ns < 0) {
+ ret.s--;
+ ret.ns += 1000000000;
+ }
+
+ return ret;
+}
+
+
+EPOCH time_epoch_add (EPOCH a, EPOCH b)
+{
+ EPOCH ret;
+
+ ret.ns = a.ns + b.ns;
+ ret.s = a.s + b.s;
+
+ while (ret.ns > 1000000000) {
+ ret.s++;
+ ret.ns -= 1000000000;
+ }
+
+ return ret;
+}
+
+
+UTC time_epoch_to_utc (EPOCH epoch)
+{
+ UTC u = {0};
+ uint64_t day;
+ unsigned y400, y100, y4;
+
+ day = epoch.s / 86400;
+ epoch.s -= day * 86400;
+
+ day += 134774;
+
+ u.wday = day % 7;
+ u.wday++;
+
+
+ y400 = day / 146097; /*146097 days in 400 years */
+ day -= (y400 * 146097);
+
+ y100 = day / 36524; /*36524 days in 100 years */
+ day -= (y100 * 36524);
+
+ y4 = day / 1461; /*1461 days in 4 years */
+ day -= (y4 * 1461);
+
+ /* This may look redundant but 31 Dec in year 4 is special case */
+ if (day < 1095) { /*1095 days in 3 years */
+ u.year = day / 365; /*365 days in a year */
+ day -= (365 * u.year);
+ } else {
+ u.year = 3;
+ day -= 1095;
+ }
+
+
+ /* Now put it all back together */
+ u.year += 1601;
+ u.year += 4 * y4;
+ u.year += 100 * y100;
+ u.year += 400 * y400;
+
+
+ u.jday = day + 1;
+
+ u.is_leap = is_leap (u.year);
+
+
+ if (!u.is_leap) {
+ /*Days and months for ordinary years */
+ if (u.jday < 32) {
+ u.month = 1;
+ u.mday = u.jday;
+ } else if (u.jday < 60) {
+ u.month = 2;
+ u.mday = u.jday - 31;
+ } else if (u.jday < 91) {
+ u.month = 3;
+ u.mday = u.jday - 59;
+ } else if (u.jday < 121) {
+ u.month = 4;
+ u.mday = u.jday - 90;
+ } else if (u.jday < 152) {
+ u.month = 5;
+ u.mday = u.jday - 120;
+ } else if (u.jday < 182) {
+ u.month = 6;
+ u.mday = u.jday - 151;
+ } else if (u.jday < 213) {
+ u.month = 7;
+ u.mday = u.jday - 181;
+ } else if (u.jday < 244) {
+ u.month = 8;
+ u.mday = u.jday - 212;
+ } else if (u.jday < 274) {
+ u.month = 9;
+ u.mday = u.jday - 243;
+ } else if (u.jday < 305) {
+ u.month = 10;
+ u.mday = u.jday - 273;
+ } else if (u.jday < 335) {
+ u.month = 11;
+ u.mday = u.jday - 304;
+ } else {
+ u.month = 12;
+ u.mday = u.jday - 334;
+ }
+ } else {
+ /*And leap years */
+ if (u.jday < 32) {
+ u.month = 1;
+ u.mday = u.jday;
+ } else if (u.jday < 61) {
+ u.month = 2;
+ u.mday = u.jday - 31;
+ } else if (u.jday < 92) {
+ u.month = 3;
+ u.mday = u.jday - 60;
+ } else if (u.jday < 122) {
+ u.month = 4;
+ u.mday = u.jday - 91;
+ } else if (u.jday < 153) {
+ u.month = 5;
+ u.mday = u.jday - 121;
+ } else if (u.jday < 183) {
+ u.month = 6;
+ u.mday = u.jday - 152;
+ } else if (u.jday < 214) {
+ u.month = 7;
+ u.mday = u.jday - 182;
+ } else if (u.jday < 245) {
+ u.month = 8;
+ u.mday = u.jday - 213;
+ } else if (u.jday < 275) {
+ u.month = 9;
+ u.mday = u.jday - 244;
+ } else if (u.jday < 306) {
+ u.month = 10;
+ u.mday = u.jday - 274;
+ } else if (u.jday < 336) {
+ u.month = 11;
+ u.mday = u.jday - 305;
+ } else {
+ u.month = 12;
+ u.mday = u.jday - 335;
+ }
+ }
+
+ u.hour = epoch.s / 3600;
+ epoch.s -= u.hour * 3600;
+ u.minute = epoch.s / 60;
+ epoch.s -= u.minute * 60;
+ u.second = epoch.s;
+
+ u.nanosecond = epoch.ns;
+
+ return u;
+}
+
+EPOCH time_utc_to_epoch (UTC u)
+{
+ unsigned y400;
+ unsigned y100;
+ unsigned y4;
+
+ EPOCH ret;
+
+ static int const mdays[] =
+ { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ static int const lmdays[] =
+ { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
+
+ u.is_leap = is_leap (u.year);
+
+ if (u.year < 100) u.year += 2000;
+
+
+ if (!u.jday) {
+ if (u.is_leap)
+ u.jday = u.mday + lmdays[u.month];
+ else
+ u.jday = u.mday + mdays[u.month];
+ }
+
+ u.year -= 1601;
+ y400 = u.year / 400;
+ u.year -= y400 * 400;
+ y100 = u.year / 100;
+ u.year -= y100 * 100;
+ y4 = u.year / 4;
+ u.year -= y4 * 4;
+
+
+
+ ret.s = u.jday - 1;
+ ret.s += u.year * 365;
+ ret.s += y4 * 1461;
+ ret.s += y100 * 36524;
+ ret.s += y400 * 146097;
+
+ ret.s -= 134774;
+
+ ret.s *= 86400;
+
+ ret.s += u.second;
+ ret.s += u.minute * 60;
+ ret.s += u.hour * 3600;
+
+ ret.ns = u.nanosecond;
+
+ return ret;
+}
+
+void utc_to_str (char *dst, UTC *u)
+{
+ const char *dname[] = {"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat", "Sun"};
+ const char *mname[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ sprintf (dst, "%s %04d-%s-%02d %02d:%02d:%02d.%09d", dname[u->wday], u->year, mname[u->month], u->mday, u->hour, u->minute, u->second, u->nanosecond);
+}
+
+
+void time_print_utc (const char *p, UTC *u, const char *t)
+{
+ const char *dname[] = {"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat", "Sun"};
+ const char *mname[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ printf ("%s%s %04d-%s-%02d %02d:%02d:%02d.%09d %s\r\n", p ? p : "", dname[u->wday], u->year, mname[u->month], u->mday, u->hour, u->minute, u->second, u->nanosecond, t ? t : "");
+}
+
+void time_print_epoch (const char *p, EPOCH e, const char *t)
+{
+ UTC u = time_epoch_to_utc (e);
+ time_print_utc (p, &u, t);
+}
+
+
+double
+time_utc_to_tjd (UTC u)
+{
+ unsigned y400;
+ unsigned y100;
+ unsigned y4;
+
+ double ret;
+ unsigned jd;
+
+ static int const mdays[] =
+ { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ static int const lmdays[] =
+ { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
+
+ u.is_leap = is_leap (u.year);
+
+ if (u.year < 100)
+ u.year += 2000;
+
+
+ if (!u.jday) {
+ if (u.is_leap)
+ u.jday = u.mday + lmdays[u.month];
+ else
+ u.jday = u.mday + mdays[u.month];
+ }
+
+ u.year -= 1601;
+ y400 = u.year / 400;
+ u.year -= y400 * 400;
+ y100 = u.year / 100;
+ u.year -= y100 * 100;
+ y4 = u.year / 4;
+ u.year -= y4 * 4;
+
+ jd = u.jday - 1;
+ jd += u.year * 365;
+ jd += y4 * 1461;
+ jd += y100 * 36524;
+ jd += y400 * 146097;
+
+
+ jd += 2305813;
+ jd -= 2451545;
+
+
+
+ ret = (double) u.nanosecond;
+ ret /= 1000000000.;
+ ret += (double) u.second;
+ ret /= 60.;
+ ret += (double) u.minute;
+ ret /= 60.;
+ ret += (double) u.hour;
+ ret /= 24.;
+
+ ret += .5;
+
+ ret += (double) jd;
+
+ return ret;
+}
+
+
+EPOCH time_tjd_to_epoch (double tjd)
+{
+ EPOCH e;
+
+
+ tjd -= 2440587.5;
+
+ tjd *= 86400.;
+ e.s = (uint64_t) floor (tjd);
+
+ tjd -= (double) e.s;
+
+ tjd *= 1000000000.;
+ e.ns = (unsigned) floor (tjd);
+
+ return e;
+}
+
+UTC time_tjd_to_utc (double tjd)
+{
+ return time_epoch_to_utc (time_tjd_to_epoch (tjd));
+}
+
+
+
+RA ra_normalize (RA r)
+{
+
+ while (r.ra < 0.) {
+ r.ra += 360.;
+ r.days--;
+ }
+
+ if (r.ra >= 3600.0) {
+ r.days = (unsigned) (floor (r.ra / 360.) + .5);
+ r.ra = remainder (r.ra, 360.);
+ } else while (r.ra >= 360.0) {
+ r.ra -= 360.;
+ r.days++;
+ }
+
+ return r;
+}
+
+
+RA time_utc_to_ra (UTC u)
+{
+ RA r;
+ double tjd = time_utc_to_tjd (u);
+ double T = tjd / 36525.;
+
+ r.ra =
+ 280.46061837 + (360.98564736629 * tjd) + (0.000387933 * T * T) -
+ (T * T * T / 38710000.0);
+
+ r.days = 0;
+
+ return ra_normalize (r);
+}
+
+
+
+RA time_st_to_ra (ST st)
+{
+ RA r;
+ unsigned i;
+
+ r.days = st.days;
+
+ i = st.hour;
+ i *= 60;
+ i += st.minute;
+ i *= 60;
+ i += st.second;
+
+ r.ra = (double) st.nanosecond;
+ r.ra /= 1000000000.;
+ r.ra += (double) i;
+
+ r.ra /= 240.;
+
+ return r;
+}
+
+
+
+ST
+time_ra_to_st (RA r)
+{
+ ST ret;
+ unsigned i;
+
+ r = ra_normalize (r);
+
+ ret.days = r.days;
+
+ r.ra *= 240.0;
+
+ i = (int) (floor (r.ra) + .5);
+ r.ra -= (double) i;
+ r.ra *= 1000000000.;
+
+ ret.nanosecond = (unsigned) (r.ra + .5);
+ ret.second = i % 60;
+ i /= 60;
+ ret.minute = i % 60;
+ i /= 60;
+ ret.hour = i;
+
+
+ return ret;
+}
+
+
+
+ST time_utc_to_lst (UTC u, double lon)
+{
+ RA r;
+
+ r = time_utc_to_ra (u);
+
+ r.ra += lon;
+
+ return time_ra_to_st (r);
+}
+
+
+
+#if 0
+int time_ra_cmp (double a, double b)
+{
+ return (ra_normalize (a - b) < 180.) ? -1 : 1;;
+}
+
+
+/*Find the next occuring time for RA tra */
+
+static int test_side (EPOCH m, double tra)
+{
+
+ double ra;
+ UTC u;
+
+ u = time_epoch_to_utc (m);
+ ra = time_utc_to_ra (u);
+
+ return time_ra_cmp (ra, tra);
+}
+
+
+EPOCH time_ra_to_next_epoch (EPOCH l, double tra)
+{
+ EPOCH r, m;
+ unsigned n;
+
+ int dog = 48;
+
+ printf ("time_ra_to_next_epoch %.9f\n", tra);
+
+ /* XXX: we should use newton raphson, but */
+ /* 1) we're on team hooke */
+ /* 2) we want to limit the domain of solutions */
+ /* So IB works better */
+
+
+ while ((test_side (l, tra) != 1) && dog--)
+ l.s += 3600;
+
+ r = l;
+
+ while ((test_side (r, tra) != -1) && dog--)
+ r.s += 3600;
+
+ for (n = 0; n < 64; ++n) {
+
+ m = time_epoch_sub (r, l);
+
+ if (m.s < 0) {
+ m.s = 0;
+ m.ns = 0;
+ break;
+ }
+
+ if (m.s & 1)
+ m.ns += 1000000000;
+
+ m.s /= 2;
+ m.ns /= 2;
+
+ m = time_epoch_add (l, m);
+
+ if (test_side (m, tra) < 0)
+ r = m;
+ else
+ l = m;
+ }
+
+ return m;
+}
+
+#endif
+
+
+
+
+
+/*
+ * Returns the EPOCH for the start of the metric year which
+ * starts in the custumary year y
+ *
+ * the metric year begins on the autumnal equinox (at the paris observatory natch.)
+ */
+static EPOCH start_of_year (unsigned y)
+{
+ double tjd = autumnal_equinox (y);
+ UTC u;
+
+ tjd += (2.3372305555 / 360); /* Offset of paris meridian from greenwich */
+
+ u = time_tjd_to_utc (tjd);
+
+ u.hour =
+ u.minute =
+ u.second =
+ u.nanosecond = 0;
+
+ return time_utc_to_epoch (u);
+}
+
+MTIME time_to_metric (EPOCH e, UTC u)
+{
+ MTIME ret;
+
+ static EPOCH year_start, year_end;
+ static unsigned year;
+
+ unsigned s;
+ unsigned d;
+
+ double fd;
+
+ EPOCH equinox;
+
+ if ((e.s > year_end.s) || (e.s < year_start.s)) {
+ /*calculate the equinox in this customary year */
+
+ equinox = start_of_year (u.year);
+
+ if (e.s < equinox.s) {
+ year_start = start_of_year (u.year - 1);
+ year_end = equinox;
+ year = u.year - 1792;
+ } else {
+ year_start = equinox;
+ year_end = start_of_year (u.year + 1);
+ year = u.year - 1791;
+ }
+ }
+
+ ret.year = year;
+
+ e = time_epoch_sub (e, year_start);
+ s = e.s;
+ d = s / 86400;
+ s -= d * 86400;
+
+ ret.jday = d;
+
+ ret.month = (d / 30) + 1;
+ ret.mday = (d % 30) + 1;
+ ret.wday = d % 10;
+
+ /* Now for the horror of time of day */
+
+ fd = (double) e.ns;
+ fd /= 1000000000.;
+ fd += (double) s;
+ fd /= 86400.;
+ fd *= 100000;
+
+ s = (int) fd;
+ fd -= (double) s;
+ fd *= 1000000000.;
+
+ ret.nanosecond = (int) fd;
+
+ ret.second = s % 100;
+ s -= ret.second;
+ s /= 100;
+
+ ret.minute = s % 100;
+ s -= ret.minute;
+ s /= 100;
+
+ ret.hour = s;
+
+ return ret;
+}
+
+
+MTIME time_utc_to_metric (UTC u)
+{
+ return time_to_metric (time_utc_to_epoch (u), u);
+}
+
+
+MTIME time_epoch_to_metric (EPOCH e)
+{
+ return time_to_metric (e, time_epoch_to_utc (e));
+}
+
+
+
+void time_print_metric (const char *p, MTIME *m, const char *t)
+{
+ const char *dname[] = {"Pri", "Duo", "Tri", "Qua", "Qui", "Sex", "Sep", "Oct", "Non", "Dec" };
+ const char *mname[] = {"", "Ven", "Bru", "Fri", "Niv", "Plu", "Ven", "Ger", "Flo", "Pra", "Mes", "The", "Fru", "San"};
+ printf ("%s%s %03d-%s-%02d %01d:%02d:%02d.%09d %s\r\n", p ? p : "", dname[m->wday], m->year, mname[m->month], m->mday, m->hour, m->minute, m->second, m->nanosecond, t ? t : "");
+}
+
+