[education/kstars] kstars/ekos/align: Fix align hang when a slew completes without an observable IPS_BUSY

Jasem Mutlaq <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 6b46891bf8018b758b9682938a98a2f0ce62748b by Jasem Mutlaq.
Committed on 15/08/2026 at 10:11.
Pushed by mutlaqja into branch 'master'.

Fix align hang when a slew completes without an observable IPS_BUSY

Some mount drivers finish very short corrective slews (e.g. the small
residual left after a Sync) within a single status tick and never emit
an intermediate IPS_BUSY for EQUATORIAL_EOD_COORD/COORD. Align's
ALIGN_SLEWING handler only trusted an IPS_OK once it had witnessed
IPS_BUSY (or a 10s timer elapsed), and that elapsed-timer fallback is
only re-evaluated when a new property update arrives - so once the
mount settled and stopped pushing updates, align was stuck forever,
never re-triggering capture/plate-solving.

Snapshot the mount's reported RA/DE right before Slew() commands the
move, and also accept an IPS_OK whose position differs from that
snapshot as proof of a genuine completion. IPS_OK means "not busy" by
INDI convention, so a changed position can only mean the mount already
reported completion, never that it's still mid-slew - this can't fire
while a slew, however long, is still genuinely in progress.

M  +5    -0    kstars/ekos/align/align.h
M  +23   -1    kstars/ekos/align/align_goto.cpp

https://invent.kde.org/education/kstars/-/commit/6b46891bf8018b758b9682938a98a2f0ce62748b

diff --git a/kstars/ekos/align/align.h b/kstars/ekos/align/align.h
index 258a032c30..353e1c55c1 100644
--- a/kstars/ekos/align/align.h
+++ b/kstars/ekos/align/align.h
@@ -915,6 +915,11 @@ class Align : public QWidget, public Ui::Align
         // Only wait this many milliseconds for slew to start.
         // Otherwise assume it has begun.
         static constexpr int MAX_WAIT_FOR_SLEW_START_MSEC = 10000;
+        // Mount's reported RA/DE (raw property values) right before the last Slew() was
+        // commanded. Lets the ALIGN_SLEWING/IPS_OK handler recognize a fresh completion even
+        // when no IPS_BUSY was ever observed for that slew.
+        double m_PreSlewRA { 0 };
+        double m_PreSlewDE { 0 };
 
         // Online and Offline parsers
         AstrometryParser* parser { nullptr };
diff --git a/kstars/ekos/align/align_goto.cpp b/kstars/ekos/align/align_goto.cpp
index 484120dfdb..a6c554d0ae 100644
--- a/kstars/ekos/align/align_goto.cpp
+++ b/kstars/ekos/align/align_goto.cpp
@@ -185,7 +185,17 @@ void Align::updateProperty(INDI::Property prop)
 
                     case ALIGN_SLEWING:
 
-                        if (!didSlewStart())
+                        // didSlewStart() only trusts an IPS_OK if we previously witnessed an
+                        // IPS_BUSY for this slew (or a 10s timer has elapsed). Some drivers
+                        // complete very short slews within a single status tick and never emit
+                        // an observable IPS_BUSY, so that condition alone can stay false forever
+                        // even though the mount genuinely already moved. Also accept the update
+                        // if the reported position differs from what it was right before this
+                        // slew was commanded: IPS_OK means "not busy" by INDI convention, so a
+                        // changed position can only mean the mount already reported completion,
+                        // never that it's still mid-slew.
+                        if (!didSlewStart() &&
+                                nvp->np[0].value == m_PreSlewRA && nvp->np[1].value == m_PreSlewDE)
                         {
                             qCDebug(KSTARS_EKOS_ALIGN) << "Mount slew planned, but not started slewing yet...";
                             break;
@@ -484,6 +494,18 @@ void Align::Slew()
     setState(ALIGN_SLEWING);
     Q_EMIT newStatus(state);
 
+    // Snapshot the mount's currently-reported coordinates before commanding the slew, so the
+    // ALIGN_SLEWING/IPS_OK handler above can tell a fresh completion from a stale, pre-slew
+    // property value that simply hasn't been superseded by an observable IPS_BUSY yet.
+    if (auto pn = m_Mount->getNumber(m_Mount->isJ2000() ? "EQUATORIAL_COORD" : "EQUATORIAL_EOD_COORD"))
+    {
+        if (auto nvp = pn.getNumber())
+        {
+            m_PreSlewRA = nvp->np[0].value;
+            m_PreSlewDE = nvp->np[1].value;
+        }
+    }
+
     if (m_Mount->Slew(&m_TargetCoord))
     {
         slewStartTimer.start();
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.