Skip to content

Add MSF, JJY, and DCF signals#13

Open
emmby wants to merge 66 commits intomainfrom
feature-multisignal
Open

Add MSF, JJY, and DCF signals#13
emmby wants to merge 66 commits intomainfrom
feature-multisignal

Conversation

@emmby
Copy link
Owner

@emmby emmby commented Dec 3, 2025

Closes #12

Implemented by Gemini.
Checked the resulting output against reference implementation txtempus

DO NOT SUBMIT
depends on s00500/ESPUI#335

emmby added 30 commits December 3, 2025 14:39
…method to `getSymbol` across signal classes and usage.
…nge `frameBits_` to a `TimeCodeSymbol` array.
…f `uint64_t` bitmasks, simplifying symbol retrieval and removing bit manipulation helpers.
…rted by enhanced mocks for time and UI controls.
…ime tracking instead of `struct timeval`.

this prevents random restartsx when we manually change the time all over the place
…mplement it in derived classes, adjusting JJY frequency.
emmby added 29 commits December 7, 2025 08:23
Measure how precisely signal transitions align to 100ms boundaries
by computing (tv_usec % 100000) / 1000 at each transition. This
directly uses the same RTC clock that drives transitions, giving
independent per-transition measurements with no error propagation.

- Add TransitionStats class with 100 one-sided 1ms histogram buckets
- Track count, nonzero (≥1ms) count, average, and percentiles (p90/p95/p99)
- Log stats once per minute (deferred after ledcWrite to avoid latency)
- Reset stats daily at midnight UTC
- Add 5 unit tests covering alignment, jitter, independence, average,
  and midnight reset
Display transition jitter stats in a horizontal bar chart on the
ESPUI web interface. The histogram uses 5ms display buckets (0-50ms)
aggregated from 1ms internal resolution, with summary text showing
count, nonzero count, average, and percentiles at 1ms precision.

- Add formatForUI() to TransitionStats for sparse data transfer
  (only nonzero buckets sent, e.g. "0:442,1:3,2:1")
- Add ui_jitter ESPUI label with periodic data push
- Add convertToHistogram() JS renderer with CSS bar chart
- Hook histogram into existing MutationObserver
- Add Wetasphalt to mock ControlColor enum
At midnight UTC reset, snapshot the current day's aggregate stats
(n, nonzero, avg, p90/p95/p99) into a 7-entry FIFO before clearing.
The ESPUI panel displays previous days in a "Previous Days" table
below the live histogram.

- Add DailySummary struct and history_[7] rolling buffer
- Save snapshot in checkMidnightReset before reset()
- Append history entries to formatForUI (|| delimited)
- Update JS to parse || sections and render history table
- Update midnight reset test to verify history preservation
Add frame-level tracking to determine how many one-minute frames
contained at least one transition with ≥1ms jitter. Displayed in
today's stats and the daily history table.

- Add frameCount_, nonZeroFrameCount_, and frameHadNonZero_ flag
- Merge markFrameBoundary + checkMidnightReset into onMinuteBoundary()
- Include frames/nzFrames in formatForUI, serial log, and DailySummary
- Update JS to display frame stats in today's summary and history table
Switch midnight reset from UTC to local time so the daily boundary
aligns with the user's timezone. Add p99.9 (permille) and p100 (max)
percentiles. Track which minutes had nonzero jitter in a ring buffer
of 20 error frames, recording the affected seconds as a bitmask.
Expand histogram to full 0-99ms range (20 five-ms buckets).

- Rename checkMidnightReset to onMinuteBoundary, use local hour/min
- Add getPermille() for p99.9 calculation
- Add ErrorFrame struct with hour, minute, nzCount, maxJitter,
  and 60-bit errorSeconds bitmask
- Append error frame log to formatForUI (@@@ delimiter)
- Pass current second to recordTransition for bitmask tracking
- JS renders "Recent Error Frames" table with affected seconds
- Expand histogram display from 10 to 20 buckets (0-99ms)
- Increase jitterBuf from 512 to 1024 bytes
…ini and creating build_opt.h.

this should mitigate crashes from longer output using ESPUI print
Replace the loop()-based PWM output with a high-priority esp_timer
callback (onSignalTimer) that fires every 1ms. The callback reads
gettimeofday(), looks up the pre-computed bit from a double-buffered
broadcast array, and writes the antenna pin — immune to WiFi, ESPUI,
and mDNS delays that previously caused 1-60ms jitter on ~50% of frames.

- Add onSignalTimer() callback: ~10 lines, no timezone calls
- Double-buffer broadcast arrays (broadcastA/B) with atomic pointer swap
- loop() writes to inactive buffer, timer reads from active buffer
- Volatile shared state (transitionOccurred, lastTransitionUsec) for
  timer→loop communication of transition events
- loop() still handles encoding, stats, serial logging, ESPUI, pixels
- #ifdef UNIT_TEST fallback computes signal inline when no timer exists
- Add architecture comment explaining the two-part design
Move test-specific concerns out of the application code and into the
test infrastructure. The app code is now identical in production and
test builds.

- Add test/mocks/esp_timer.h with no-op stubs for esp_timer_create
  and esp_timer_start_periodic, so the timer setup code compiles in
  native tests without #ifdef guards
- Remove the inline signal computation fallback from loop() — tests
  now call onSignalTimer(NULL) directly to simulate the hardware timer
- Test explicitly simulates the timer→loop interaction the same way
  the real hardware does
Add section headers (Configuration, Includes, Globals, Helpers,
Callbacks, Arduino Setup & Loop) to improve readability. Move
configuration values (ENABLE_WEB_UI, PIN_ANTENNA, timezone) above
includes for visibility. Reorder helpers before callbacks so
dutyCycle is defined before onSignalTimer calls it. Fix duplicate
timezone comment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider adding other protocols from https://github.com/adotagarwal/WatchTower2

1 participant