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