397 lines
17 KiB
C++
397 lines
17 KiB
C++
#include "catch2/catch.hpp"
|
|
|
|
#include "../../../../src/modules/buttons.h"
|
|
#include "../../../../src/modules/finda.h"
|
|
#include "../../../../src/modules/fsensor.h"
|
|
#include "../../../../src/modules/globals.h"
|
|
#include "../../../../src/modules/idler.h"
|
|
#include "../../../../src/modules/leds.h"
|
|
#include "../../../../src/modules/motion.h"
|
|
#include "../../../../src/modules/permanent_storage.h"
|
|
#include "../../../../src/modules/selector.h"
|
|
|
|
#include "../../../../src/logic/unload_filament.h"
|
|
|
|
#include "../../modules/stubs/stub_adc.h"
|
|
|
|
#include "../stubs/homing.h"
|
|
#include "../stubs/main_loop_stub.h"
|
|
#include "../stubs/stub_motion.h"
|
|
|
|
using Catch::Matchers::Equals;
|
|
using namespace std::placeholders;
|
|
|
|
#include "../helpers/helpers.ipp"
|
|
|
|
void RegularUnloadFromSlot04Init(uint8_t slot, logic::UnloadFilament &uf) {
|
|
// prepare startup conditions
|
|
ForceReinitAllAutomata();
|
|
|
|
// change the startup to what we need here
|
|
REQUIRE(EnsureActiveSlotIndex(slot, mg::FilamentLoadState::InNozzle));
|
|
|
|
// set FINDA ON + debounce
|
|
SetFINDAStateAndDebounce(true);
|
|
|
|
// verify startup conditions
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), slot, true, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
|
|
|
// restart the automaton
|
|
uf.Reset(slot);
|
|
}
|
|
|
|
void RegularUnloadFromSlot04(uint8_t slot, logic::UnloadFilament &uf, uint8_t entryIdlerSlotIndex,
|
|
bool selectorShallHomeAtEnd, ml::Mode entryGreenLED) {
|
|
// Stage 0 - verify state just after Reset()
|
|
// we still think we have filament loaded at this stage
|
|
// idler should have been activated by the underlying automaton
|
|
// no change in selector's position
|
|
// FINDA on
|
|
// green LED should blink, red off
|
|
REQUIRE(VerifyState(uf, (mg::FilamentLoadState)(mg::FilamentLoadState::InNozzle | mg::FilamentLoadState::InSelector),
|
|
entryIdlerSlotIndex, slot, true, true, entryGreenLED, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda));
|
|
|
|
// run the automaton
|
|
// Stage 1 - unloading to FINDA
|
|
REQUIRE(WhileCondition(
|
|
uf,
|
|
[&](uint32_t step) -> bool {
|
|
if(step == 100){ // on 100th step make FINDA trigger
|
|
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
|
|
}
|
|
return uf.TopLevelState() == ProgressCode::UnloadingToFinda; },
|
|
50000));
|
|
|
|
// we still think we have filament loaded at this stage
|
|
// idler should have been activated by the underlying automaton
|
|
// no change in selector's position
|
|
// FINDA triggered off
|
|
// green LED should be off
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, slot, slot, false, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::RetractingFromFinda));
|
|
|
|
// Stage 2 - retracting from FINDA
|
|
REQUIRE(WhileTopState(uf, ProgressCode::RetractingFromFinda, idlerEngageDisengageMaxSteps));
|
|
|
|
// Stage 3 - idler was engaged, disengage it
|
|
REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps));
|
|
|
|
if (selectorShallHomeAtEnd) {
|
|
REQUIRE(ms::selector.Slot() == 0xff);
|
|
SimulateSelectorHoming(uf);
|
|
}
|
|
|
|
// filament unloaded
|
|
// idler should have been disengaged
|
|
// no change in selector's position
|
|
// FINDA still triggered off
|
|
// green LED should be off
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
|
|
|
// Stage 5 - repeated calls to TopLevelState should return "OK"
|
|
REQUIRE(uf.TopLevelState() == ProgressCode::OK);
|
|
REQUIRE(mg::globals.FilamentLoaded() == mg::FilamentLoadState::AtPulley);
|
|
REQUIRE(mf::finda.Pressed() == false);
|
|
REQUIRE(uf.Error() == ErrorCode::OK); // no error
|
|
}
|
|
|
|
TEST_CASE("unload_filament::regular_unload_from_slot_0-4", "[unload_filament]") {
|
|
for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
|
|
logic::UnloadFilament uf;
|
|
RegularUnloadFromSlot04Init(slot, uf);
|
|
RegularUnloadFromSlot04(slot, uf, mi::Idler::IdleSlotIndex(), false, ml::off);
|
|
}
|
|
}
|
|
|
|
void FindaDidntTriggerCommonSetup(uint8_t slot, logic::UnloadFilament &uf) {
|
|
// prepare startup conditions
|
|
ForceReinitAllAutomata();
|
|
|
|
// change the startup to what we need here
|
|
// move selector to the right spot
|
|
REQUIRE(EnsureActiveSlotIndex(slot, mg::FilamentLoadState::InNozzle));
|
|
|
|
// set FINDA ON + debounce
|
|
SetFINDAStateAndDebounce(true);
|
|
|
|
// mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::InNozzle);
|
|
|
|
// verify startup conditions
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), slot, true, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
|
|
|
// restart the automaton
|
|
uf.Reset(slot);
|
|
|
|
// Stage 0 - verify state just after Reset()
|
|
// we still think we have filament loaded at this stage
|
|
// idler should have been activated by the underlying automaton
|
|
// no change in selector's position
|
|
// FINDA triggered off
|
|
// green LED should be off
|
|
// no error so far
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InNozzle, mi::Idler::IdleSlotIndex(), slot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda));
|
|
|
|
// run the automaton
|
|
// Stage 1 - unloading to FINDA - do NOT let it trigger - keep it pressed, the automaton should finish all moves with the pulley
|
|
// without reaching the FINDA and report an error
|
|
REQUIRE(WhileCondition(
|
|
uf,
|
|
[&](uint32_t step) {
|
|
SimulateUnloadToFINDA(step, 10, 1'000'000);
|
|
return uf.TopLevelState() == ProgressCode::UnloadingToFinda;
|
|
},
|
|
200'000));
|
|
|
|
// we still think we have filament loaded at this stage
|
|
// idler should have been activated by the underlying automaton
|
|
// no change in selector's position
|
|
// FINDA still on
|
|
// red LED should blink, green LED should be off
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, slot, slot, true, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERRDisengagingIdler));
|
|
|
|
// Stage 2 - idler should get disengaged
|
|
REQUIRE(WhileTopState(uf, ProgressCode::ERRDisengagingIdler, idlerEngageDisengageMaxSteps));
|
|
|
|
// we still think we have filament loaded at this stage
|
|
// idler should have been disengaged
|
|
// no change in selector's position
|
|
// FINDA still on
|
|
// red LED should blink
|
|
// green LED should be off
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, true, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERRWaitingForUser));
|
|
}
|
|
|
|
void FindaDidntTriggerResolveHelp(uint8_t slot, logic::UnloadFilament &uf) {
|
|
|
|
// 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 0 + debounce
|
|
PressButtonAndDebounce(uf, mb::Left, false);
|
|
|
|
// we still think we have filament loaded at this stage
|
|
// idler should have been disengaged
|
|
// no change in selector's position
|
|
// FINDA still on
|
|
// red LED should blink, green LED should be off
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, true, false, ml::off, ml::blink0, ErrorCode::RUNNING, ProgressCode::ERREngagingIdler));
|
|
|
|
SimulateIdlerHoming(uf);
|
|
|
|
// Stage 4 - engage the idler
|
|
REQUIRE(WhileTopState(uf, ProgressCode::ERREngagingIdler, idlerEngageDisengageMaxSteps));
|
|
|
|
// we still think we have filament loaded at this stage
|
|
// idler should be engaged
|
|
// no change in selector's position
|
|
// FINDA still on
|
|
// red LED should blink, green LED should be off
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, slot, slot, true, true, ml::off, ml::blink0, ErrorCode::RUNNING, ProgressCode::ERRHelpingFilament));
|
|
}
|
|
|
|
void FindaDidntTriggerResolveHelpFindaTriggered(uint8_t slot, logic::UnloadFilament &uf) {
|
|
// Stage 5 - move the pulley a bit - simulate FINDA depress
|
|
REQUIRE(WhileCondition(
|
|
uf,
|
|
[&](uint32_t step) -> bool {
|
|
if(step == 100){ // on 100th step make FINDA trigger
|
|
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
|
|
}
|
|
return uf.TopLevelState() == ProgressCode::ERRHelpingFilament; },
|
|
5000));
|
|
|
|
// we still think we have filament loaded at this stage
|
|
// idler should be engaged
|
|
// no change in selector's position
|
|
// FINDA depressed
|
|
// red LED should blink, green LED should be off
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, slot, slot, false, true, ml::off, ml::blink0, ErrorCode::RUNNING, ProgressCode::DisengagingIdler));
|
|
}
|
|
|
|
void FindaDidntTriggerResolveHelpFindaDidntTrigger(uint8_t slot, logic::UnloadFilament &uf) {
|
|
// Stage 5 - move the pulley a bit - no FINDA change
|
|
REQUIRE(WhileTopState(uf, ProgressCode::ERRHelpingFilament, 5000));
|
|
|
|
// we still think we have filament loaded at this stage
|
|
// idler should be engaged
|
|
// no change in selector's position
|
|
// FINDA still pressed
|
|
// red LED should blink, green LED should be off
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, slot, slot, true, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERRDisengagingIdler));
|
|
}
|
|
|
|
TEST_CASE("unload_filament::finda_didnt_trigger_resolve_help_second_ok", "[unload_filament]") {
|
|
for (uint8_t slot = 0; slot < config::toolCount; ++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 < config::toolCount; ++slot) {
|
|
logic::UnloadFilament uf;
|
|
FindaDidntTriggerCommonSetup(slot, uf);
|
|
FindaDidntTriggerResolveHelp(slot, uf);
|
|
FindaDidntTriggerResolveHelpFindaDidntTrigger(slot, uf);
|
|
}
|
|
}
|
|
|
|
void FindaDidntTriggerResolveTryAgain(uint8_t slot, logic::UnloadFilament &uf) {
|
|
// 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 second option
|
|
PressButtonAndDebounce(uf, mb::Middle, false);
|
|
|
|
// we still think we have filament loaded at this stage
|
|
// idler should have been disengaged
|
|
// no change in selector's position
|
|
// FINDA still on
|
|
// red LED should blink, green LED should be off
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda));
|
|
|
|
// Assume, the Idler homed (homing is invalidated after pressing the recovery button)
|
|
SimulateIdlerHoming(uf);
|
|
}
|
|
|
|
TEST_CASE("unload_filament::finda_didnt_trigger_resolve_try_again", "[unload_filament]") {
|
|
for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
|
|
logic::UnloadFilament uf;
|
|
FindaDidntTriggerCommonSetup(slot, uf);
|
|
FindaDidntTriggerResolveTryAgain(slot, uf);
|
|
RegularUnloadFromSlot04(slot, uf, slot, true, ml::blink0);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("unload_filament::not_loaded", "[unload_filament]") {
|
|
logic::UnloadFilament uf;
|
|
|
|
// prepare startup conditions
|
|
ForceReinitAllAutomata();
|
|
|
|
// change the startup to what we need here
|
|
// move selector to the right spot
|
|
REQUIRE(EnsureActiveSlotIndex(0, mg::FilamentLoadState::AtPulley));
|
|
|
|
// verify startup conditions
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), 0, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
|
|
|
// restart the automaton
|
|
uf.Reset(0);
|
|
|
|
// Stage 0 - unload filament should finish immediately as there is no filament loaded
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), 0, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
|
}
|
|
|
|
void FailedUnloadResolveManual(uint8_t slot, logic::UnloadFilament &uf) {
|
|
// simulate the user fixed the issue himself
|
|
|
|
// Perform press on button 2 + debounce + switch off FINDA
|
|
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
|
|
PressButtonAndDebounce(uf, mb::Right, false);
|
|
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, false, false, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::FeedingToFinda));
|
|
|
|
// we still need to feed to FINDA and back to verify the position of the filament
|
|
SimulateIdlerHoming(uf);
|
|
|
|
REQUIRE(WhileCondition(uf, std::bind(SimulateFeedToFINDA, _1, 100), 5000));
|
|
|
|
REQUIRE(WhileCondition(uf, std::bind(SimulateRetractFromFINDA, _1, 100), 5000));
|
|
REQUIRE(WhileCondition(
|
|
uf, [&](uint32_t) { return uf.State() == ProgressCode::RetractingFromFinda; }, 50000));
|
|
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, config::toolCount, config::toolCount, false, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::DisengagingIdler));
|
|
SimulateSelectorHoming(uf);
|
|
REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps));
|
|
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
|
}
|
|
|
|
void FailedUnloadResolveManualFINDAon(uint8_t slot, logic::UnloadFilament &uf) {
|
|
// simulate the user fixed the issue himself
|
|
|
|
// Perform press on button 2 + debounce + keep FINDA on
|
|
PressButtonAndDebounce(uf, mb::Right, false);
|
|
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, true, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERRWaitingForUser));
|
|
}
|
|
|
|
void FailedUnloadResolveManualFSensorOn(uint8_t slot, logic::UnloadFilament &uf) {
|
|
// simulate the user fixed the issue himself
|
|
|
|
// Perform press on button 2 + debounce + keep FSensor on
|
|
SetFSensorStateAndDebounce(true);
|
|
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
|
|
PressButtonAndDebounce(uf, mb::Right, false);
|
|
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::blink0, ErrorCode::FSENSOR_DIDNT_SWITCH_OFF, ProgressCode::ERRWaitingForUser));
|
|
}
|
|
|
|
TEST_CASE("unload_filament::failed_unload_to_finda_0-4_resolve_manual", "[unload_filament]") {
|
|
for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
|
|
logic::UnloadFilament uf;
|
|
FindaDidntTriggerCommonSetup(slot, uf);
|
|
FailedUnloadResolveManual(slot, uf);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("unload_filament::failed_unload_to_finda_0-4_resolve_manual_FINDA_on", "[unload_filament]") {
|
|
for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
|
|
logic::UnloadFilament uf;
|
|
FindaDidntTriggerCommonSetup(slot, uf);
|
|
FailedUnloadResolveManualFINDAon(slot, uf);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("unload_filament::failed_unload_to_finda_0-4_resolve_manual_FSensor_on", "[unload_filament]") {
|
|
for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
|
|
logic::UnloadFilament uf;
|
|
FindaDidntTriggerCommonSetup(slot, uf);
|
|
FailedUnloadResolveManualFSensorOn(slot, uf);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("unload_filament::unload_homing_retry", "[unload_filament][homing]") {
|
|
uint8_t slot = 0;
|
|
logic::UnloadFilament uf;
|
|
FindaDidntTriggerCommonSetup(slot, uf);
|
|
|
|
// simulate the user fixed the issue himself (not really important, we are after a failed homing of the selector)
|
|
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
|
|
PressButtonAndDebounce(uf, mb::Right, false);
|
|
SimulateIdlerHoming(uf); // make Idler happy
|
|
|
|
REQUIRE(WhileCondition(uf, std::bind(SimulateFeedToFINDA, _1, 100), 5000));
|
|
|
|
REQUIRE(WhileCondition(uf, std::bind(SimulateRetractFromFINDA, _1, 100), 5000));
|
|
REQUIRE(WhileCondition(
|
|
uf, [&](uint32_t) { return uf.State() == ProgressCode::RetractingFromFinda; }, 50000));
|
|
|
|
REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps));
|
|
|
|
// now fail homing of the Selector
|
|
REQUIRE(SimulateFailedHomeSelectorRepeated(uf));
|
|
|
|
// REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::OK));
|
|
REQUIRE(uf.State() == ProgressCode::Homing);
|
|
REQUIRE(uf.Error() == ErrorCode::RUNNING);
|
|
|
|
// one retry
|
|
REQUIRE(SimulateFailedHomeSelectorRepeated(uf));
|
|
|
|
// success
|
|
SimulateSelectorHoming(uf);
|
|
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
|
}
|