Astro pack: sun / moon / Maidenhead / lat-lon display modes#6
Draft
peterlewis wants to merge 3 commits into
Draft
Astro pack: sun / moon / Maidenhead / lat-lon display modes#6peterlewis wants to merge 3 commits into
peterlewis wants to merge 3 commits into
Conversation
39b1e79 to
de7fb99
Compare
Five GPS-derived astronomy read-outs, each opt-in via a MODE_* config key and shown on the 10-char date row while the live clock keeps running on the time row (SATVIEW-style, COUNT_NORMAL): MODE_SUN sunrise / sunset / solar noon (local), auto-paged MODE_SUN_AZEL sun azimuth & elevation, now MODE_MOON moon phase index (0-7) + illuminated % MODE_GRID Maidenhead grid locator MODE_LATLON latitude / longitude, auto-paged The astronomy maths is a self-contained Core/Src/astro.c (+ astro.h): low- precision NOAA/Meeus sun alt-az and event times, moon phase, equation of time, and Maidenhead. It has no firmware dependencies, so it unit-tests natively (test/test_astro.c, 45 reference vectors) and was validated to ~1e-5 before touching the firmware. The L4 has only a single-precision FPU, so the double maths would be slow soft- float. It is therefore computed in the main loop (astro_update(), gated on the active mode exactly as measure_vbat() is for MODE_VBAT) and swapped into a cache under a brief __disable_irq() mask; the sendDate() cases that run inside the SysTick ISR only format the cached scalars -- no trig in the interrupt. Modes are disabled by default; with no GPS fix they use fake_latitude/longitude if set, else show "----". config.txt documents the keys and the moon-phase index legend. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
"LAT 51.48" vs "LAT-51.48" let the minus swallow the separator. Add a sign
slot after the label space — "LAT 51.48" / "LAT -51.48" — so the digits
start in the same column either way, matching the RISE/SET layout. A 3-digit
longitude can't fit both the separator and the slot in 10 characters, so the
separator alone is dropped there ("LON-179.99").
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 5, 2026
The paged modes (SUN, LATLON) previously flipped sub-screen every 2 s hard-coded. Make the dwell a config key (page_ms, ms; unset -> 5500, floored at 250 so a tiny value can't flood the date-board UART), driven off uwTick, and repaint the moment a page flips rather than waiting for the 1 Hz date-row refresh (guarded by decisec!=9 to avoid racing the SysTick sendDate). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Five new display modes, each disabled by default and enabled individually with a
MODE_*key inconfig.txt, exactly like the existing modes. They follow theMODE_SATVIEWpattern: the read-out shows on the 10-character date row while the live clock keeps running on the time row, so you never lose the time to read the sky.MODE_SUNastro_page_ms);RISE/SET/SOLlabels are 4-char-padded so the time columns stay alignedRISE 04.43·SET 21.21·SOL 13.02MODE_SUN_AZELAZ179EL62,AZ083EL-29MODE_MOONMOON 4 100(full),MOON 7 16MODE_GRIDIO91xlMODE_LATLONLAT 51.48·LON 0.00The sun page auto-pages (default 5.5 s, set by
astro_page_ms); the labels are padded to 4 characters so thetime digits stay column-aligned (note
SET/SOLsit one column right ofRISE):With no GPS fix the modes use
fake_latitude/fake_longitudeif set (handy indoors), otherwise show----. The moon needs no fix at all.Why these
They reuse data the firmware already has (position + disciplined UTC) for things the existing modes don't surface, and they suit the device's likely owner — a tinkerer / ham / observer: sun & moon position, sunrise/sunset, your grid square, your coordinates.
Design — keeping the maths out of the ISR
sendDate()runs inside the SysTick ISR (the 0.900 s repaint), and the L4 has only a single-precision FPU, so the double-precision astronomy would be slow soft-float in an interrupt. So the heavy maths runs in the main loop —astro_update(), gated on the active mode in exactly the waymeasure_vbat()is gated forMODE_VBAT— and the small result struct is swapped into a cache under a brief__disable_irq()mask. ThesendDate()cases only format cached scalars: no trig, nosun_times, nothing heavy in the ISR. Position is snapshotted once per update so az/el, grid and lat/lon are always mutually consistent.Everything is parameterised by
NUM_DISPLAY_MODES(the enum append growsconfig.modes_enabled[]automatically), so the modes join the button cycle and config parsing with no other changes.The maths —
Core/Src/astro.c(+astro.h)A self-contained C99 +
<math.h>unit with no firmware dependencies:sun_az_el()— apparent solar azimuth/elevation (NOAA/Meeus low-precision).sun_times()— sunrise / sunset / solar noon (+ optional civil/nautical/golden), decimal UTC hours.moon_phase()/moon_illuminated_fraction()/moon_phase_index().equation_of_time().maidenhead()— 6-char locator.Because it has no firmware ties, it unit-tests on a host.
test/test_astro.cchecks it against 45 reference vectors (four locations spanning hemispheres/seasons incl. a polar-winter case, plus fixed Maidenhead known-answers like Trafalgar Sq →IO91wm, ARRL HQ →FN31pr):Agreement with the reference is ~1e-5 (well under the whole-degree / whole-minute the display shows).
astro.cis added underCore/Src, which the.cprojectcompiles automatically;test/is not a source path, so the test never enters the firmware build.Accuracy & legibility (honest notes)
S→5,I→1,O→0,Z→2), the same as the existingGPS/bat/ttff/rtclabels. Maidenhead's lowercase subsquare (a–x) renders best-effort and is in-bounds forlut_7seg.config.txt.Config
config.txtgains the five mode keys (disabled by default) with comments and the moon-index legend, plusastro_page_ms— the dwell (ms) each sub-screen of the paged modes (SUN, LATLON) shows before flipping (default 5500, floored at 250):Build & test
Build
mk4-timein Release (Debug links a non-bootloader script, so a Debugfwt.binwon't flash via the bootloader) — no project-file changes are needed (astro.cauto-compiles). All five modes — and theastro_page_mssub-screen paging, its cadence tuned on the unit itself — have been built and confirmed working on real hardware (from a single location); cross-location and edge-case behaviour — hemispheres, the antimeridian, polar day/night — is covered by the 45 native reference vectors above. It stays a draft for your review, not for want of testing.Review & verification
Before this PR the change was put through an adversarial review across three independent lenses, each trying to break it rather than confirm it:
config.modes_enabled[NUM_DISPLAY_MODES]sizing, buffer bounds, switch-case correctness, and that the new modes take the normalCOUNT_NORMALlive-clock path.maidenheadclamping,fmodsign.Verdict was ship-with-fixes; the findings were addressed in this branch:
MODE_LATLONformatted the livelatitude/longitudeinsidesendDate()(which runs in the SysTick ISR) instead of the IRQ-mask-swappedastrocache, so the shown coordinates could disagree with the cachedhave_pos/grid in the same frame. Lat/lon are now snapshotted into the cache with everything else.%.2fprintedLON-0.00; switched to integer-hundredths so it readsLON 0.00.lut_7segrenders the full printable-ASCII set, so the labels and lowercase Maidenhead subsquares display fine;maidenhead()is left faithful.measure_vbat); only cached scalars are formatted in the ISR, so there's no soft-float in the interrupt.Possible follow-ups
HH:MM:SS.astro.c).Files
mk4-time/Core/Src/astro.c,mk4-time/Core/Inc/astro.h— new, self-contained maths.mk4-time/test/test_astro.c— new, native test (not built into firmware).mk4-time/Core/Src/main.c,Core/Inc/main.h— enum, cache,astro_update(), 5sendDatecases, 5 config keys, main-loop hook.qspi/config.txt— documented keys + legend.🤖 Generated with Claude Code