diff --git a/src/application.cpp b/src/application.cpp index 69d743b..6285917 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -128,8 +128,8 @@ void Application::PlanCommand(const modules::protocol::RequestMsg &rq) { break; } currentCommandRq = rq; // save the Current Command Request for indentification of responses - currentCommand->Reset(rq.value); - ReportCommandAccepted(rq, mp::ResponseMsgParamCodes::Accepted); + bool accepted = currentCommand->Reset(rq.value); + ReportCommandAccepted(rq, accepted ? mp::ResponseMsgParamCodes::Accepted : mp::ResponseMsgParamCodes::Rejected); } else { ReportCommandAccepted(rq, mp::ResponseMsgParamCodes::Rejected); } diff --git a/src/logic/command_base.h b/src/logic/command_base.h index 0d8eee5..5af61f7 100644 --- a/src/logic/command_base.h +++ b/src/logic/command_base.h @@ -38,7 +38,8 @@ public: /// resets the automaton /// @param param numerical parameter that comes with some commands (e.g. T1 for tool change 1) - virtual void Reset(uint8_t param) = 0; + /// @returns true if the command was accepted and started (which may not be possible e.g. due to filament position) + virtual bool Reset(uint8_t param) = 0; /// Steps the state machine. This is the preferred way of stepping the machine /// as it handles the global HW error states uniformly (so that the derived classes do not have to deal diff --git a/src/logic/cut_filament.cpp b/src/logic/cut_filament.cpp index 7326283..b45ef94 100644 --- a/src/logic/cut_filament.cpp +++ b/src/logic/cut_filament.cpp @@ -14,9 +14,9 @@ namespace logic { CutFilament cutFilament; -void CutFilament::Reset(uint8_t param) { +bool CutFilament::Reset(uint8_t param) { if (!CheckToolIndex(param)) { - return; + return false; } error = ErrorCode::RUNNING; @@ -28,6 +28,7 @@ void CutFilament::Reset(uint8_t param) { } else { SelectFilamentSlot(); } + return true; } void CutFilament::SelectFilamentSlot() { diff --git a/src/logic/cut_filament.h b/src/logic/cut_filament.h index ae48413..1e69575 100644 --- a/src/logic/cut_filament.h +++ b/src/logic/cut_filament.h @@ -15,7 +15,7 @@ public: /// Restart the automaton /// @param param index of filament slot to perform cut onto - void Reset(uint8_t param) override; + bool Reset(uint8_t param) override; /// @returns true if the state machine finished its job, false otherwise bool StepInner() override; diff --git a/src/logic/eject_filament.cpp b/src/logic/eject_filament.cpp index 4eff71e..19f543f 100644 --- a/src/logic/eject_filament.cpp +++ b/src/logic/eject_filament.cpp @@ -15,9 +15,9 @@ namespace logic { EjectFilament ejectFilament; -void EjectFilament::Reset(uint8_t param) { +bool EjectFilament::Reset(uint8_t param) { if (!CheckToolIndex(param)) { - return; + return false; } error = ErrorCode::RUNNING; @@ -32,6 +32,7 @@ void EjectFilament::Reset(uint8_t param) { } else { MoveSelectorAside(); } + return true; } void EjectFilament::MoveSelectorAside() { diff --git a/src/logic/eject_filament.h b/src/logic/eject_filament.h index 10b68b0..998d966 100644 --- a/src/logic/eject_filament.h +++ b/src/logic/eject_filament.h @@ -27,7 +27,7 @@ public: /// Restart the automaton /// @param param index of filament slot to eject - void Reset(uint8_t param) override; + bool Reset(uint8_t param) override; /// @returns true if the state machine finished its job, false otherwise bool StepInner() override; diff --git a/src/logic/home.cpp b/src/logic/home.cpp index 642fcfa..cded6fd 100644 --- a/src/logic/home.cpp +++ b/src/logic/home.cpp @@ -12,10 +12,11 @@ namespace logic { Home home; -void Home::Reset(uint8_t /*param*/) { +bool Home::Reset(uint8_t /*param*/) { error = ErrorCode::RUNNING; state = ProgressCode::Homing; InvalidateHomingAndFilamentState(); + return true; } bool Home::StepInner() { diff --git a/src/logic/home.h b/src/logic/home.h index eb07d1e..560f257 100644 --- a/src/logic/home.h +++ b/src/logic/home.h @@ -25,7 +25,7 @@ public: /// Restart the automaton /// @param param unused - void Reset(uint8_t /*param*/) override; + bool Reset(uint8_t /*param*/) override; /// @returns true if the state machine finished its job, false otherwise bool StepInner() override; diff --git a/src/logic/load_filament.cpp b/src/logic/load_filament.cpp index 658e978..0d11a40 100644 --- a/src/logic/load_filament.cpp +++ b/src/logic/load_filament.cpp @@ -15,14 +15,22 @@ namespace logic { LoadFilament loadFilament; -void LoadFilament::Reset(uint8_t param) { +bool LoadFilament::Reset(uint8_t param) { if (!CheckToolIndex(param)) { - return; + return false; + } + if (mg::globals.FilamentLoaded() > mg::FilamentLoadState::InSelector) { + return false; // avoid starting loadfilament if there is already some filament in the selector in some OTHER slot + } + // there is one special case though - same slot AND filament load state == InSelector (it MUST NOT be anywhere farther) + if (mg::globals.FilamentLoaded() > mg::FilamentLoadState::AtPulley && mg::globals.ActiveSlot() != param) { + return false; } dbg_logic_P(PSTR("Load Filament")); mg::globals.SetFilamentLoaded(param, mg::FilamentLoadState::AtPulley); // still at pulley, haven't moved yet verifyLoadedFilament = 1; Reset2(false); + return true; } void LoadFilament::ResetLimited(uint8_t param) { diff --git a/src/logic/load_filament.h b/src/logic/load_filament.h index 66afdd6..76c1793 100644 --- a/src/logic/load_filament.h +++ b/src/logic/load_filament.h @@ -16,7 +16,7 @@ public: /// Restart the automaton - performs unlimited rotation of the Pulley /// @param param index of filament slot to load - void Reset(uint8_t param) override; + bool Reset(uint8_t param) override; /// Restart the automaton for a limited rotation of the Pulley /// @param param index of filament slot to load diff --git a/src/logic/move_selector.cpp b/src/logic/move_selector.cpp index 6becc4b..a6f687d 100644 --- a/src/logic/move_selector.cpp +++ b/src/logic/move_selector.cpp @@ -8,14 +8,16 @@ namespace logic { MoveSelector moveSelector; -void MoveSelector::Reset(uint8_t param) { +bool MoveSelector::Reset(uint8_t param) { state = ProgressCode::MovingSelector; if (ms::selector.MoveToSlot(param) != ms::Selector::OperationResult::Refused) { // operation accepted error = ErrorCode::RUNNING; + return true; } else { error = ErrorCode::HOMING_SELECTOR_FAILED; // @@TODO + return false; } } diff --git a/src/logic/move_selector.h b/src/logic/move_selector.h index 8be1fab..f0a0a37 100644 --- a/src/logic/move_selector.h +++ b/src/logic/move_selector.h @@ -20,7 +20,7 @@ public: /// Restart the automaton /// @param param target selector slot - void Reset(uint8_t param) override; + bool Reset(uint8_t param) override; /// @returns true if the state machine finished its job, false otherwise bool StepInner() override; diff --git a/src/logic/no_command.h b/src/logic/no_command.h index 2064b3a..c65ef17 100644 --- a/src/logic/no_command.h +++ b/src/logic/no_command.h @@ -12,7 +12,7 @@ public: : CommandBase() {} /// Restart the automaton - void Reset(uint8_t /*param*/) override {} + bool Reset(uint8_t /*param*/) override { return true; } /// @returns true if the state machine finished its job, false otherwise bool StepInner() override { return true; } diff --git a/src/logic/set_mode.cpp b/src/logic/set_mode.cpp index 60e7d70..abf3e8a 100644 --- a/src/logic/set_mode.cpp +++ b/src/logic/set_mode.cpp @@ -7,11 +7,12 @@ namespace logic { SetMode setMode; -void SetMode::Reset(uint8_t param) { +bool SetMode::Reset(uint8_t param) { mg::globals.SetMotorsMode(param != 0); // remember the last mode set // distribute the mode to all motors immediately mm::motion.SetMode((param == 0) ? mm::Normal : mm::Stealth); FinishedOK(); + return true; } } // namespace logic diff --git a/src/logic/set_mode.h b/src/logic/set_mode.h index dc372f0..7e25a37 100644 --- a/src/logic/set_mode.h +++ b/src/logic/set_mode.h @@ -17,7 +17,7 @@ public: : CommandBase() {} /// Restart the automaton - void Reset(uint8_t param) override; + bool Reset(uint8_t param) override; /// @returns true if the state machine finished its job, false otherwise /// Since we perform the TMC2130 mode change in the Reset directly, the return is always true here (command finished ok) diff --git a/src/logic/tool_change.cpp b/src/logic/tool_change.cpp index 7f8cb19..df21ba4 100644 --- a/src/logic/tool_change.cpp +++ b/src/logic/tool_change.cpp @@ -17,15 +17,15 @@ namespace logic { ToolChange toolChange; -void ToolChange::Reset(uint8_t param) { +bool ToolChange::Reset(uint8_t param) { if (!CheckToolIndex(param)) { - return; + return false; } if (param == mg::globals.ActiveSlot() && (mg::globals.FilamentLoaded() == mg::FilamentLoadState::InNozzle)) { // we are already at the correct slot and the filament is loaded in the nozzle - nothing to do dbg_logic_P(PSTR("we are already at the correct slot and the filament is loaded - nothing to do\n")); - return; + return true; } // we are either already at the correct slot, just the filament is not loaded - load the filament directly @@ -43,6 +43,7 @@ void ToolChange::Reset(uint8_t param) { mg::globals.SetFilamentLoaded(plannedSlot, mg::FilamentLoadState::InSelector); feed.Reset(true, false); } + return true; } void logic::ToolChange::GoToFeedingToBondtech() { diff --git a/src/logic/tool_change.h b/src/logic/tool_change.h index 2d84071..848f499 100644 --- a/src/logic/tool_change.h +++ b/src/logic/tool_change.h @@ -16,7 +16,7 @@ public: /// Restart the automaton /// @param param index of filament slot to change to - i.e. to load - void Reset(uint8_t param) override; + bool Reset(uint8_t param) override; /// @returns true if the state machine finished its job, false otherwise bool StepInner() override; diff --git a/src/logic/unload_filament.cpp b/src/logic/unload_filament.cpp index 2509231..122367f 100644 --- a/src/logic/unload_filament.cpp +++ b/src/logic/unload_filament.cpp @@ -16,12 +16,12 @@ namespace logic { UnloadFilament unloadFilament; -void UnloadFilament::Reset(uint8_t /*param*/) { +bool UnloadFilament::Reset(uint8_t /*param*/) { if (!mf::finda.Pressed() && mg::globals.FilamentLoaded() < mg::FilamentLoadState::InSelector) { // it looks like we have nothing in the PTFE tube, at least FINDA doesn't sense anything // so the filament has been probably already unloaded - terminate with OK or report an error? - return; + return true; } // unloads filament from extruder - filament is above Bondtech gears @@ -30,6 +30,7 @@ void UnloadFilament::Reset(uint8_t /*param*/) { error = ErrorCode::RUNNING; unl.Reset(maxRetries); ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off); + return true; } void UnloadFilament::UnloadFinishedCorrectly() { diff --git a/src/logic/unload_filament.h b/src/logic/unload_filament.h index 23ba850..c22bedd 100644 --- a/src/logic/unload_filament.h +++ b/src/logic/unload_filament.h @@ -16,7 +16,7 @@ public: /// Restart the automaton /// @param param is not used, always unloads from the active slot - void Reset(uint8_t param) override; + bool Reset(uint8_t param) override; /// @returns true if the state machine finished its job, false otherwise bool StepInner() override; diff --git a/tests/unit/logic/load_filament/test_load_filament.cpp b/tests/unit/logic/load_filament/test_load_filament.cpp index b70d304..8ad1750 100644 --- a/tests/unit/logic/load_filament/test_load_filament.cpp +++ b/tests/unit/logic/load_filament/test_load_filament.cpp @@ -351,3 +351,41 @@ TEST_CASE("load_filament::unlimited_load_manual_stop", "[load_filament]") { LoadFilamentStopped(slot, lf); } } + +void LoadFilamentAlreadyPresentFilament(uint8_t slot, logic::LoadFilament &lf) { + //one of the first steps of the state machine should pick up the fact that FINDA is on and transfer into the retracting phase + REQUIRE(WhileTopState(lf, ProgressCode::FeedingToFinda, 5000)); + REQUIRE(VerifyState(lf, mg::FilamentLoadState::InSelector, slot, slot, true, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::RetractingFromFinda)); + REQUIRE(WhileCondition(lf, std::bind(SimulateRetractFromFINDA, _1, 100), 5000)); + REQUIRE(WhileTopState(lf, ProgressCode::RetractingFromFinda, 5000)); + REQUIRE(VerifyState(lf, mg::FilamentLoadState::AtPulley, slot, slot, false, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::FeedingToFinda)); + // make FINDA switch on again + REQUIRE(WhileCondition(lf, std::bind(SimulateFeedToFINDA, _1, 100), 5000)); + REQUIRE(WhileTopState(lf, ProgressCode::FeedingToFinda, 5000)); + REQUIRE(VerifyState(lf, mg::FilamentLoadState::InSelector, slot, slot, true, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::RetractingFromFinda)); + // make FINDA switch off again + REQUIRE(WhileCondition(lf, std::bind(SimulateRetractFromFINDA, _1, 100), 5000)); + REQUIRE(WhileTopState(lf, ProgressCode::RetractingFromFinda, 5000)); +} + +TEST_CASE("load_filament::avoid_load_filament_finda", "[load_filament]") { + auto fls = GENERATE(mg::FilamentLoadState::InSelector, mg::FilamentLoadState::InFSensor, mg::FilamentLoadState::InNozzle); + + for (uint8_t slot = 0; slot < config::toolCount; ++slot) { + for (uint8_t activeSlot = 0; activeSlot < config::toolCount; ++activeSlot) { + logic::LoadFilament lf; + ForceReinitAllAutomata(); + SetFINDAStateAndDebounce(true); + EnsureActiveSlotIndex(activeSlot, fls); + REQUIRE(VerifyState(lf, fls, mi::Idler::IdleSlotIndex(), activeSlot, true, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK)); + bool accepted = lf.Reset(slot); + if (activeSlot != slot) { + REQUIRE_FALSE(accepted); + } else if (activeSlot == slot && fls <= mg::FilamentLoadState::InSelector) { + LoadFilamentAlreadyPresentFilament(slot, lf); + } else { + REQUIRE_FALSE(accepted); + } + } + } +}