From 65251c47b821ba71cb409fa6c0ff5f988b5472cf Mon Sep 17 00:00:00 2001 From: Marcelo Brigato Date: Sun, 29 Mar 2026 23:19:57 -0300 Subject: [PATCH] Selector: add timeout to PlannedHome to prevent deadlock Add a plannedHomeTimer counter that increments each main-loop iteration while the selector is in PlannedHome waiting for the idler to become HomingValid. If 30 000 iterations elapse without the idler becoming valid, HomeFailed() is called, transitioning to HomingFailed which surfaces an error screen to the user. This prevents an indefinite deadlock when the idler is stuck in a non-error state (e.g. Ready with homingValid==false) that WaitForModulesErrorRecovery cannot detect. --- src/modules/selector.cpp | 8 ++++++++ src/modules/selector.h | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/modules/selector.cpp b/src/modules/selector.cpp index 56514da..6c8d5d7 100644 --- a/src/modules/selector.cpp +++ b/src/modules/selector.cpp @@ -21,6 +21,7 @@ void Selector::PrepareMoveToPlannedSlot() { void Selector::PlanHomingMoveForward() { state = PlannedHome; + plannedHomeTimer = 0; // reset timeout counter when entering PlannedHome dbg_logic_P(PSTR("Plan Homing Selector Forward")); } @@ -110,6 +111,13 @@ bool Selector::Step() { state = HomeForward; mm::motion.PlanMove(mm::unitToAxisUnit(-config::selectorLimits.lenght * 2), mm::unitToAxisUnit(mg::globals.SelectorHomingFeedrate_mm_s())); + } else if (++plannedHomeTimer >= 30000U) { + // Idler did not become homing-valid within ~30 000 main-loop iterations. + // This breaks a potential deadlock where the idler is stuck in a non-error + // state (e.g. Ready with homingValid==false) that WaitForModulesErrorRecovery + // cannot detect. HomeFailed() transitions selector to HomingFailed, which IS + // detected and surfaces an error screen to the user. + HomeFailed(); } return false; case HomeForward: diff --git a/src/modules/selector.h b/src/modules/selector.h index 0fd247c..66ee19e 100644 --- a/src/modules/selector.h +++ b/src/modules/selector.h @@ -15,7 +15,8 @@ namespace mm = modules::motion; class Selector : public mm::MovableBase { public: inline constexpr Selector() - : MovableBase(mm::Selector) {} + : MovableBase(mm::Selector) + , plannedHomeTimer(0) {} /// Plan move of the selector to a specific filament slot /// @param slot index to move to @@ -49,6 +50,10 @@ protected: virtual void FinishMove() override; private: + /// Counts main-loop iterations spent in PlannedHome while waiting for the idler to become HomingValid. + /// Guards against indefinite deadlock: if the idler never becomes valid, HomeFailed() fires and the + /// WaitForModulesErrorRecovery path surfaces the error to the user. + uint16_t plannedHomeTimer; }; /// The one and only instance of Selector in the FW