Host C Specs


Directory: src/c/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 29 / 0 / 29
Functions: 100.0% 5 / 0 / 5
Branches: 100.0% 14 / 0 / 14

core/clock/moon.c
Line Branch Exec Source
1 /**
2 * @file moon.c
3 * @brief Pure moon-phase math, host-testable off-device.
4 *
5 * @ingroup lib_core
6 */
7 #include "clock/moon.h"
8
9 18 int32_t moon_age_sec(time_t utc)
10 {
11 // the offset from the epoch fits 32 bits until 2068 which outlives the watch.
12 // staying in 32 bits keeps the 64 bit division helpers out of the binary
13 18 int32_t age = (int32_t)(utc - MOON_EPOCH_UTC) % MOON_SYNODIC_SEC;
14
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 17 times.
18 if (age < 0)
15 {
16 1 age += MOON_SYNODIC_SEC;
17 }
18
19 18 return age;
20 }
21
22 6 int moon_glyph_index(time_t utc, int count)
23 {
24
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (count <= 0)
25 {
26 2 return 0;
27 }
28
29 // round the age to the nearest of count evenly spaced glyphs around the ring.
30 // age times count tops out around 71 million for the 28 glyph ring so int32 holds it
31 4 int32_t age = moon_age_sec(utc);
32 4 int idx = (int)(((age * count) + MOON_SYNODIC_SEC / 2) / MOON_SYNODIC_SEC);
33 4 return idx % count;
34 }
35
36 3 int moon_illumination_pct(time_t utc)
37 {
38 3 int32_t age = moon_age_sec(utc);
39 3 int32_t half = MOON_SYNODIC_SEC / 2;
40
41 // a triangle from new to full and back. not the true cosine curve, but close enough
42 // for a percent readout and it stays pure integer math
43 5 int32_t lit = age <= half ? (age * 100) / half
44
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 : ((MOON_SYNODIC_SEC - age) * 100) / half;
45 3 return (int)lit;
46 }
47
48 8 int moon_days_to_phase(time_t utc, bool to_full)
49 {
50
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 int32_t target = to_full ? MOON_SYNODIC_SEC / 2 : MOON_SYNODIC_SEC;
51 8 int32_t until = target - moon_age_sec(utc);
52
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
8 if (until < 0)
53 {
54 // just past the target so the next one is almost a whole cycle away
55 3 until += MOON_SYNODIC_SEC;
56 }
57
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 7 times.
8 if (until >= MOON_SYNODIC_SEC)
58 {
59 // right on the new moon the age is 0, which puts the target a whole cycle out
60 1 until -= MOON_SYNODIC_SEC;
61 }
62
63 // half a day either side of the moon counts as now. a moon that was full six hours ago is
64 // still tonight's, and rounding a nearly whole cycle would read 30
65
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 7 times.
8 if (until > MOON_SYNODIC_SEC - 43200)
66 {
67 1 return 0;
68 }
69
70 // whole days rounded to the nearest so half a day out still reads right
71 7 return (int)((until + 43200) / 86400);
72 }
73
74 2 const char *moon_phase_name(time_t utc)
75 {
76 static const char *names[8] = {
77 "NEW", "WAX CRES", "1ST QTR", "WAX GIB",
78 "FULL", "WAN GIB", "3RD QTR", "WAN CRES",
79 };
80
81 2 return names[moon_glyph_index(utc, 8)];
82 }
83