/// @file movable_base.h #pragma once #include #include "../config/axis.h" #include "../hal/tmc2130.h" namespace modules { namespace motion { /// Base class for movable modules - #modules::idler::Idler and #modules::selector::Selector contains the common code class MovableBase { public: /// Internal states of the state machine enum { Ready = 0, // intentionally set as zero in order to allow zeroing the Idler structure upon startup -> avoid explicit initialization code Moving, PlannedHome, HomeForward, HomeBack, TMCFailed, HomingFailed, OnHold, }; /// Operation (Engage/Disengage/MoveToSlot) return values enum class OperationResult : uint8_t { Accepted, ///< the operation has been successfully started Refused, ///< another operation is currently underway, cannot start a new one Failed ///< the operation could not been started due to HW issues }; inline constexpr MovableBase(config::Axis axis) : state(Ready) , plannedSlot(-1) , currentSlot(-1) , homingValid(false) , axis(axis) , axisStart(0) {} /// virtual ~MovableBase(); intentionally disabled, see description in logic::CommandBase /// @returns currently active slot /// This state is updated only when a planned move is successfully finished, so it is safe for higher-level /// state machines to use this call as a waiting condition for the desired state of the derive class (idler/selector) /// While homing, Slot() returns 0xff as the current slot index is invalid. inline uint8_t Slot() const { return currentSlot; } /// @returns internal state of the state machine inline uint8_t State() const { return state; } inline hal::tmc2130::ErrorFlags TMCErrorFlags() const { return tmcErrorFlags; } /// Invalidates the homing flag - that is now used to inform the movable component (Idler or Selector) /// that their current coordinates may have been compromised and a new homing move is to be performed. /// Each movable component performs the homing move immediately after it is possible to do so: /// - Idler immediately (and then moves to desired slot again) /// - Selector once there is no filament stuck in it (and then moves to desired slot again) /// Homing procedure therefore becomes completely transparent to upper layers /// and it will not be necessary to call it explicitly. /// Please note this method does not clear any planned move on the component /// - on the contrary - the planned move will be peformed immediately after homing /// (which makes homing completely transparent) inline void InvalidateHoming() { homingValid = false; } /// Prepare a homing move of the axis void PlanHome(); inline bool HomingValid() const { return homingValid; } inline config::Axis Axis() const { return axis; } /// Set TMC2130 iRun current level for this axis /// iRun == 0 means set the default from config void SetCurrents(uint8_t iRun, uint8_t iHold); /// Puts the movable on-hold void HoldOn() { state = OnHold; } /// Allows the movable to move/home again void Resume() { state = Ready; } #ifndef UNITTEST protected: #endif /// internal state of the automaton uint8_t state; /// planned slot - where to move to uint8_t plannedSlot; /// current slot uint8_t currentSlot; /// true if the axis is considered as homed bool homingValid; /// cached TMC2130 error flags - being read only if the axis is enabled and doing something (moving) hal::tmc2130::ErrorFlags tmcErrorFlags; config::Axis axis; int32_t axisStart; virtual void PrepareMoveToPlannedSlot() = 0; virtual void PlanHomingMoveForward() = 0; virtual void PlanHomingMoveBack() = 0; /// @returns true if the measured axis length is within the expected range, false otherwise virtual bool FinishHomingAndPlanMoveToParkPos() = 0; virtual void FinishMove() = 0; /// Initializes movement of a movable module. /// Beware: this operation reinitializes the axis/TMC driver as well (may introduce axis creep as we have seen on the Idler) OperationResult InitMovement(); /// Initializes movement of a movable module without reinitializing the axis/TMC driver OperationResult InitMovementNoReinitAxis(); void PerformMove(); void PerformHomeForward(); void PerformHomeBack(); void HomeFailed(); void CheckTMC(); }; } // namespace motion } // namespace modules