diff --git a/src/logic/error_codes.h b/src/logic/error_codes.h index bc495f9..66734a7 100644 --- a/src/logic/error_codes.h +++ b/src/logic/error_codes.h @@ -41,6 +41,11 @@ enum class ErrorCode : uint_fast16_t { FINDA_VS_EEPROM_DISREPANCY = 0x8008, ///< E32776 FINDA is pressed but we have no such record in EEPROM - this can only happen at the start of the MMU and can be resolved by issuing an Unload command + FSENSOR_TOO_EARLY = 0x8009, ///< E32777 FSensor triggered while doing FastFeedToBondtech - that means either: + ///< - the PTFE is too short + ///< - a piece of filament was left inside - pushed in front of the loaded filament causing the fsensor trigger too early + ///< - fsensor is faulty producing bogus triggers + QUEUE_FULL = 0x802b, ///< E32811 internal logic error - attempt to move with a full queue VERSION_MISMATCH = 0x802c, ///< E32812 internal error of the printer - incompatible version of the MMU FW diff --git a/src/logic/feed_to_bondtech.cpp b/src/logic/feed_to_bondtech.cpp index 28e36ce..7f71b79 100644 --- a/src/logic/feed_to_bondtech.cpp +++ b/src/logic/feed_to_bondtech.cpp @@ -34,7 +34,7 @@ bool FeedToBondtech::Step() { if (mi::idler.Engaged()) { dbg_logic_P(PSTR("Feed to Bondtech --> Idler engaged")); dbg_logic_fP(PSTR("Pulley start steps %u"), mpu::pulley.CurrentPosition_mm()); - state = PushingFilamentToFSensor; + state = PushingFilamentFast; mpu::pulley.InitAxis(); // plan a fast move while in the safe minimal length mpu::pulley.PlanMove(config::minimumBowdenLength, config::pulleyLoadFeedrate, config::pulleySlowFeedrate); @@ -42,14 +42,26 @@ bool FeedToBondtech::Step() { mpu::pulley.PlanMove(config::maximumBowdenLength - config::minimumBowdenLength, config::pulleySlowFeedrate, config::pulleySlowFeedrate); } return false; + case PushingFilamentFast: + if (mfs::fsensor.Pressed()) { + // Safety precaution - if the fsensor triggers while pushing the filament fast, we must stop pushing immediately + // With a correctly set-up MMU this shouldn't happen + mm::motion.AbortPlannedMoves(); // stop pushing filament + state = FSensorTooEarly; + } else if (mm::motion.PlannedMoves(mm::Pulley) == 1) { + // a bit of a hack - the fast (already planned) move has finished, doing the slow part + // -> just switch to FeedingToFSensor + state = PushingFilamentToFSensor; + } + return false; case PushingFilamentToFSensor: //dbg_logic_P(PSTR("Feed to Bondtech --> Pushing")); if (mfs::fsensor.Pressed()) { mm::motion.AbortPlannedMoves(); // stop pushing filament GoToPushToNozzle(); - } else if (mm::motion.StallGuard(mm::Pulley)) { - // stall guard occurred during movement - the filament got stuck - state = Failed; // @@TODO may be even report why it failed + // } else if (mm::motion.StallGuard(mm::Pulley)) { + // // stall guard occurred during movement - the filament got stuck + // state = PulleyStalled; } else if (mm::motion.QueueEmpty()) { // all moves have been finished and the fsensor didn't switch on state = Failed; } @@ -76,6 +88,8 @@ bool FeedToBondtech::Step() { dbg_logic_P(PSTR("Feed to Bondtech OK")); return true; case Failed: + case FSensorTooEarly: + // case PulleyStalled: dbg_logic_P(PSTR("Feed to Bondtech FAILED")); return true; default: diff --git a/src/logic/feed_to_bondtech.h b/src/logic/feed_to_bondtech.h index b4a28bc..146c48a 100644 --- a/src/logic/feed_to_bondtech.h +++ b/src/logic/feed_to_bondtech.h @@ -14,11 +14,14 @@ struct FeedToBondtech { /// internal states of the state machine enum { EngagingIdler, + PushingFilamentFast, PushingFilamentToFSensor, PushingFilamentIntoNozzle, DisengagingIdler, OK, - Failed + Failed, + FSensorTooEarly, + // PulleyStalled }; inline FeedToBondtech() diff --git a/src/logic/progress_codes.h b/src/logic/progress_codes.h index 6b37ce4..7dd2e19 100644 --- a/src/logic/progress_codes.h +++ b/src/logic/progress_codes.h @@ -39,5 +39,7 @@ enum class ProgressCode : uint_fast8_t { Homing, // P26 MovingSelector, // P27 + FeedingToFSensor, // P28 + Empty = 0xff // dummy empty state }; diff --git a/src/logic/tool_change.cpp b/src/logic/tool_change.cpp index 62438bf..c524486 100644 --- a/src/logic/tool_change.cpp +++ b/src/logic/tool_change.cpp @@ -81,9 +81,14 @@ bool ToolChange::StepInner() { break; case ProgressCode::FeedingToBondtech: if (james.Step()) { - if (james.State() == FeedToBondtech::Failed) { + switch (james.State()) { + case FeedToBondtech::Failed: GoToErrDisengagingIdler(ErrorCode::FSENSOR_DIDNT_SWITCH_ON); // signal loading error - } else { + break; + case FeedToBondtech::FSensorTooEarly: + GoToErrDisengagingIdler(ErrorCode::FSENSOR_TOO_EARLY); // signal loading error + break; + default: ToolChangeFinishedCorrectly(); } } @@ -163,6 +168,15 @@ ProgressCode ToolChange::State() const { switch (state) { case ProgressCode::UnloadingFilament: return unl.State(); // report sub-automaton states properly + case ProgressCode::FeedingToBondtech: + // only process the important states + switch (james.State()) { + case FeedToBondtech::PushingFilamentToFSensor: + return ProgressCode::FeedingToFSensor; + case FeedToBondtech::PushingFilamentIntoNozzle: + return ProgressCode::FeedingToNozzle; + } + // [[fallthrough]] // everything else is reported as FeedingToBondtech default: return state; } diff --git a/tests/unit/logic/feed_to_bondtech/test_feed_to_bondtech.cpp b/tests/unit/logic/feed_to_bondtech/test_feed_to_bondtech.cpp index e8e61eb..65424ee 100644 --- a/tests/unit/logic/feed_to_bondtech/test_feed_to_bondtech.cpp +++ b/tests/unit/logic/feed_to_bondtech/test_feed_to_bondtech.cpp @@ -52,14 +52,21 @@ TEST_CASE("feed_to_bondtech::feed_phase_unlimited", "[feed_to_bondtech]") { CHECK(mm::axes[mm::Pulley].enabled); // idler engaged, selector in position, we'll start pushing filament - REQUIRE(fb.State() == FeedToBondtech::PushingFilamentToFSensor); + REQUIRE(fb.State() == FeedToBondtech::PushingFilamentFast); // at least at the beginning the LED should shine green (it should be blinking, but this mode has been already verified in the LED's unit test) REQUIRE(ml::leds.Mode(mg::globals.ActiveSlot(), ml::green) == ml::blink0); + // fast load - no fsensor trigger + REQUIRE(WhileCondition( + fb, + [&](uint32_t) { return fb.State() == FeedToBondtech::PushingFilamentFast; }, + mm::unitToSteps(config::minimumBowdenLength) + 2)); + + // slow load - expecting fsensor trigger REQUIRE(WhileCondition( fb, [&](uint32_t step) { - if( step == 1000 ){ + if( step == 100 ){ mfs::fsensor.ProcessMessage(true); } return fb.State() == FeedToBondtech::PushingFilamentToFSensor; }, diff --git a/tests/unit/logic/tool_change/test_tool_change.cpp b/tests/unit/logic/tool_change/test_tool_change.cpp index 3f56490..1145c86 100644 --- a/tests/unit/logic/tool_change/test_tool_change.cpp +++ b/tests/unit/logic/tool_change/test_tool_change.cpp @@ -42,15 +42,17 @@ void FeedingToFinda(logic::ToolChange &tc, uint8_t toSlot, uint32_t triggerAt = } void FeedingToBondtech(logic::ToolChange &tc, uint8_t toSlot) { - // james is feeding + // james is feeding fast and then slowly + // FSensor must not trigger too early + REQUIRE_FALSE(mfs::fsensor.Pressed()); REQUIRE(WhileCondition( tc, [&](uint32_t step) -> bool { - if(step == 2000){ // on 2000th step make filament sensor trigger + if(step == mm::unitToSteps(config::minimumBowdenLength)+10){ // on the correct step make filament sensor trigger mfs::fsensor.ProcessMessage(true); } return tc.TopLevelState() == ProgressCode::FeedingToBondtech; }, - 20000UL)); + mm::unitToSteps(config::minimumBowdenLength) + 10000)); REQUIRE(VerifyState(tc, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), toSlot, true, false, ml::on, ml::off, ErrorCode::OK, ProgressCode::OK)); } @@ -73,7 +75,9 @@ void ToolChange(logic::ToolChange &tc, uint8_t fromSlot, uint8_t toSlot) { REQUIRE(WhileCondition( tc, [&](uint32_t step) -> bool { - if(step == 2000){ // on 2000th step make FINDA trigger + if(step == 20){ // on 20th step make FSensor switch off + mfs::fsensor.ProcessMessage(false); + } else if(step == mm::unitToSteps(config::minimumBowdenLength)){ // on 2000th step make FINDA trigger hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low); } return tc.TopLevelState() == ProgressCode::UnloadingFilament; },