From b36e6b99a1972945d591bcafec1ddbdf6d71ba1e Mon Sep 17 00:00:00 2001 From: "D.R.racer" Date: Mon, 17 Jan 2022 07:40:48 +0100 Subject: [PATCH] Add Pulley as a Movable module This PR brings the following improvements: - unifies the error handling of TMC and Homing/Stallguard errors on all motorized modules (Idler, Selector, Pulley) - now we distinguish between Homing and TMC errors + we have a separate handling of these two kinds into CommandBase unified for all motorized modules - adds unit tests to verify the function - fixes SetFINDAStateAndDebounce (didn't obey the press parameter before) --- src/logic/command_base.cpp | 131 ++++++++++++------ src/logic/command_base.h | 19 ++- src/logic/cut_filament.cpp | 5 +- src/logic/eject_filament.cpp | 7 +- src/logic/error_codes.h | 5 + src/logic/feed_to_bondtech.cpp | 11 +- src/logic/feed_to_finda.cpp | 7 +- src/logic/load_filament.cpp | 5 +- src/logic/retract_from_finda.cpp | 3 +- src/logic/tool_change.cpp | 3 +- src/logic/unload_filament.cpp | 7 +- src/logic/unload_to_finda.cpp | 7 +- src/modules/CMakeLists.txt | 1 + src/modules/idler.cpp | 20 +-- src/modules/idler.h | 2 +- src/modules/movable_base.cpp | 14 +- src/modules/movable_base.h | 22 ++- src/modules/pulley.cpp | 55 ++++++++ src/modules/pulley.h | 50 +++++++ src/modules/selector.cpp | 16 +-- src/modules/selector.h | 2 +- tests/unit/logic/cut_filament/CMakeLists.txt | 1 + .../unit/logic/eject_filament/CMakeLists.txt | 1 + tests/unit/logic/failing_tmc/CMakeLists.txt | 2 + .../logic/failing_tmc/test_failing_tmc.cpp | 72 +++++++++- .../logic/feed_to_bondtech/CMakeLists.txt | 1 + tests/unit/logic/feed_to_finda/CMakeLists.txt | 1 + tests/unit/logic/load_filament/CMakeLists.txt | 1 + tests/unit/logic/stubs/main_loop_stub.cpp | 5 +- tests/unit/logic/tool_change/CMakeLists.txt | 1 + .../unit/logic/unload_filament/CMakeLists.txt | 1 + .../unit/logic/unload_to_finda/CMakeLists.txt | 1 + 32 files changed, 374 insertions(+), 105 deletions(-) create mode 100644 src/modules/pulley.cpp create mode 100644 src/modules/pulley.h diff --git a/src/logic/command_base.cpp b/src/logic/command_base.cpp index 021a304..9de4ad3 100644 --- a/src/logic/command_base.cpp +++ b/src/logic/command_base.cpp @@ -4,6 +4,7 @@ #include "../modules/finda.h" #include "../modules/fsensor.h" #include "../modules/idler.h" +#include "../modules/pulley.h" #include "../modules/selector.h" #include "../modules/motion.h" #include "../modules/leds.h" @@ -15,7 +16,7 @@ inline ErrorCode &operator|=(ErrorCode &a, ErrorCode b) { return a = (ErrorCode)((uint16_t)a | (uint16_t)b); } -static ErrorCode TMC2130ToErrorCode(const hal::tmc2130::ErrorFlags &ef, uint8_t tmcIndex) { +static ErrorCode TMC2130ToErrorCode(const hal::tmc2130::ErrorFlags &ef) { ErrorCode e = ErrorCode::RUNNING; if (ef.reset_flag) { @@ -34,51 +35,101 @@ static ErrorCode TMC2130ToErrorCode(const hal::tmc2130::ErrorFlags &ef, uint8_t e |= ErrorCode::TMC_OVER_TEMPERATURE_ERROR; } - if (e != ErrorCode::RUNNING) { - switch (tmcIndex) { - case config::Axis::Pulley: - e |= ErrorCode::TMC_PULLEY_BIT; - break; - case config::Axis::Selector: - e |= ErrorCode::TMC_SELECTOR_BIT; - break; - case config::Axis::Idler: - e |= ErrorCode::TMC_IDLER_BIT; - break; - default: - break; - } - } - return e; } -bool CommandBase::Step() { - ErrorCode tmcErr = ErrorCode::RUNNING; - // check the global HW errors - may be we should avoid the modules layer and check for the HAL layer errors directly - if (mi::idler.State() == mi::Idler::Failed) { - state = ProgressCode::ERRTMCFailed; - tmcErr |= TMC2130ToErrorCode(mi::idler.TMCErrorFlags(), mm::Axis::Idler); +static ErrorCode AddErrorAxisBit(ErrorCode ec, uint8_t tmcIndex) { + switch (tmcIndex) { + case config::Axis::Pulley: + ec |= ErrorCode::TMC_PULLEY_BIT; + break; + case config::Axis::Selector: + ec |= ErrorCode::TMC_SELECTOR_BIT; + break; + case config::Axis::Idler: + ec |= ErrorCode::TMC_IDLER_BIT; + break; + default: + break; } - if (ms::selector.State() == ms::Selector::Failed) { - state = ProgressCode::ERRTMCFailed; - tmcErr |= TMC2130ToErrorCode(ms::selector.TMCErrorFlags(), mm::Axis::Selector); - } - // may be we should model the Pulley as well... - // if (ms::selector.State() == ms::Selector::Failed) { - // state = ProgressCode::ERRTMCFailed; - // error |= TMC2130ToErrorCode(mm::motion.DriverForAxis(mm::Axis::Selector), mm::Axis::Selector); - // return true; // the HW error prevents us from continuing with the state machine - the MMU must be restarted/fixed before continuing - // } + return ec; +} - // @@TODO not sure how to prevent losing the previously accumulated error ... or do I really need to do it? - // May be the TMC error word just gets updated with new flags as the motion proceeds - // And how about the logical errors like FINDA_DIDNT_SWITCH_ON? - if (tmcErr != ErrorCode::RUNNING) { - error |= tmcErr; +ErrorCode CheckMovable(mm::MovableBase &m) { + switch (m.State()) { + case mm::MovableBase::TMCFailed: + return AddErrorAxisBit(TMC2130ToErrorCode(m.TMCErrorFlags()), m.Axis()); + case mm::MovableBase::HomingFailed: + return AddErrorAxisBit(ErrorCode::HOMING_FAILED, m.Axis()); + } + return ErrorCode::RUNNING; +} + +static inline ErrorCode WithoutAxisBits(ErrorCode ec) { + return static_cast( + static_cast(ec) + & (~(static_cast(ErrorCode::TMC_SELECTOR_BIT) + | static_cast(ErrorCode::TMC_IDLER_BIT) + | static_cast(ErrorCode::TMC_PULLEY_BIT)))); +} + +bool CommandBase::WaitForOneModuleErrorRecovery(ErrorCode ec, modules::motion::MovableBase &m) { + if (ec != ErrorCode::RUNNING) { + if (stateBeforeModuleFailed == ProgressCode::OK) { + // a new problem with the movable modules + // @@TODO not sure how to prevent losing the previously accumulated error ... or do I really need to do it? + // May be the TMC error word just gets updated with new flags as the motion proceeds + stateBeforeModuleFailed = state; + error = ec; + state = ProgressCode::ERRWaitingForUser; // such a situation always requires user's attention -> let the printer display an error screen + return true; + } else { + switch (state) { + case ProgressCode::ERRWaitingForUser: // waiting for a recovery - mask axis bits: + if (WithoutAxisBits(ec) == ErrorCode::HOMING_FAILED) { + // homing can be recovered + mui::Event ev = mui::userInput.ConsumeEvent(); + if (ev == mui::Event::Middle) { + m.InvalidateHoming(); // @@TODO invalidate and force initiate a new homing attempt + state = ProgressCode::Homing; + } + } + // TMC errors cannot be recovered safely, waiting for power cycling the MMU + return true; + case ProgressCode::Homing: + if (m.HomingValid()) { + // managed to recover from a homing problem + state = stateBeforeModuleFailed; + stateBeforeModuleFailed = ProgressCode::OK; + return false; + } + return true; + default: + return true; // no idea what to do in other states ... set internal fw error state? + } + return true; + } + } + return false; +} + +bool CommandBase::WaitForModulesErrorRecovery() { + if (WaitForOneModuleErrorRecovery(CheckMovable(mi::idler), mi::idler)) + return true; + + if (WaitForOneModuleErrorRecovery(CheckMovable(ms::selector), ms::selector)) + return true; + + if (WaitForOneModuleErrorRecovery(CheckMovable(mp::pulley), mp::pulley)) + return true; + + return false; +} + +bool CommandBase::Step() { + if (WaitForModulesErrorRecovery()) { return true; } - return StepInner(); } @@ -129,7 +180,7 @@ bool CommandBase::CheckToolIndex(uint8_t index) { void CommandBase::ErrDisengagingIdler() { if (!mi::idler.Engaged()) { state = ProgressCode::ERRWaitingForUser; - mm::motion.Disable(mm::Pulley); + mp::pulley.Disable(); mui::userInput.Clear(); // remove all buffered events if any just before we wait for some input } } diff --git a/src/logic/command_base.h b/src/logic/command_base.h index bd5d75b..ed8cd3d 100644 --- a/src/logic/command_base.h +++ b/src/logic/command_base.h @@ -4,6 +4,12 @@ #include "error_codes.h" #include "progress_codes.h" +namespace modules { +namespace motion { +class MovableBase; +} +} + /// The logic namespace handles the application logic on top of the modules. namespace logic { @@ -19,7 +25,8 @@ class CommandBase { public: inline CommandBase() : state(ProgressCode::OK) - , error(ErrorCode::OK) {} + , error(ErrorCode::OK) + , stateBeforeModuleFailed(ProgressCode::OK) {} // Normally, a base class should (must) have a virtual destructor to enable correct deallocation of superstructures. // However, in our case we don't want ANY destruction of these objects and moreover - adding a destructor like this @@ -82,6 +89,15 @@ protected: /// If not, it returns false and sets the error to ErrorCode::INVALID_TOOL bool CheckToolIndex(uint8_t index); + /// Checks for errors of modules - that includes TMC errors, Idler and Selector errors and possibly more. + /// The idea is to check blocking errors at one spot consistently. + /// Some of the detected errors can be irrecoverable (i.e. need power cycling the MMU). + /// @returns true if waiting for a recovery, false if the state machine can continue. + bool WaitForModulesErrorRecovery(); + + /// @returns true when still waiting for a module to recover, false otherwise. + bool WaitForOneModuleErrorRecovery(ErrorCode iState, modules::motion::MovableBase &m); + /// Perform disengaging idler in ErrDisengagingIdler state void ErrDisengagingIdler(); @@ -93,6 +109,7 @@ protected: ProgressCode state; ///< current progress state of the state machine ErrorCode error; ///< current error code + ProgressCode stateBeforeModuleFailed; ///< saved state of the state machine before a common error happened }; } // namespace logic diff --git a/src/logic/cut_filament.cpp b/src/logic/cut_filament.cpp index dbaae44..cef5258 100644 --- a/src/logic/cut_filament.cpp +++ b/src/logic/cut_filament.cpp @@ -7,6 +7,7 @@ #include "../modules/leds.h" #include "../modules/motion.h" #include "../modules/permanent_storage.h" +#include "../modules/pulley.h" #include "../modules/selector.h" namespace logic { @@ -60,7 +61,7 @@ bool CutFilament::StepInner() { } else { // unload back to the pulley state = ProgressCode::UnloadingToPulley; - mm::motion.PlanMove(-config::cutLength, config::pulleyUnloadFeedrate); + mp::pulley.PlanMove(-config::cutLength, config::pulleyUnloadFeedrate); } } break; @@ -74,7 +75,7 @@ bool CutFilament::StepInner() { case ProgressCode::PreparingBlade: if (ms::selector.Slot() == cutSlot + 1) { state = ProgressCode::PushingFilament; - mm::motion.PlanMove(config::cutLength, config::pulleyUnloadFeedrate); // + mp::pulley.PlanMove(config::cutLength, config::pulleyUnloadFeedrate); // } break; case ProgressCode::PushingFilament: diff --git a/src/logic/eject_filament.cpp b/src/logic/eject_filament.cpp index 8ded9b8..095d28e 100644 --- a/src/logic/eject_filament.cpp +++ b/src/logic/eject_filament.cpp @@ -7,6 +7,7 @@ #include "../modules/leds.h" #include "../modules/motion.h" #include "../modules/permanent_storage.h" +#include "../modules/pulley.h" #include "../modules/selector.h" #include "../debug.h" @@ -53,8 +54,8 @@ bool EjectFilament::StepInner() { case ProgressCode::ParkingSelector: if (mm::motion.QueueEmpty()) { // selector parked aside state = ProgressCode::EjectingFilament; - mm::motion.InitAxis(mm::Pulley); - mm::motion.PlanMove(-config::filamentMinLoadedToMMU, config::pulleySlowFeedrate); + mp::pulley.InitAxis(); + mp::pulley.PlanMove(-config::filamentMinLoadedToMMU, config::pulleySlowFeedrate); } break; case ProgressCode::EjectingFilament: @@ -65,7 +66,7 @@ bool EjectFilament::StepInner() { break; case ProgressCode::DisengagingIdler: if (!mi::idler.Engaged()) { // idler disengaged - mm::motion.Disable(mm::Pulley); + mp::pulley.Disable(); mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::NotLoaded); state = ProgressCode::OK; error = ErrorCode::OK; diff --git a/src/logic/error_codes.h b/src/logic/error_codes.h index 1b49589..771b187 100644 --- a/src/logic/error_codes.h +++ b/src/logic/error_codes.h @@ -41,6 +41,11 @@ enum class ErrorCode : uint_fast16_t { QUEUE_FULL = 0x802b, ///< E32811 internal logic error - attempt to move with a full queue + HOMING_FAILED = 0x8007, ///< generic homing failed error - always reported with the corresponding axis bit set (Idler or Selector) as follows: + HOMING_SELECTOR_FAILED = HOMING_FAILED | TMC_SELECTOR_BIT, ///< E32903 the Selector was unable to home properly - that means something is blocking its movement + HOMING_IDLER_FAILED = HOMING_FAILED | TMC_IDLER_BIT, ///< E33031 the Idler was unable to home properly - that means something is blocking its movement + STALLED_PULLEY = HOMING_FAILED | TMC_PULLEY_BIT, ///< E32839 for the Pulley "homing" means just stallguard detected during Pulley's operation (Pulley doesn't home) + VERSION_MISMATCH = 0x802c, ///< E32812 internal error of the printer - incompatible version of the MMU FW PROTOCOL_ERROR = 0x802d, ///< E32813 internal error of the printer - communication with the MMU got garbled - protocol decoder couldn't decode the incoming messages MMU_NOT_RESPONDING = 0x802e, ///< E32814 internal error of the printer - communication with the MMU is not working diff --git a/src/logic/feed_to_bondtech.cpp b/src/logic/feed_to_bondtech.cpp index d1890b8..23e1aba 100644 --- a/src/logic/feed_to_bondtech.cpp +++ b/src/logic/feed_to_bondtech.cpp @@ -7,6 +7,7 @@ #include "../modules/leds.h" #include "../modules/motion.h" #include "../modules/permanent_storage.h" +#include "../modules/pulley.h" #include "../debug.h" namespace logic { @@ -23,7 +24,7 @@ void logic::FeedToBondtech::GoToPushToNozzle() { mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InFSensor); // plan a slow move to help push filament into the nozzle //@@TODO the speed in mm/s must correspond to printer's feeding speed! - mm::motion.PlanMove(config::fsensorToNozzle, config::pulleySlowFeedrate); + mp::pulley.PlanMove(config::fsensorToNozzle, config::pulleySlowFeedrate); state = PushingFilamentIntoNozzle; } @@ -34,8 +35,8 @@ bool FeedToBondtech::Step() { dbg_logic_P(PSTR("Feed to Bondtech --> Idler engaged")); dbg_logic_fP(PSTR("Pulley start steps %u"), mm::motion.CurPosition(mm::Pulley)); state = PushingFilamentToFSensor; - mm::motion.InitAxis(mm::Pulley); - mm::motion.PlanMove(config::defaultBowdenLength, config::pulleyLoadFeedrate, config::pulleySlowFeedrate); + mp::pulley.InitAxis(); + mp::pulley.PlanMove(config::defaultBowdenLength, config::pulleyLoadFeedrate, config::pulleySlowFeedrate); } return false; case PushingFilamentToFSensor: @@ -55,7 +56,7 @@ bool FeedToBondtech::Step() { mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle); mi::idler.Disengage(); // while disengaging the idler, keep on moving with the pulley to avoid grinding while the printer is trying to grab the filament itself - mm::motion.PlanMove(config::fsensorToNozzleAvoidGrind, config::pulleySlowFeedrate); + mp::pulley.PlanMove(config::fsensorToNozzleAvoidGrind, config::pulleySlowFeedrate); state = DisengagingIdler; } return false; @@ -64,7 +65,7 @@ bool FeedToBondtech::Step() { dbg_logic_P(PSTR("Feed to Bondtech --> Idler disengaged")); dbg_logic_fP(PSTR("Pulley end steps %u"), mm::motion.CurPosition(mm::Pulley)); state = OK; - mm::motion.Disable(mm::Pulley); + mp::pulley.Disable(); ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::on); } return false; diff --git a/src/logic/feed_to_finda.cpp b/src/logic/feed_to_finda.cpp index 3d5152a..b709f44 100644 --- a/src/logic/feed_to_finda.cpp +++ b/src/logic/feed_to_finda.cpp @@ -7,6 +7,7 @@ #include "../modules/leds.h" #include "../modules/motion.h" #include "../modules/permanent_storage.h" +#include "../modules/pulley.h" #include "../modules/user_input.h" #include "../debug.h" namespace logic { @@ -29,12 +30,12 @@ bool FeedToFinda::Step() { dbg_logic_P(PSTR("Feed to Finda --> Idler engaged")); dbg_logic_fP(PSTR("Pulley start steps %u"), mm::motion.CurPosition(mm::Pulley)); state = PushingFilament; - mm::motion.InitAxis(mm::Pulley); + mp::pulley.InitAxis(); // @@TODO this may never happen as load filament always assumes the filament is at least at the pulley // if (mg::globals.FilamentLoaded() == mg::FilamentLoadState::NotLoaded) { // feed slowly filament to PTFE - // mm::motion.PlanMove(config::filamentMinLoadedToMMU, config::pulleySlowFeedrate); + // mp::pulley.PlanMove(config::filamentMinLoadedToMMU, config::pulleySlowFeedrate); // } - mm::motion.PlanMove(config::maximumFeedToFinda, config::pulleySlowFeedrate); + mp::pulley.PlanMove(config::maximumFeedToFinda, config::pulleySlowFeedrate); mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InSelector); mui::userInput.Clear(); // remove all buffered events if any just before we wait for some input } diff --git a/src/logic/load_filament.cpp b/src/logic/load_filament.cpp index 09f7785..f190783 100644 --- a/src/logic/load_filament.cpp +++ b/src/logic/load_filament.cpp @@ -6,6 +6,7 @@ #include "../modules/leds.h" #include "../modules/motion.h" #include "../modules/permanent_storage.h" +#include "../modules/pulley.h" #include "../modules/selector.h" #include "../modules/user_input.h" #include "../debug.h" @@ -41,7 +42,7 @@ void logic::LoadFilament::FinishedCorrectly() { state = ProgressCode::OK; error = ErrorCode::OK; ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off); - mm::motion.Disable(mm::Pulley); + mp::pulley.Disable(); } bool LoadFilament::StepInner() { @@ -117,7 +118,7 @@ bool LoadFilament::StepInner() { case ProgressCode::ERREngagingIdler: if (mi::idler.Engaged()) { state = ProgressCode::ERRHelpingFilament; - mm::motion.PlanMove(config::pulleyHelperMove, config::pulleySlowFeedrate); + mp::pulley.PlanMove(config::pulleyHelperMove, config::pulleySlowFeedrate); } return false; case ProgressCode::ERRHelpingFilament: diff --git a/src/logic/retract_from_finda.cpp b/src/logic/retract_from_finda.cpp index 651d334..8f16879 100644 --- a/src/logic/retract_from_finda.cpp +++ b/src/logic/retract_from_finda.cpp @@ -5,6 +5,7 @@ #include "../modules/idler.h" #include "../modules/leds.h" #include "../modules/motion.h" +#include "../modules/pulley.h" #include "../debug.h" namespace logic { @@ -22,7 +23,7 @@ bool RetractFromFinda::Step() { if (mi::idler.Engaged()) { dbg_logic_fP(PSTR("Pulley start steps %u"), mm::motion.CurPosition(mm::Pulley)); state = UnloadBackToPTFE; - mm::motion.PlanMove(-(config::cuttingEdgeToFindaMidpoint + config::cuttingEdgeRetract), config::pulleyUnloadFeedrate); + mp::pulley.PlanMove(-(config::cuttingEdgeToFindaMidpoint + config::cuttingEdgeRetract), config::pulleyUnloadFeedrate); } return false; case UnloadBackToPTFE: diff --git a/src/logic/tool_change.cpp b/src/logic/tool_change.cpp index 5ee773d..d48df22 100644 --- a/src/logic/tool_change.cpp +++ b/src/logic/tool_change.cpp @@ -8,6 +8,7 @@ #include "../modules/leds.h" #include "../modules/motion.h" #include "../modules/permanent_storage.h" +#include "../modules/pulley.h" #include "../modules/selector.h" #include "../modules/user_input.h" #include "../debug.h" @@ -132,7 +133,7 @@ bool ToolChange::StepInner() { case ProgressCode::ERREngagingIdler: if (mi::idler.Engaged()) { state = ProgressCode::ERRHelpingFilament; - mm::motion.PlanMove(config::pulleyHelperMove, config::pulleySlowFeedrate); + mp::pulley.PlanMove(config::pulleyHelperMove, config::pulleySlowFeedrate); } return false; case ProgressCode::ERRHelpingFilament: diff --git a/src/logic/unload_filament.cpp b/src/logic/unload_filament.cpp index 802c642..fe55b90 100644 --- a/src/logic/unload_filament.cpp +++ b/src/logic/unload_filament.cpp @@ -7,6 +7,7 @@ #include "../modules/leds.h" #include "../modules/motion.h" #include "../modules/permanent_storage.h" +#include "../modules/pulley.h" #include "../modules/selector.h" #include "../modules/user_input.h" #include "../debug.h" @@ -24,7 +25,7 @@ void UnloadFilament::Reset(uint8_t /*param*/) { } // unloads filament from extruder - filament is above Bondtech gears - mm::motion.InitAxis(mm::Pulley); + mp::pulley.InitAxis(); state = ProgressCode::UnloadingToFinda; error = ErrorCode::RUNNING; unl.Reset(maxRetries); @@ -34,7 +35,7 @@ void UnloadFilament::Reset(uint8_t /*param*/) { void UnloadFilament::FinishedCorrectly() { state = ProgressCode::OK; error = ErrorCode::OK; - mm::motion.Disable(mm::Pulley); + mp::pulley.Disable(); mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::AtPulley); // filament unloaded ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off); } @@ -132,7 +133,7 @@ bool UnloadFilament::StepInner() { case ProgressCode::ERREngagingIdler: if (mi::idler.Engaged()) { state = ProgressCode::ERRHelpingFilament; - mm::motion.PlanMove(-config::pulleyHelperMove, config::pulleySlowFeedrate); + mp::pulley.PlanMove(-config::pulleyHelperMove, config::pulleySlowFeedrate); } return false; case ProgressCode::ERRHelpingFilament: diff --git a/src/logic/unload_to_finda.cpp b/src/logic/unload_to_finda.cpp index 8896a03..3644c58 100644 --- a/src/logic/unload_to_finda.cpp +++ b/src/logic/unload_to_finda.cpp @@ -7,6 +7,7 @@ #include "../modules/leds.h" #include "../modules/motion.h" #include "../modules/permanent_storage.h" +#include "../modules/pulley.h" namespace logic { @@ -32,7 +33,7 @@ bool UnloadToFinda::Step() { case EngagingIdler: if (mg::globals.FilamentLoaded() >= mg::FilamentLoadState::InSelector) { state = UnloadingToFinda; - mm::motion.InitAxis(mm::Pulley); + mp::pulley.InitAxis(); ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0); } else { state = FailedFINDA; @@ -42,8 +43,8 @@ bool UnloadToFinda::Step() { if (mi::idler.Engaged()) { state = WaitingForFINDA; mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InSelector); - unloadStart_mm = CurrentPositionPulley_mm(); - mm::motion.PlanMove(-config::defaultBowdenLength - config::feedToFinda - config::filamentMinLoadedToMMU, config::pulleyUnloadFeedrate); + unloadStart_mm = mp::pulley.CurrentPositionPulley_mm(); + mp::pulley.PlanMove(-config::defaultBowdenLength - config::feedToFinda - config::filamentMinLoadedToMMU, config::pulleyUnloadFeedrate); } return false; case WaitingForFINDA: { diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index 47ff979..eefa559 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources( motion.cpp movable_base.cpp permanent_storage.cpp + pulley.cpp pulse_gen.cpp selector.cpp speed_table.cpp diff --git a/src/modules/idler.cpp b/src/modules/idler.cpp index 771fb7f..9735435 100644 --- a/src/modules/idler.cpp +++ b/src/modules/idler.cpp @@ -29,7 +29,7 @@ void Idler::FinishHomingAndPlanMoveToParkPos() { if (!plannedEngage) { plannedSlot = IdleSlotIndex(); } - InitMovement(mm::Idler); + InitMovement(); } void Idler::FinishMove() { @@ -48,7 +48,7 @@ Idler::OperationResult Idler::Disengage() { // coordinates invalid, first home, then disengage if (!homingValid) { - PerformHome(mm::Idler); + PerformHome(); return OperationResult::Accepted; } @@ -59,7 +59,7 @@ Idler::OperationResult Idler::Disengage() { } // disengaging - return InitMovement(mm::Idler); + return InitMovement(); } Idler::OperationResult Idler::Engage(uint8_t slot) { @@ -81,7 +81,7 @@ Idler::OperationResult Idler::Engage(uint8_t slot) { // so rebooting the MMU while the printer is printing (and thus holding the filament by the moving Idler) // should not be an issue if (!homingValid) { - PlanHome(mm::Idler); + PlanHome(); return OperationResult::Accepted; } @@ -92,26 +92,26 @@ Idler::OperationResult Idler::Engage(uint8_t slot) { } // engaging - return InitMovement(mm::Idler); + return InitMovement(); } bool Idler::Step() { switch (state) { case Moving: // dbg_logic_P(PSTR("Moving Idler")); - PerformMove(mm::Idler); + PerformMove(); return false; case Homing: dbg_logic_P(PSTR("Homing Idler")); - PerformHome(mm::Idler); + PerformHome(); return false; case Ready: if (!homingValid && mg::globals.FilamentLoaded() < mg::InFSensor) { - PlanHome(mm::Idler); + PlanHome(); return false; } return true; - case Failed: + case TMCFailed: dbg_logic_P(PSTR("Idler Failed")); default: return true; @@ -121,7 +121,7 @@ bool Idler::Step() { void Idler::Init() { if (mg::globals.FilamentLoaded() < mg::InFSensor) { // home the Idler only in case we don't have filament loaded in the printer (or at least we think we don't) - PlanHome(mm::Idler); + PlanHome(); } else { // otherwise assume the Idler is at its idle position (that's where it usually is) mm::motion.SetPosition(mm::Idler, SlotPosition(IdleSlotIndex()).v); diff --git a/src/modules/idler.h b/src/modules/idler.h index 7f75ef6..11a7529 100644 --- a/src/modules/idler.h +++ b/src/modules/idler.h @@ -15,7 +15,7 @@ namespace mm = modules::motion; class Idler : public motion::MovableBase { public: inline constexpr Idler() - : MovableBase() + : MovableBase(mm::Idler) , plannedEngage(false) , currentlyEngaged(false) {} diff --git a/src/modules/movable_base.cpp b/src/modules/movable_base.cpp index b367ade..11e2f49 100644 --- a/src/modules/movable_base.cpp +++ b/src/modules/movable_base.cpp @@ -6,7 +6,7 @@ namespace modules { namespace motion { -void MovableBase::PlanHome(config::Axis axis) { +void MovableBase::PlanHome() { // switch to normal mode on this axis mm::motion.InitAxis(axis); mm::motion.SetMode(axis, mm::Normal); @@ -17,22 +17,22 @@ void MovableBase::PlanHome(config::Axis axis) { state = Homing; } -MovableBase::OperationResult MovableBase::InitMovement(config::Axis axis) { +MovableBase::OperationResult MovableBase::InitMovement() { if (motion.InitAxis(axis)) { PrepareMoveToPlannedSlot(); state = Moving; return OperationResult::Accepted; } else { - state = Failed; + state = TMCFailed; return OperationResult::Failed; } } -void MovableBase::PerformMove(config::Axis axis) { +void MovableBase::PerformMove() { if (!mm::motion.DriverForAxis(axis).GetErrorFlags().Good()) { // @@TODO check occasionally, i.e. not every time? // TMC2130 entered some error state, the planned move couldn't have been finished - result of operation is Failed tmcErrorFlags = mm::motion.DriverForAxis(axis).GetErrorFlags(); // save the failed state - state = Failed; + state = TMCFailed; } else if (mm::motion.QueueEmpty(axis)) { // move finished currentSlot = plannedSlot; @@ -41,7 +41,7 @@ void MovableBase::PerformMove(config::Axis axis) { } } -void MovableBase::PerformHome(config::Axis axis) { +void MovableBase::PerformHome() { if (mm::motion.StallGuard(axis)) { // we have reached the end of the axis - homed ok mm::motion.AbortPlannedMoves(axis, true); @@ -53,7 +53,7 @@ void MovableBase::PerformHome(config::Axis axis) { // we ran out of planned moves but no StallGuard event has occurred - homing failed homingValid = false; mm::motion.SetMode(axis, mg::globals.MotorsStealth() ? mm::Stealth : mm::Normal); - state = Failed; + state = HomingFailed; } } diff --git a/src/modules/movable_base.h b/src/modules/movable_base.h index b765aeb..14a8ead 100644 --- a/src/modules/movable_base.h +++ b/src/modules/movable_base.h @@ -15,7 +15,8 @@ public: Ready = 0, // intentionally set as zero in order to allow zeroing the Idler structure upon startup -> avoid explicit initialization code Moving, Homing, - Failed + TMCFailed, + HomingFailed }; /// Operation (Engage/Disengage/MoveToSlot) return values @@ -25,11 +26,12 @@ public: Failed ///< the operation could not been started due to HW issues }; - inline constexpr MovableBase() + inline constexpr MovableBase(config::Axis axis) : state(Ready) , plannedSlot(-1) , currentSlot(-1) - , homingValid(false) {} + , homingValid(false) + , axis(axis) {} /// virtual ~MovableBase(); intentionally disabled, see description in logic::CommandBase @@ -55,6 +57,10 @@ public: /// (which makes homing completely transparent) inline void InvalidateHoming() { homingValid = false; } + inline bool HomingValid() const { return homingValid; } + + inline config::Axis Axis() const { return axis; } + protected: /// internal state of the automaton uint8_t state; @@ -71,19 +77,21 @@ protected: /// cached TMC2130 error flags - being read only if the axis is enabled and doing something (moving) hal::tmc2130::ErrorFlags tmcErrorFlags; + config::Axis axis; + virtual void PrepareMoveToPlannedSlot() = 0; virtual void PlanHomingMove() = 0; virtual void FinishHomingAndPlanMoveToParkPos() = 0; virtual void FinishMove() = 0; - OperationResult InitMovement(config::Axis axis); + OperationResult InitMovement(); /// Prepare a homing move of the axis - void PlanHome(config::Axis axis); + void PlanHome(); - void PerformMove(config::Axis axis); + void PerformMove(); - void PerformHome(config::Axis axis); + void PerformHome(); }; } // namespace motion diff --git a/src/modules/pulley.cpp b/src/modules/pulley.cpp new file mode 100644 index 0000000..f6eb4c9 --- /dev/null +++ b/src/modules/pulley.cpp @@ -0,0 +1,55 @@ +/// @file pulley.cpp +#include "pulley.h" +#include "buttons.h" +#include "globals.h" +#include "leds.h" +#include "motion.h" +#include "permanent_storage.h" +#include "../debug.h" + +namespace modules { +namespace pulley { + +Pulley pulley; + +void Pulley::FinishHomingAndPlanMoveToParkPos() { + mm::motion.SetPosition(mm::Pulley, 0); +} + +bool Pulley::Step() { + switch (state) { + case Moving: + PerformMove(); + return false; + case Homing: + homingValid = true; + FinishHomingAndPlanMoveToParkPos(); + return true; + case Ready: + return true; + case TMCFailed: + default: + return true; + } +} + +void Pulley::PlanMove(unit::U_mm delta, unit::U_mm_s feed_rate, unit::U_mm_s end_rate) { + mm::motion.PlanMove(delta, feed_rate, end_rate); + state = Moving; +} + +int32_t Pulley::CurrentPositionPulley_mm() { + return mm::stepsToUnit(mm::P_pos_t({ mm::motion.CurPosition(mm::Pulley) })); +} + +void Pulley::InitAxis() { + mm::motion.InitAxis(mm::Pulley); +} + +void Pulley::Disable() { + mm::motion.Disable(mm::Pulley); + state = Ready; +} + +} // namespace pulley +} // namespace modules diff --git a/src/modules/pulley.h b/src/modules/pulley.h new file mode 100644 index 0000000..12e70ce --- /dev/null +++ b/src/modules/pulley.h @@ -0,0 +1,50 @@ +/// @file pulley.h +#pragma once +#include "../config/config.h" +#include "axisunit.h" +#include "../unit.h" +#include "movable_base.h" + +namespace modules { + +/// The pulley namespace provides all necessary facilities related to the logical model of the pulley device of the MMU unit. +namespace pulley { + +namespace mm = modules::motion; + +/// The Pulley model is an analogy to Idler and Selector. +/// It encapsulates the same error handling principles like the other two (motored) modules. +/// On the other hand - the Pulley is much simpler, there is no homing, engage/disengage and slots, +/// but it supports free rotation in either directions and some computation on top of it. +class Pulley : public motion::MovableBase { +public: + inline constexpr Pulley() + : MovableBase(mm::Pulley) {} + + /// Performs one step of the state machine according to currently planned operation + /// @returns true if the pulley is ready to accept new commands (i.e. it has finished the last operation) + bool Step(); + + void PlanMove(unit::U_mm delta, unit::U_mm_s feed_rate, unit::U_mm_s end_rate = { 0 }); + + /// @returns rounded current position (rotation) of the Pulley + /// This exists purely to avoid expensive float (long double) computations of distance traveled by the filament + int32_t CurrentPositionPulley_mm(); + + void InitAxis(); + void Disable(); + +protected: + virtual void PrepareMoveToPlannedSlot() override {} + virtual void PlanHomingMove() override {} + virtual void FinishHomingAndPlanMoveToParkPos() override; + virtual void FinishMove() override {} +}; + +/// The one and only instance of Pulley in the FW +extern Pulley pulley; + +} // namespace pulley +} // namespace modules + +namespace mp = modules::pulley; diff --git a/src/modules/selector.cpp b/src/modules/selector.cpp index 6f2e4f1..09af3bd 100644 --- a/src/modules/selector.cpp +++ b/src/modules/selector.cpp @@ -31,7 +31,7 @@ void Selector::FinishHomingAndPlanMoveToParkPos() { if (plannedSlot > config::toolCount) { plannedSlot = IdleSlotIndex(); } - InitMovement(mm::Selector); + InitMovement(); } void Selector::FinishMove() { @@ -52,7 +52,7 @@ Selector::OperationResult Selector::MoveToSlot(uint8_t slot) { // coordinates invalid, first home, then engage if (!homingValid && mg::globals.FilamentLoaded() < mg::FilamentLoadState::InSelector) { - PlanHome(mm::Selector); + PlanHome(); return OperationResult::Accepted; } @@ -63,26 +63,26 @@ Selector::OperationResult Selector::MoveToSlot(uint8_t slot) { } // do the move - return InitMovement(mm::Selector); + return InitMovement(); } bool Selector::Step() { switch (state) { case Moving: - PerformMove(mm::Selector); + PerformMove(); //dbg_logic_P(PSTR("Moving Selector")); return false; case Homing: dbg_logic_P(PSTR("Homing Selector")); - PerformHome(mm::Selector); + PerformHome(); return false; case Ready: if (!homingValid && mg::globals.FilamentLoaded() < mg::InSelector) { - PlanHome(mm::Selector); + PlanHome(); return false; } return true; - case Failed: + case TMCFailed: dbg_logic_P(PSTR("Selector Failed")); default: return true; @@ -92,7 +92,7 @@ bool Selector::Step() { void Selector::Init() { if (mg::globals.FilamentLoaded() < mg::FilamentLoadState::InSelector && (!mf::finda.Pressed())) { // home the Selector only in case we don't have filament loaded (or at least we think we don't) - PlanHome(mm::Selector); + PlanHome(); } else { // otherwise set selector's position according to know slot positions (and pretend it is correct) mm::motion.SetPosition(mm::Selector, SlotPosition(mg::globals.ActiveSlot()).v); diff --git a/src/modules/selector.h b/src/modules/selector.h index f2fcec1..3170323 100644 --- a/src/modules/selector.h +++ b/src/modules/selector.h @@ -15,7 +15,7 @@ namespace mm = modules::motion; class Selector : public mm::MovableBase { public: inline constexpr Selector() - : MovableBase() {} + : MovableBase(mm::Selector) {} /// Plan move of the selector to a specific filament slot /// @param slot index to move to diff --git a/tests/unit/logic/cut_filament/CMakeLists.txt b/tests/unit/logic/cut_filament/CMakeLists.txt index eda20ee..8afcaa4 100644 --- a/tests/unit/logic/cut_filament/CMakeLists.txt +++ b/tests/unit/logic/cut_filament/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulley.cpp ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp diff --git a/tests/unit/logic/eject_filament/CMakeLists.txt b/tests/unit/logic/eject_filament/CMakeLists.txt index 5113b18..c0efedc 100644 --- a/tests/unit/logic/eject_filament/CMakeLists.txt +++ b/tests/unit/logic/eject_filament/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulley.cpp ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp diff --git a/tests/unit/logic/failing_tmc/CMakeLists.txt b/tests/unit/logic/failing_tmc/CMakeLists.txt index 0c7fa64..79b716f 100644 --- a/tests/unit/logic/failing_tmc/CMakeLists.txt +++ b/tests/unit/logic/failing_tmc/CMakeLists.txt @@ -3,6 +3,7 @@ add_executable( failing_tmc_tests ${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp ${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp + ${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp ${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp ${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp ${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp @@ -15,6 +16,7 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulley.cpp ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp diff --git a/tests/unit/logic/failing_tmc/test_failing_tmc.cpp b/tests/unit/logic/failing_tmc/test_failing_tmc.cpp index 8f8c47f..1d80f72 100644 --- a/tests/unit/logic/failing_tmc/test_failing_tmc.cpp +++ b/tests/unit/logic/failing_tmc/test_failing_tmc.cpp @@ -15,6 +15,7 @@ #include "../../../../src/modules/selector.h" #include "../../../../src/logic/unload_filament.h" +#include "../../../../src/logic/load_filament.h" #include "../../modules/stubs/stub_adc.h" @@ -34,7 +35,7 @@ inline ErrorCode operator|(ErrorCode a, ErrorCode b) { return (ErrorCode)((uint16_t)a | (uint16_t)b); } -void FailingIdler(hal::tmc2130::ErrorFlags ef, ErrorCode ec) { +void FailingMovableUnload(hal::tmc2130::ErrorFlags ef, ErrorCode ec, config::Axis axis, uint32_t failingStep) { // prepare startup conditions ForceReinitAllAutomata(); @@ -54,15 +55,14 @@ void FailingIdler(hal::tmc2130::ErrorFlags ef, ErrorCode ec) { REQUIRE(VerifyState(uf, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), 0, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda)); - uint32_t failingStep = 5; REQUIRE(WhileCondition( uf, [&](uint32_t step) -> bool { if(step == failingStep){ // on 5th step make the TMC report some error - CauseTMCError(mm::Idler, ef); + CauseTMCError(axis, ef); } return uf.TopLevelState() == ProgressCode::UnloadingToFinda; }, - 5000)); + 50000)); // the simulated motion may proceed, but I don't care here. In reality no one really knows what the TMC does // The checked value is not really important here (just that it moves!), so with tuning of the constants it may break the unit test @@ -78,15 +78,75 @@ void FailingIdler(hal::tmc2130::ErrorFlags ef, ErrorCode ec) { REQUIRE(ml::leds.Mode(0, ml::red) == ml::off); REQUIRE(ml::leds.Mode(0, ml::green) == ml::blink0); REQUIRE(uf.Error() == ec); - REQUIRE(uf.TopLevelState() == ProgressCode::ERRTMCFailed); + REQUIRE(uf.TopLevelState() == ProgressCode::ERRWaitingForUser); main_loop(); uf.Step(); } } +void FailingMovableLoad(hal::tmc2130::ErrorFlags ef, ErrorCode ec, config::Axis axis, uint32_t failingStep, uint8_t slot) { + // prepare startup conditions + ForceReinitAllAutomata(); + + // change the startup to what we need here + EnsureActiveSlotIndex(5, mg::FilamentLoadState::AtPulley); + + // set FINDA OFF + debounce + SetFINDAStateAndDebounce(false); + + logic::LoadFilament lf; + + // verify startup conditions + REQUIRE(VerifyState(lf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), ms::Selector::IdleSlotIndex(), false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK)); + + // UnloadFilament starts by engaging the idler (through the UnloadToFinda state machine) + lf.Reset(slot); + + REQUIRE(WhileCondition( + lf, + [&](uint32_t step) -> bool { + if(step == failingStep){ // on 5th step make the TMC report some error + CauseTMCError(axis, ef); + } + return lf.TopLevelState() == ProgressCode::FeedingToFinda; }, + 50000)); + + // the simulated motion may proceed, but I don't care here. In reality no one really knows what the TMC does + // The checked value is not really important here (just that it moves!), so with tuning of the constants it may break the unit test + // Therefore it is disabled by default + // REQUIRE(mm::axes[mm::Idler].pos == failingStep * config::pulleyToCuttingEdge.v + 1); + + // repeated calls to step this logic automaton shall produce no change + for (int i = 0; i < 5; ++i) { + // and this must cause the state machine to run into a TMC error state and report the error correctly + // Please note we are leaving the Idler in an intermediate position due to the TMC failure, + // so we cannot use the usual VerifyState(), but have to check the stuff manually + // REQUIRE(VerifyState(uf, true, raw_6, 0, false, ml::blink0, ml::blink0, ec, ProgressCode::ERRTMCFailed)); + REQUIRE(ml::leds.Mode(0, ml::red) == ml::off); + REQUIRE(ml::leds.Mode(0, ml::green) == ml::blink0); + REQUIRE(lf.Error() == ec); + REQUIRE(lf.TopLevelState() == ProgressCode::ERRWaitingForUser); + + main_loop(); + lf.Step(); + } +} + TEST_CASE("failing_tmc::failing_idler", "[failing_tmc]") { hal::tmc2130::ErrorFlags ef; ef.ot = 1; // make the TMC hot like hell - FailingIdler(ef, ErrorCode::TMC_OVER_TEMPERATURE_ERROR | ErrorCode::TMC_IDLER_BIT); + FailingMovableUnload(ef, ErrorCode::TMC_OVER_TEMPERATURE_ERROR | ErrorCode::TMC_IDLER_BIT, mm::Idler, 5); +} + +TEST_CASE("failing_tmc::failing_selector", "[failing_tmc]") { + hal::tmc2130::ErrorFlags ef; + ef.ot = 1; // make the TMC hot like hell + FailingMovableLoad(ef, ErrorCode::TMC_OVER_TEMPERATURE_ERROR | ErrorCode::TMC_SELECTOR_BIT, mm::Selector, 5, 0); +} + +TEST_CASE("failing_tmc::failing_pulley", "[failing_tmc]") { + hal::tmc2130::ErrorFlags ef; + ef.ot = 1; // make the TMC hot like hell + FailingMovableUnload(ef, ErrorCode::TMC_OVER_TEMPERATURE_ERROR | ErrorCode::TMC_PULLEY_BIT, mm::Pulley, 2000); } diff --git a/tests/unit/logic/feed_to_bondtech/CMakeLists.txt b/tests/unit/logic/feed_to_bondtech/CMakeLists.txt index 7558c11..99b84ba 100644 --- a/tests/unit/logic/feed_to_bondtech/CMakeLists.txt +++ b/tests/unit/logic/feed_to_bondtech/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulley.cpp ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp diff --git a/tests/unit/logic/feed_to_finda/CMakeLists.txt b/tests/unit/logic/feed_to_finda/CMakeLists.txt index 0f93766..ad87517 100644 --- a/tests/unit/logic/feed_to_finda/CMakeLists.txt +++ b/tests/unit/logic/feed_to_finda/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulley.cpp ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp diff --git a/tests/unit/logic/load_filament/CMakeLists.txt b/tests/unit/logic/load_filament/CMakeLists.txt index bb8199a..966750d 100644 --- a/tests/unit/logic/load_filament/CMakeLists.txt +++ b/tests/unit/logic/load_filament/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulley.cpp ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp diff --git a/tests/unit/logic/stubs/main_loop_stub.cpp b/tests/unit/logic/stubs/main_loop_stub.cpp index 53c5108..791ef4d 100644 --- a/tests/unit/logic/stubs/main_loop_stub.cpp +++ b/tests/unit/logic/stubs/main_loop_stub.cpp @@ -12,6 +12,7 @@ #include "../../../../src/modules/leds.h" #include "../../../../src/modules/motion.h" #include "../../../../src/modules/permanent_storage.h" +#include "../../../../src/modules/pulley.h" #include "../../../../src/modules/selector.h" #include "../../../../src/modules/user_input.h" @@ -26,6 +27,7 @@ void main_loop() { mf::finda.Step(); mfs::fsensor.Step(); mi::idler.Step(); + mp::pulley.Step(); ms::selector.Step(); mm::motion.Step(); mui::userInput.Step(); @@ -50,6 +52,7 @@ void ForceReinitAllAutomata() { new (&mf::finda) mf::FINDA(); new (&mfs::fsensor) mfs::FSensor(); new (&mi::idler) mi::Idler(); + new (&mp::pulley) mp::Pulley(); new (&ms::selector) ms::Selector(); new (&mm::motion) mm::Motion(); @@ -137,7 +140,7 @@ void EnsureActiveSlotIndex(uint8_t slot, mg::FilamentLoadState loadState) { } void SetFINDAStateAndDebounce(bool press) { - hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::high); + hal::gpio::WritePin(FINDA_PIN, press ? hal::gpio::Level::high : hal::gpio::Level::low); for (size_t i = 0; i < config::findaDebounceMs + 1; ++i) main_loop(); } diff --git a/tests/unit/logic/tool_change/CMakeLists.txt b/tests/unit/logic/tool_change/CMakeLists.txt index 13cb494..b0057a7 100644 --- a/tests/unit/logic/tool_change/CMakeLists.txt +++ b/tests/unit/logic/tool_change/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulley.cpp ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp diff --git a/tests/unit/logic/unload_filament/CMakeLists.txt b/tests/unit/logic/unload_filament/CMakeLists.txt index b7fa33f..dcaf237 100644 --- a/tests/unit/logic/unload_filament/CMakeLists.txt +++ b/tests/unit/logic/unload_filament/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulley.cpp ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp diff --git a/tests/unit/logic/unload_to_finda/CMakeLists.txt b/tests/unit/logic/unload_to_finda/CMakeLists.txt index 33ace3b..6a0694c 100644 --- a/tests/unit/logic/unload_to_finda/CMakeLists.txt +++ b/tests/unit/logic/unload_to_finda/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulley.cpp ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp