Improve and verify Load filament alg and unit tests

pull/37/head
D.R.racer 2021-06-23 18:35:54 +02:00 committed by DRracer
parent 46a40f7488
commit f6e5d4ae76
10 changed files with 234 additions and 104 deletions

View File

@ -37,7 +37,8 @@ bool FeedToBondtech::Step() {
case PushingFilament:
if (mfs::fsensor.Pressed()) {
mm::motion.AbortPlannedMoves(); // stop pushing filament
state = DisengagingIdler;
// mi::idler.Disengage();
state = OK;
} 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
@ -45,12 +46,12 @@ bool FeedToBondtech::Step() {
state = Failed;
}
return false;
case DisengagingIdler:
if (!mi::idler.Engaged()) {
state = OK;
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::Color::green, ml::on);
}
return false;
// case DisengagingIdler:
// if (!mi::idler.Engaged()) {
// state = OK;
// ml::leds.SetMode(mg::globals.ActiveSlot(), ml::Color::green, ml::on);
// }
// return false;
case OK:
case Failed:
default:

View File

@ -51,14 +51,14 @@ bool FeedToFinda::Step() {
return false;
case UnloadBackToPTFE:
if (mm::motion.QueueEmpty()) { // all moves have been finished
state = DisengagingIdler;
mi::idler.Disengage();
}
return false;
case DisengagingIdler:
if (!mi::idler.Engaged()) {
// state = DisengagingIdler;
// mi::idler.Disengage();
// }
// return false;
// case DisengagingIdler:
// if (!mi::idler.Engaged()) {
state = OK;
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::Color::green, ml::on);
// ml::leds.SetMode(mg::globals.ActiveSlot(), ml::Color::green, ml::on);
}
// @@TODO FINDA must be reported as OFF again as we are pulling the filament from it - is this correct?
return false;

View File

@ -24,6 +24,8 @@ void LoadFilament::Reset(uint8_t param) {
error = ErrorCode::OK;
mg::globals.SetActiveSlot(param);
mi::idler.Engage(mg::globals.ActiveSlot());
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::off);
}
bool LoadFilament::Step() {
@ -40,7 +42,9 @@ bool LoadFilament::Step() {
if (feed.State() == FeedToFinda::Failed) {
// @@TODO - try to repeat 6x - push/pull sequence - probably something to put into feed_to_finda as an option
state = ProgressCode::ERR1DisengagingIdler;
error = ErrorCode::FINDA_DIDNT_TRIGGER;
mi::idler.Disengage();
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::Color::green, ml::Mode::off);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::Color::red, ml::Mode::blink0); // signal loading error
} else {
state = ProgressCode::FeedingToBondtech;
@ -62,13 +66,14 @@ bool LoadFilament::Step() {
case ProgressCode::DisengagingIdler:
if (!mi::idler.Engaged()) {
state = ProgressCode::OK;
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::off);
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::on);
mg::globals.SetFilamentLoaded(true);
}
break;
case ProgressCode::OK:
mg::globals.SetFilamentLoaded(true);
return true;
case ProgressCode::ERR1DisengagingIdler: // couldn't unload to FINDA
error = ErrorCode::FINDA_DIDNT_TRIGGER;
if (!mi::idler.Engaged()) {
state = ProgressCode::ERR1WaitingForUser;
}
@ -80,12 +85,13 @@ bool LoadFilament::Step() {
bool userResolved = modules::buttons::buttons.ButtonPressed(modules::buttons::Right) /*|| command_userResolved()*/;
if (help) {
// try to manually load just a tiny bit - help the filament with the pulley
//@@TODO
state = ProgressCode::ERR1EngagingIdler;
mi::idler.Engage(mg::globals.ActiveSlot());
} else if (tryAgain) {
// try again the whole sequence
Reset(0); // @@TODO param
Reset(mg::globals.ActiveSlot());
} else if (userResolved) {
// problem resolved - the user pulled the fillament by hand
// problem resolved - the user pushed the fillament by hand?
modules::leds::leds.SetMode(mg::globals.ActiveSlot(), modules::leds::red, modules::leds::off);
modules::leds::leds.SetMode(mg::globals.ActiveSlot(), modules::leds::green, modules::leds::on);
// mm::motion.PlanMove(mm::Pulley, 450, 5000); // @@TODO constants
@ -93,6 +99,26 @@ bool LoadFilament::Step() {
}
return false;
}
case ProgressCode::ERR1EngagingIdler:
if (mi::idler.Engaged()) {
state = ProgressCode::ERR1HelpingFilament;
mm::motion.PlanMove(mm::Pulley, 450, 5000); //@@TODO constants
}
return false;
case ProgressCode::ERR1HelpingFilament:
if (mf::finda.Pressed()) {
// the help was enough to press the FINDA, we are ok, continue normally
state = ProgressCode::FeedingToBondtech;
error = ErrorCode::OK;
} else if (mm::motion.QueueEmpty()) {
// helped a bit, but FINDA didn't trigger, return to the main error state
state = ProgressCode::ERR1DisengagingIdler;
}
return false;
default: // we got into an unhandled state, better report it
state = ProgressCode::ERRInternal;
error = ErrorCode::INTERNAL;
return true;
}
return false;
}

View File

@ -84,7 +84,7 @@ bool UnloadFilament::Step() {
mi::idler.Engage(mg::globals.ActiveSlot());
} else if (tryAgain) {
// try again the whole sequence
Reset(0);
Reset(0); //@@TODO validate the reset parameter
} else if (userResolved) {
// problem resolved - the user pulled the fillament by hand
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::off);

View File

@ -62,26 +62,30 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
// 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.LedOn(mg::globals.ActiveSlot(), ml::Color::green));
// @@TODO simulate incoming message from the printer - fsensor triggered
REQUIRE(WhileCondition(
fb,
[&](int) { return fb.State() == FeedToBondtech::PushingFilament; },
[&](int step) {
if( step == 1000 ){
modules::fsensor::fsensor.ProcessMessage(true);
}
return fb.State() == FeedToBondtech::PushingFilament; },
1500));
// disengaging idler
REQUIRE(fb.State() == FeedToBondtech::DisengagingIdler);
REQUIRE(WhileCondition(
fb,
[&](int) { return fb.State() == FeedToBondtech::DisengagingIdler; },
5000));
REQUIRE(modules::fsensor::fsensor.Pressed());
CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // @@TODO constants
// // disengaging idler
// REQUIRE(fb.State() == FeedToBondtech::DisengagingIdler);
// REQUIRE(WhileCondition(
// fb,
// [&](int) { return fb.State() == FeedToBondtech::DisengagingIdler; },
// 5000));
// CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // @@TODO constants
CHECK(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(0));
// state machine finished ok, the green LED should be on
REQUIRE(fb.State() == FeedToBondtech::OK);
REQUIRE(ml::leds.LedOn(mg::globals.ActiveSlot(), ml::Color::green));
// REQUIRE(ml::leds.LedOn(mg::globals.ActiveSlot(), ml::Color::green));
REQUIRE(fb.Step() == true); // the automaton finished its work, any consecutive calls to Step must return true
}

View File

@ -79,19 +79,19 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
[&](int) { return ff.State() == FeedToFinda::UnloadBackToPTFE; },
5000));
// disengaging idler
REQUIRE(ff.State() == FeedToFinda::DisengagingIdler);
REQUIRE(WhileCondition(
ff,
[&](int) { return mi::idler.Engaged(); },
5000));
// // disengaging idler
// REQUIRE(ff.State() == FeedToFinda::DisengagingIdler);
// REQUIRE(WhileCondition(
// ff,
// [&](int) { return mi::idler.Engaged(); },
// 5000));
CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // @@TODO constants
CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(0)); // @@TODO constants
CHECK(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(0));
// state machine finished ok, the green LED should be on
REQUIRE(ff.State() == FeedToFinda::OK);
REQUIRE(ml::leds.LedOn(mg::globals.ActiveSlot(), ml::Color::green));
REQUIRE(ml::leds.Mode(mg::globals.ActiveSlot(), ml::green) == ml::blink0);
REQUIRE(ff.Step() == true); // the automaton finished its work, any consecutive calls to Step must return true
}

View File

@ -0,0 +1,15 @@
template<typename SM>
bool VerifyState(SM &uf, bool filamentLoaded, uint8_t idlerSlotIndex, uint8_t selectorSlotIndex,
bool findaPressed, ml::Mode greenLEDMode, ml::Mode redLEDMode, ErrorCode err, ProgressCode topLevelProgress) {
CHECKED_ELSE(mg::globals.FilamentLoaded() == filamentLoaded) { return false; }
CHECKED_ELSE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(idlerSlotIndex)) { return false; }
CHECKED_ELSE(mi::idler.Engaged() == (idlerSlotIndex < 5)) { return false; }
CHECKED_ELSE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(selectorSlotIndex)) { return false; }
CHECKED_ELSE(ms::selector.Slot() == selectorSlotIndex) { return false; }
CHECKED_ELSE(mf::finda.Pressed() == findaPressed) { return false; }
CHECKED_ELSE(ml::leds.Mode(selectorSlotIndex, ml::red) == redLEDMode) { return false; }
CHECKED_ELSE(ml::leds.Mode(selectorSlotIndex, ml::green) == greenLEDMode) { return false; }
CHECKED_ELSE(uf.Error() == err) { return false; }
CHECKED_ELSE(uf.TopLevelState() == topLevelProgress) { return false; }
return true;
}

View File

@ -27,30 +27,143 @@ namespace mb = modules::buttons;
namespace mg = modules::globals;
namespace ms = modules::selector;
TEST_CASE("unload_filament::unload0", "[unload_filament]") {
using namespace logic;
#include "../helpers/helpers.ipp"
void LoadFilamentCommonSetup(uint8_t slot, logic::LoadFilament &lf) {
ForceReinitAllAutomata();
LoadFilament lf;
// change the startup to what we need here
EnsureActiveSlotIndex(slot);
// verify startup conditions
REQUIRE(VerifyState(lf, false, 5, slot, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
// restart the automaton
lf.Reset(0);
lf.Reset(slot);
main_loop();
// Stage 0 - verify state just after Reset()
// we assume the filament is not loaded
// idler should have been activated by the underlying automaton
// no change in selector's position
// FINDA off
// green LED should blink, red off
REQUIRE(VerifyState(lf, false, 5, slot, false, ml::blink0, ml::off, ErrorCode::OK, ProgressCode::EngagingIdler));
// REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::UnloadingToFinda; }, 5000));
// REQUIRE(uf.TopLevelState() == ProgressCode::DisengagingIdler);
// REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::DisengagingIdler; }, 5000));
// CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5));
// REQUIRE(uf.TopLevelState() == ProgressCode::AvoidingGrind);
// REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::AvoidingGrind; }, 5000));
// REQUIRE(uf.TopLevelState() == ProgressCode::FinishingMoves);
// REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::FinishingMoves; }, 5000));
// REQUIRE(uf.TopLevelState() == ProgressCode::OK);
REQUIRE(modules::globals::globals.FilamentLoaded() == true);
// Stage 1 - engaging idler
REQUIRE(WhileTopState(lf, ProgressCode::EngagingIdler, 5000));
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::blink0, ml::off, ErrorCode::OK, ProgressCode::FeedingToFinda));
}
void LoadFilamentSuccessful(uint8_t slot, logic::LoadFilament &lf) {
// Stage 2 - feeding to finda
// we'll assume the finda is working correctly here
REQUIRE(WhileCondition(
lf,
[&](int step) -> bool {
if(step == 100){ // on 100th step make FINDA trigger
hal::adc::SetADC(1, 1023);
}
return lf.TopLevelState() == ProgressCode::FeedingToFinda; },
5000));
REQUIRE(VerifyState(lf, false, slot, slot, true, ml::blink0, ml::off, ErrorCode::OK, ProgressCode::FeedingToBondtech));
// Stage 3 - feeding to bondtech
// we'll make a fsensor switch during the process
REQUIRE(WhileCondition(
lf,
[&](int step) -> bool {
if(step == 100){ // on 100th step make fsensor trigger
modules::fsensor::fsensor.ProcessMessage(true);
}
return lf.TopLevelState() == ProgressCode::FeedingToBondtech; },
5000));
REQUIRE(VerifyState(lf, false, slot, slot, true, ml::blink0, ml::off, ErrorCode::OK, ProgressCode::DisengagingIdler));
// Stage 4 - disengaging idler
REQUIRE(WhileTopState(lf, ProgressCode::DisengagingIdler, 5000));
REQUIRE(VerifyState(lf, true, 5, slot, true, ml::on, ml::off, ErrorCode::OK, ProgressCode::OK));
}
TEST_CASE("load_filament::regular_load_to_slot_0-4", "[load_filament]") {
for (uint8_t slot = 0; slot < 5; ++slot) {
logic::LoadFilament lf;
LoadFilamentCommonSetup(slot, lf);
LoadFilamentSuccessful(slot, lf);
}
}
void FailedLoadToFinda(uint8_t slot, logic::LoadFilament &lf) {
// Stage 2 - feeding to finda
// we'll assume the finda is defective here and does not trigger
REQUIRE(WhileTopState(lf, ProgressCode::FeedingToFinda, 5000));
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_TRIGGER, ProgressCode::ERR1DisengagingIdler));
// Stage 3 - disengaging idler in error mode
REQUIRE(WhileTopState(lf, ProgressCode::ERR1DisengagingIdler, 5000));
REQUIRE(VerifyState(lf, false, 5, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_TRIGGER, ProgressCode::ERR1WaitingForUser));
}
void FailedLoadToFindaResolveHelp(uint8_t slot, logic::LoadFilament &lf) {
// Stage 3 - the user has to do something
// there are 3 options:
// - help the filament a bit
// - try again the whole sequence
// - resolve the problem by hand - after pressing the button we shall check, that FINDA is off and we should do what?
// In this case we check the first option
// Perform press on button 1 + debounce
hal::adc::SetADC(0, 0);
while (!mb::buttons.ButtonPressed(0)) {
main_loop();
lf.Step();
}
REQUIRE(VerifyState(lf, false, 5, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_TRIGGER, ProgressCode::ERR1EngagingIdler));
// Stage 4 - engage the idler
REQUIRE(WhileTopState(lf, ProgressCode::ERR1EngagingIdler, 5000));
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_TRIGGER, ProgressCode::ERR1HelpingFilament));
}
void FailedLoadToFindaResolveHelpFindaTriggered(uint8_t slot, logic::LoadFilament &lf) {
// Stage 5 - move the pulley a bit - simulate FINDA depress
REQUIRE(WhileCondition(
lf,
[&](int step) -> bool {
if(step == 100){ // on 100th step make FINDA trigger
hal::adc::SetADC(1, 1023);
}
return lf.TopLevelState() == ProgressCode::ERR1HelpingFilament; },
5000));
REQUIRE(VerifyState(lf, false, slot, slot, true, ml::off, ml::blink0, ErrorCode::OK, ProgressCode::FeedingToBondtech));
}
void FailedLoadToFindaResolveHelpFindaDidntTrigger(uint8_t slot, logic::LoadFilament &lf) {
// Stage 5 - move the pulley a bit - no FINDA change
REQUIRE(WhileTopState(lf, ProgressCode::ERR1HelpingFilament, 5000));
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_TRIGGER, ProgressCode::ERR1DisengagingIdler));
}
TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_help_second_ok", "[load_filament]") {
for (uint8_t slot = 0; slot < 5; ++slot) {
logic::LoadFilament lf;
LoadFilamentCommonSetup(slot, lf);
FailedLoadToFinda(slot, lf);
FailedLoadToFindaResolveHelp(slot, lf);
FailedLoadToFindaResolveHelpFindaTriggered(slot, lf);
}
}
TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_help_second_fail", "[load_filament]") {
for (uint8_t slot = 0; slot < 5; ++slot) {
logic::LoadFilament lf;
LoadFilamentCommonSetup(slot, lf);
FailedLoadToFinda(slot, lf);
FailedLoadToFindaResolveHelp(slot, lf);
FailedLoadToFindaResolveHelpFindaDidntTrigger(slot, lf);
}
}

View File

@ -27,20 +27,7 @@ namespace mb = modules::buttons;
namespace mg = modules::globals;
namespace ms = modules::selector;
bool VerifyState(logic::UnloadFilament &uf, bool filamentLoaded, uint8_t idlerSlotIndex, uint8_t selectorSlotIndex,
bool findaPressed, ml::Mode greenLEDMode, ml::Mode redLEDMode, ErrorCode err, ProgressCode topLevelProgress) {
CHECKED_ELSE(mg::globals.FilamentLoaded() == filamentLoaded) { return false; }
CHECKED_ELSE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(idlerSlotIndex)) { return false; }
CHECKED_ELSE(mi::idler.Engaged() == (idlerSlotIndex < 5)) { return false; }
CHECKED_ELSE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(selectorSlotIndex)) { return false; }
CHECKED_ELSE(ms::selector.Slot() == selectorSlotIndex) { return false; }
CHECKED_ELSE(mf::finda.Pressed() == findaPressed) { return false; }
CHECKED_ELSE(ml::leds.Mode(selectorSlotIndex, ml::red) == redLEDMode) { return false; }
CHECKED_ELSE(ml::leds.Mode(selectorSlotIndex, ml::green) == greenLEDMode) { return false; }
CHECKED_ELSE(uf.Error() == err) { return false; }
CHECKED_ELSE(uf.TopLevelState() == topLevelProgress) { return false; }
return true;
}
#include "../helpers/helpers.ipp"
void RegularUnloadFromSlot04Init(uint8_t slot, logic::UnloadFilament &uf) {
// prepare startup conditions
@ -251,14 +238,16 @@ void FindaDidntTriggerResolveHelpFindaDidntTrigger(uint8_t slot, logic::UnloadFi
REQUIRE(VerifyState(uf, true, slot, slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_TRIGGER, ProgressCode::ERR1DisengagingIdler));
}
TEST_CASE("unload_filament::finda_didnt_trigger_resolve_help", "[unload_filament]") {
TEST_CASE("unload_filament::finda_didnt_trigger_resolve_help_second_ok", "[unload_filament]") {
for (uint8_t slot = 0; slot < 5; ++slot) {
logic::UnloadFilament uf;
FindaDidntTriggerCommonSetup(slot, uf);
FindaDidntTriggerResolveHelp(slot, uf);
FindaDidntTriggerResolveHelpFindaTriggered(slot, uf);
}
}
TEST_CASE("unload_filament::finda_didnt_trigger_resolve_help_second_fail", "[unload_filament]") {
// the same with different end scenario
for (uint8_t slot = 0; slot < 5; ++slot) {
logic::UnloadFilament uf;

View File

@ -30,25 +30,17 @@ namespace ms = modules::selector;
namespace ha = hal::adc;
TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
using namespace logic;
ForceReinitAllAutomata();
// we need finda ON
hal::adc::ReinitADC(1, hal::adc::TADCData({ 1023 }), 1);
SetFINDAStateAndDebounce(true);
UnloadToFinda ff;
// wait for FINDA to debounce
REQUIRE(WhileCondition(
ff,
[&](int) { return !mf::finda.Pressed(); },
5000));
logic::UnloadToFinda ff;
// restart the automaton - just 1 attempt
ff.Reset(1);
REQUIRE(ff.State() == UnloadToFinda::EngagingIdler);
REQUIRE(ff.State() == logic::UnloadToFinda::EngagingIdler);
// it should have instructed the selector and idler to move to slot 1
// check if the idler and selector have the right command
@ -63,51 +55,41 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
5000));
// now pulling the filament until finda triggers
REQUIRE(ff.State() == UnloadToFinda::WaitingForFINDA);
REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA);
hal::adc::ReinitADC(1, hal::adc::TADCData({ 1023, 900, 800, 500, 0 }), 10);
REQUIRE(WhileCondition(
ff,
[&](int) { return mf::finda.Pressed(); },
50000));
REQUIRE(ff.State() == UnloadToFinda::OK);
REQUIRE(ff.State() == logic::UnloadToFinda::OK);
}
TEST_CASE("unload_to_finda::no_sense_FINDA_upon_start", "[unload_to_finda]") {
using namespace logic;
ForceReinitAllAutomata(); // that implies FINDA OFF which should really not happen for an unload call
UnloadToFinda ff;
logic::UnloadToFinda ff;
// restart the automaton - just 1 attempt
ff.Reset(1);
// the state machine should accept the unpressed FINDA as no-fillament-loaded
// thus should immediately end in the OK state
REQUIRE(ff.State() == UnloadToFinda::OK);
REQUIRE(ff.State() == logic::UnloadToFinda::OK);
}
TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]") {
using namespace logic;
ForceReinitAllAutomata();
// we need finda ON
hal::adc::ReinitADC(1, hal::adc::TADCData({ 1023 }), 1);
SetFINDAStateAndDebounce(true);
UnloadToFinda ff;
// wait for FINDA to debounce
REQUIRE(WhileCondition(
ff,
[&](int) { return !mf::finda.Pressed(); },
5000));
logic::UnloadToFinda ff;
// restart the automaton - just 1 attempt
ff.Reset(1);
REQUIRE(ff.State() == UnloadToFinda::EngagingIdler);
REQUIRE(ff.State() == logic::UnloadToFinda::EngagingIdler);
// it should have instructed the selector and idler to move to slot 1
// check if the idler and selector have the right command
@ -122,7 +104,7 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]")
5000));
// now pulling the filament until finda triggers
REQUIRE(ff.State() == UnloadToFinda::WaitingForFINDA);
REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA);
// no changes to FINDA during unload - we'll pretend it never triggers
REQUIRE(!WhileCondition(
@ -130,5 +112,5 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]")
[&](int) { return mf::finda.Pressed(); },
50000));
REQUIRE(ff.State() == UnloadToFinda::Failed);
REQUIRE(ff.State() == logic::UnloadToFinda::Failed);
}