From 4e80b67fa7c295c07aa07e443d9f0cd947518073 Mon Sep 17 00:00:00 2001 From: Lutz Date: Tue, 13 Oct 2026 22:22:46 -0700 Subject: [PATCH 1/2] fix(guiding): accept guide pulses while another pulse is active V1.13.14 (#261) added an isSlewingTRK() guard to guidePulse() to refuse pulses when the mount is not tracking (e.g. after the RA tracking limit auto-stop). However slewStatus() reports NOT_SLEWING for the entire duration of any active guide pulse, so the guard also silently dropped every pulse that arrived while another one was still running. Clients that wait for pulse completion before sending the next one (PHD2 via the ASCOM driver polling :GIG#) never hit this. Blind senders (INDI/EKOS) do: with typical 500-3000ms pulses on a 1-2s cadence, most corrections were dropped and guiding was effectively dead. Both :MG replies are empty, so the client cannot detect the drop. Test the STATUS_TRACKING status flag directly via the new isTracking() accessor instead. This keeps the intended refusal when actually not tracking (limit reached, tracking off, parked) and restores the pre-V1.13.14 last-one-wins behavior for overlapping pulses. Co-Authored-By: Claude Code --- src/Mount.cpp | 17 ++++++++++++++++- src/Mount.hpp | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Mount.cpp b/src/Mount.cpp index 67ac5b0a..e3f69386 100644 --- a/src/Mount.cpp +++ b/src/Mount.cpp @@ -1700,7 +1700,10 @@ void Mount::guidePulse(byte direction, int duration) const char *directionName = "-NE-S---W"; #endif LOG(DEBUG_STEPPERS | DEBUG_GUIDE, "[GUIDE]: guidePulse: > Guide Pulse %c for %dms requested", directionName[direction], duration); - if (!isSlewingTRK()) + // Deliberately not using isSlewingTRK() here: slewStatus() reports NOT_SLEWING while any guide pulse + // is running, so that check would silently drop every pulse arriving during an active one (e.g. from + // clients that send pulses back-to-back without waiting for completion, like INDI/EKOS). + if (!isTracking()) { LOG(DEBUG_STEPPERS | DEBUG_GUIDE, "[GUIDE]: guidePulse: Not tracking (at limit?), ignoring guide pulse"); } @@ -2532,6 +2535,18 @@ bool Mount::isSlewingTRK() const return (slewStatus() & SLEWING_TRACKING) != 0; } +///////////////////////////////// +// +// isTracking +// +///////////////////////////////// +bool Mount::isTracking() const +{ + // Unlike isSlewingTRK(), this stays true while a guide pulse is running, + // since slewStatus() reports NOT_SLEWING for the whole guiding block. + return (_mountStatus & STATUS_TRACKING) != 0; +} + ///////////////////////////////// // // isParking diff --git a/src/Mount.hpp b/src/Mount.hpp index a6cdc2c5..0f740313 100644 --- a/src/Mount.hpp +++ b/src/Mount.hpp @@ -312,6 +312,7 @@ class Mount bool isSlewingRAorDEC() const; bool isSlewingIdle() const; bool isSlewingTRK() const; + bool isTracking() const; bool isParking() const; bool isGuiding() const; bool isFindingHome() const; From 5cecf4f77c1bd6523e54139112b522b513147242 Mon Sep 17 00:00:00 2001 From: Lutz Date: Tue, 13 Oct 2026 22:23:03 -0700 Subject: [PATCH 2/2] fix(display): skip info display renders during guide pulses V1.13.7 (#248) added an updateInfoDisplay() call to the else-branch of the guiding block in loop(), refreshing the display mid-pulse. A full SSD1306 frame (~1KB over the default 100kHz I2C, no Wire.setClock is configured) blocks loop() for roughly 100ms, and guiding also bypasses the slew-based 5Hz refresh throttle (slewStatus() is masked while guiding, so the idle 30Hz rate applies). The end-time check only runs at the top of each loop() iteration, so every pulse could overshoot its requested duration by up to one render. The display is not left stale: guidePulse() renders once at each pulse start, and the normal end-of-loop refresh covers the gaps between pulses. Co-Authored-By: Claude Code --- src/Mount.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Mount.cpp b/src/Mount.cpp index e3f69386..71556087 100644 --- a/src/Mount.cpp +++ b/src/Mount.cpp @@ -3188,12 +3188,10 @@ void Mount::loop() LOG(DEBUG_GUIDE, "[MOUNT]: Loop: StopGuiding. Now: %l, RA End: %l, DEC End: %l", now, _guideRaEndTime, _guideDecEndTime); stopGuiding(stopRaGuiding, stopDecGuiding); } - else - { -#if INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE - updateInfoDisplay(); -#endif - } + // Do not update the info display while a pulse is running: a full-frame render blocks + // loop() for roughly 100ms (1KB over the default 100kHz I2C), which delays the end-time + // checks above and makes guide pulses overshoot their requested duration. The display + // is still refreshed at each pulse start (guidePulse) and between pulses (end of loop()). return; }