Add more unit tests for homing + fix the homing
It is a carpet-bombing-commit again, but solving the problem correctly required such an approach.pull/154/head
parent
684051abe8
commit
c95c6677b1
|
|
@ -73,19 +73,20 @@ static inline ErrorCode WithoutAxisBits(ErrorCode ec) {
|
|||
| static_cast<uint16_t>(ErrorCode::TMC_PULLEY_BIT))));
|
||||
}
|
||||
|
||||
bool CommandBase::WaitForOneModuleErrorRecovery(ErrorCode ec, modules::motion::MovableBase &m) {
|
||||
bool CommandBase::WaitForOneModuleErrorRecovery(ErrorCode ec, modules::motion::MovableBase &m, uint8_t axisMask) {
|
||||
if (ec != ErrorCode::RUNNING) {
|
||||
if (stateBeforeModuleFailed == ProgressCode::OK) {
|
||||
if (stateBeforeModuleFailed == ProgressCode::Empty) {
|
||||
// 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;
|
||||
errorBeforeModuleFailed = error;
|
||||
error = ec;
|
||||
state = ProgressCode::ERRWaitingForUser; // such a situation always requires user's attention -> let the printer display an error screen
|
||||
}
|
||||
|
||||
// are we already recovering an error - that would mean we got another one
|
||||
if (recoveringMovableError) {
|
||||
if (recoveringMovableErrorAxisMask) {
|
||||
error = ec;
|
||||
state = ProgressCode::ERRWaitingForUser; // such a situation always requires user's attention -> let the printer display an error screen
|
||||
}
|
||||
|
|
@ -96,7 +97,7 @@ bool CommandBase::WaitForOneModuleErrorRecovery(ErrorCode ec, modules::motion::M
|
|||
// homing can be recovered
|
||||
mui::Event ev = mui::userInput.ConsumeEvent();
|
||||
if (ev == mui::Event::Middle) {
|
||||
recoveringMovableError = true;
|
||||
recoveringMovableErrorAxisMask |= axisMask;
|
||||
m.PlanHome(); // force initiate a new homing attempt
|
||||
state = ProgressCode::Homing;
|
||||
error = ErrorCode::RUNNING;
|
||||
|
|
@ -104,34 +105,33 @@ bool CommandBase::WaitForOneModuleErrorRecovery(ErrorCode ec, modules::motion::M
|
|||
}
|
||||
// TMC errors cannot be recovered safely, waiting for power cycling the MMU
|
||||
return true;
|
||||
default:
|
||||
return true; // prevent descendant from taking over while in an error state
|
||||
}
|
||||
} else if (recoveringMovableErrorAxisMask & axisMask) {
|
||||
switch (state) {
|
||||
case ProgressCode::Homing:
|
||||
if (m.HomingValid()) {
|
||||
// managed to recover from a homing problem
|
||||
state = stateBeforeModuleFailed;
|
||||
recoveringMovableError = false;
|
||||
stateBeforeModuleFailed = ProgressCode::OK;
|
||||
error = errorBeforeModuleFailed;
|
||||
recoveringMovableErrorAxisMask &= (~axisMask);
|
||||
stateBeforeModuleFailed = ProgressCode::Empty;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return true; // prevent descendant from taking over while recovering
|
||||
default:
|
||||
return true; // no idea what to do in other states ... set internal fw error state?
|
||||
return false; // let descendant do its processing?
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return recoveringMovableErrorAxisMask & axisMask;
|
||||
}
|
||||
|
||||
bool CommandBase::WaitForModulesErrorRecovery() {
|
||||
if (WaitForOneModuleErrorRecovery(CheckMovable(mi::idler), mi::idler))
|
||||
return true;
|
||||
|
||||
if (WaitForOneModuleErrorRecovery(CheckMovable(ms::selector), ms::selector))
|
||||
return true;
|
||||
|
||||
if (WaitForOneModuleErrorRecovery(CheckMovable(mpu::pulley), mpu::pulley))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
bool rv = WaitForOneModuleErrorRecovery(CheckMovable(mi::idler), mi::idler, 0x1);
|
||||
rv |= WaitForOneModuleErrorRecovery(CheckMovable(ms::selector), ms::selector, 0x2);
|
||||
rv |= WaitForOneModuleErrorRecovery(CheckMovable(mpu::pulley), mpu::pulley, 0x4);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool CommandBase::Step() {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@ public:
|
|||
inline CommandBase()
|
||||
: state(ProgressCode::OK)
|
||||
, error(ErrorCode::OK)
|
||||
, stateBeforeModuleFailed(ProgressCode::OK)
|
||||
, recoveringMovableError(false) {}
|
||||
, stateBeforeModuleFailed(ProgressCode::Empty)
|
||||
, errorBeforeModuleFailed(ErrorCode::OK)
|
||||
, recoveringMovableErrorAxisMask(0) {}
|
||||
|
||||
// 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
|
||||
|
|
@ -97,7 +98,7 @@ protected:
|
|||
bool WaitForModulesErrorRecovery();
|
||||
|
||||
/// @returns true when still waiting for a module to recover, false otherwise.
|
||||
bool WaitForOneModuleErrorRecovery(ErrorCode iState, modules::motion::MovableBase &m);
|
||||
bool WaitForOneModuleErrorRecovery(ErrorCode iState, modules::motion::MovableBase &m, uint8_t axisMask);
|
||||
|
||||
/// Perform disengaging idler in ErrDisengagingIdler state
|
||||
void ErrDisengagingIdler();
|
||||
|
|
@ -111,7 +112,8 @@ 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
|
||||
bool recoveringMovableError;
|
||||
ErrorCode errorBeforeModuleFailed; ///< saved error of the state machine before a common error happened
|
||||
uint8_t recoveringMovableErrorAxisMask;
|
||||
};
|
||||
|
||||
} // namespace logic
|
||||
|
|
|
|||
|
|
@ -37,4 +37,6 @@ enum class ProgressCode : uint_fast8_t {
|
|||
RetractingFromFinda, // P25
|
||||
|
||||
Homing,
|
||||
|
||||
Empty = 0xff // dummy empty state
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_cut_filament.cpp
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_eject_filament.cpp
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_failing_tmc.cpp
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# define the test executable
|
||||
add_executable(
|
||||
feed_to_bondtech_tests
|
||||
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/buttons.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/debouncer.cpp
|
||||
|
|
@ -21,6 +22,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_feed_to_bondtech.cpp
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# define the test executable
|
||||
add_executable(
|
||||
feed_to_finda_tests
|
||||
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/buttons.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/debouncer.cpp
|
||||
|
|
@ -21,6 +22,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_feed_to_finda.cpp
|
||||
|
|
|
|||
|
|
@ -19,17 +19,22 @@ bool VerifyEnvironmentState(mg::FilamentLoadState fls, uint8_t idlerSlotIndex, u
|
|||
return false;
|
||||
}
|
||||
}
|
||||
CHECKED_ELSE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(idlerSlotIndex).v) {
|
||||
return false;
|
||||
|
||||
if( idlerSlotIndex < config::toolCount ){ // abusing invalid index to skip checking of slot and position
|
||||
CHECKED_ELSE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(idlerSlotIndex).v) {
|
||||
return false;
|
||||
}
|
||||
CHECKED_ELSE(mi::idler.Engaged() == (idlerSlotIndex < config::toolCount)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
CHECKED_ELSE(mi::idler.Engaged() == (idlerSlotIndex < config::toolCount)) {
|
||||
return false;
|
||||
}
|
||||
CHECKED_ELSE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(selectorSlotIndex).v) {
|
||||
return false;
|
||||
}
|
||||
CHECKED_ELSE(ms::selector.Slot() == selectorSlotIndex) {
|
||||
return false;
|
||||
if( selectorSlotIndex < config::toolCount ){ // abusing invalid index to skip checking of slot and position
|
||||
CHECKED_ELSE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(selectorSlotIndex).v) {
|
||||
return false;
|
||||
}
|
||||
CHECKED_ELSE(ms::selector.Slot() == selectorSlotIndex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
CHECKED_ELSE(mf::finda.Pressed() == findaPressed) {
|
||||
return false;
|
||||
|
|
@ -143,21 +148,3 @@ void InvalidSlot(SM &logicSM, uint8_t activeSlot, uint8_t invSlot){
|
|||
logicSM.Reset(invSlot);
|
||||
REQUIRE(VerifyState(logicSM, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), activeSlot, false, false, ml::off, ml::off, ErrorCode::INVALID_TOOL, ProgressCode::OK));
|
||||
}
|
||||
|
||||
template <typename SM>
|
||||
void PressButtonAndDebounce(SM &sm, uint8_t btnIndex){
|
||||
hal::adc::SetADC(config::buttonsADCIndex, config::buttonADCLimits[btnIndex][0] + 1);
|
||||
while (!mb::buttons.ButtonPressed(btnIndex)) {
|
||||
main_loop();
|
||||
sm.Step(); // Inner
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SM>
|
||||
void ClearButtons(SM &sm){
|
||||
hal::adc::SetADC(config::buttonsADCIndex, config::buttonADCMaxValue);
|
||||
while (mb::buttons.AnyButtonPressed()) {
|
||||
main_loop();
|
||||
sm.Step(); // Inner
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_homing.cpp
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "../../modules/stubs/stub_adc.h"
|
||||
|
||||
#include "../stubs/homing.h"
|
||||
#include "../stubs/main_loop_stub.h"
|
||||
#include "../stubs/stub_motion.h"
|
||||
|
||||
|
|
@ -41,7 +42,7 @@ bool SuccessfulHome(uint8_t slot) {
|
|||
REQUIRE_FALSE(mi::idler.HomingValid());
|
||||
REQUIRE_FALSE(ms::selector.HomingValid());
|
||||
|
||||
SimulateIdlerAndSelectorHoming();
|
||||
SimulateIdlerAndSelectorHoming(h);
|
||||
|
||||
REQUIRE(WhileTopState(h, ProgressCode::Homing, 5000));
|
||||
|
||||
|
|
@ -58,120 +59,6 @@ TEST_CASE("homing::successful_run", "[homing]") {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SimulateFailedHomePostfix(T &h) {
|
||||
REQUIRE(WhileTopState(h, ProgressCode::Homing, 5));
|
||||
REQUIRE(mi::idler.HomingValid());
|
||||
|
||||
REQUIRE(h.Error() == ErrorCode::HOMING_SELECTOR_FAILED);
|
||||
REQUIRE(h.State() == ProgressCode::ERRWaitingForUser);
|
||||
REQUIRE_FALSE(mm::motion.Enabled(mm::Selector));
|
||||
|
||||
// do a few steps before pushing the button
|
||||
WhileTopState(h, ProgressCode::ERRWaitingForUser, 5);
|
||||
|
||||
REQUIRE_FALSE(mm::motion.Enabled(mm::Selector));
|
||||
|
||||
PressButtonAndDebounce(h, mb::Middle);
|
||||
|
||||
// it shall start homing again
|
||||
REQUIRE(h.Error() == ErrorCode::RUNNING);
|
||||
REQUIRE(h.State() == ProgressCode::Homing);
|
||||
REQUIRE_FALSE(ms::selector.HomingValid());
|
||||
REQUIRE(mm::motion.Enabled(mm::Selector));
|
||||
|
||||
ClearButtons(h);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SimulateFailedHomeFirstTime(T &h) {
|
||||
REQUIRE_FALSE(mi::idler.HomingValid());
|
||||
REQUIRE_FALSE(ms::selector.HomingValid());
|
||||
|
||||
{
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
main_loop();
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
}
|
||||
// now do a correct amount of steps of each axis towards the other end
|
||||
uint32_t idlerSteps = mm::unitToSteps<mm::I_pos_t>(config::idlerLimits.lenght);
|
||||
// now do LESS steps than expected to simulate something is blocking the selector
|
||||
uint32_t selectorSteps = mm::unitToSteps<mm::S_pos_t>(config::selectorLimits.lenght) + 1;
|
||||
uint32_t selectorTriggerShort = std::min(idlerSteps, selectorSteps) / 2;
|
||||
uint32_t maxSteps = selectorTriggerShort + 1;
|
||||
{
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
|
||||
if (i == selectorTriggerShort) {
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the Idler finishes its homing procedure (makes further checks much easier)
|
||||
for (uint32_t i = maxSteps; i < idlerSteps + 1; ++i) {
|
||||
main_loop();
|
||||
if (i == idlerSteps) {
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
}
|
||||
}
|
||||
|
||||
while (ms::selector.State() != mm::MovableBase::HomingFailed)
|
||||
main_loop();
|
||||
}
|
||||
|
||||
return SimulateFailedHomePostfix(h);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SimulateFailedHomeSelectorRepeated(T &h) {
|
||||
// we leave Idler aside in this case
|
||||
REQUIRE_FALSE(ms::selector.HomingValid());
|
||||
|
||||
{
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
main_loop();
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
uint32_t selectorSteps = mm::unitToSteps<mm::S_pos_t>(config::selectorLimits.lenght) + 1;
|
||||
uint32_t selectorTriggerShort = selectorSteps / 2;
|
||||
uint32_t maxSteps = selectorTriggerShort + 1;
|
||||
{
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
|
||||
if (i == selectorTriggerShort) {
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
}
|
||||
|
||||
while (ms::selector.State() != mm::MovableBase::HomingFailed)
|
||||
main_loop();
|
||||
}
|
||||
|
||||
return SimulateFailedHomePostfix(h);
|
||||
}
|
||||
|
||||
bool SelectorFailedRetry() {
|
||||
// prepare startup conditions
|
||||
ForceReinitAllAutomata();
|
||||
|
|
@ -194,7 +81,7 @@ bool SelectorFailedRetry() {
|
|||
REQUIRE(SimulateFailedHomeSelectorRepeated(h));
|
||||
}
|
||||
|
||||
SimulateSelectorHoming();
|
||||
SimulateSelectorHoming(h);
|
||||
|
||||
REQUIRE(WhileTopState(h, ProgressCode::Homing, 5000));
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_load_filament.cpp
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "../../modules/stubs/stub_adc.h"
|
||||
|
||||
#include "../stubs/homing.h"
|
||||
#include "../stubs/main_loop_stub.h"
|
||||
#include "../stubs/stub_motion.h"
|
||||
|
||||
|
|
@ -140,10 +141,10 @@ void FailedLoadToFindaResolveManual(uint8_t slot, logic::LoadFilament &lf) {
|
|||
PressButtonAndDebounce(lf, mb::Right);
|
||||
|
||||
// the Idler also engages in this call as this is planned as the next step
|
||||
SimulateIdlerHoming();
|
||||
SimulateIdlerHoming(lf);
|
||||
|
||||
// pulling filament back
|
||||
REQUIRE(VerifyState(lf, mg::FilamentLoadState::InSelector, slot, slot, true, false, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::RetractingFromFinda));
|
||||
REQUIRE(VerifyState(lf, mg::FilamentLoadState::InSelector, slot, slot, true, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::RetractingFromFinda));
|
||||
|
||||
ClearButtons(lf);
|
||||
|
||||
|
|
@ -168,7 +169,7 @@ void FailedLoadToFindaResolveManual(uint8_t slot, logic::LoadFilament &lf) {
|
|||
//
|
||||
// With the introduction of dual-side homing, the simulation gets even harder,
|
||||
// so let's assume the MMU does its job -> prefer simulating selector homing properly and check the machine's state afterwards
|
||||
SimulateSelectorHoming();
|
||||
SimulateSelectorHoming(lf);
|
||||
|
||||
// just one step is necessary to "finish" homing
|
||||
// but the selector then (correctly) plans its move to the original position
|
||||
|
|
@ -184,7 +185,7 @@ void FailedLoadToFindaResolveManualNoFINDA(uint8_t slot, logic::LoadFilament &lf
|
|||
// Perform press on button 2 + debounce + keep FINDA OFF (i.e. the user didn't solve anything)
|
||||
PressButtonAndDebounce(lf, mb::Right);
|
||||
|
||||
SimulateIdlerHoming();
|
||||
SimulateIdlerHoming(lf);
|
||||
|
||||
ClearButtons(lf);
|
||||
|
||||
|
|
@ -196,7 +197,8 @@ void FailedLoadToFindaResolveTryAgain(uint8_t slot, logic::LoadFilament &lf) {
|
|||
PressButtonAndDebounce(lf, mb::Middle);
|
||||
|
||||
// the state machine should have restarted
|
||||
REQUIRE(VerifyState(lf, mg::FilamentLoadState::InSelector, mi::Idler::IdleSlotIndex(), slot, false, false, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::FeedingToFinda));
|
||||
// Idler's position needs to be ignored as it has started homing after the button press
|
||||
REQUIRE(VerifyState(lf, mg::FilamentLoadState::InSelector, config::toolCount, slot, false, false, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::FeedingToFinda));
|
||||
ClearButtons(lf);
|
||||
|
||||
LoadFilamentSuccessful(slot, lf);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,251 @@
|
|||
#include "homing.h"
|
||||
#include "main_loop_stub.h"
|
||||
|
||||
#include "../../../../src/modules/buttons.h"
|
||||
#include "../../../../src/modules/idler.h"
|
||||
#include "../../../../src/modules/motion.h"
|
||||
#include "../../../../src/modules/selector.h"
|
||||
|
||||
#include "../stubs/stub_motion.h"
|
||||
|
||||
void SimulateIdlerAndSelectorHoming(logic::CommandBase &cb) {
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
main_loop();
|
||||
cb.Step();
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
|
||||
// now do a correct amount of steps of each axis towards the other end
|
||||
uint32_t idlerSteps = mm::unitToSteps<mm::I_pos_t>(config::idlerLimits.lenght);
|
||||
uint32_t selectorSteps = mm::unitToSteps<mm::S_pos_t>(config::selectorLimits.lenght);
|
||||
uint32_t maxSteps = std::max(idlerSteps, selectorSteps) + 1;
|
||||
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
|
||||
if (i == idlerSteps) {
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
}
|
||||
if (i == selectorSteps) {
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
}
|
||||
|
||||
// now the Selector and Idler shall perform a move into their parking positions
|
||||
while (ms::selector.State() != mm::MovableBase::Ready || mi::idler.State() != mm::MovableBase::Ready) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
}
|
||||
|
||||
void SimulateIdlerHoming(logic::CommandBase &cb) {
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
main_loop();
|
||||
cb.Step();
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
|
||||
// now do a correct amount of steps of each axis towards the other end
|
||||
uint32_t idlerSteps = mm::unitToSteps<mm::I_pos_t>(config::idlerLimits.lenght);
|
||||
uint32_t maxSteps = idlerSteps + 1;
|
||||
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
|
||||
if (i == idlerSteps) {
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
}
|
||||
}
|
||||
|
||||
// now the Idler shall perform a move into their parking positions
|
||||
while (mi::idler.State() != mm::MovableBase::Ready) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
}
|
||||
|
||||
void SimulateSelectorHoming(logic::CommandBase &cb) {
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
main_loop();
|
||||
cb.Step();
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
|
||||
// now do a correct amount of steps of each axis towards the other end
|
||||
uint32_t selectorSteps = mm::unitToSteps<mm::S_pos_t>(config::selectorLimits.lenght) + 1;
|
||||
uint32_t maxSteps = selectorSteps + 1;
|
||||
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
|
||||
if (i == selectorSteps) {
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
}
|
||||
|
||||
// now the Selector shall perform a move into their parking positions
|
||||
while (ms::selector.State() != mm::MovableBase::Ready) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
}
|
||||
|
||||
bool SimulateFailedHomeSelectorPostfix(logic::CommandBase &cb) {
|
||||
if (!WhileTopState(cb, ProgressCode::Homing, 5))
|
||||
return false;
|
||||
if (cb.Error() != ErrorCode::HOMING_SELECTOR_FAILED)
|
||||
return false;
|
||||
if (cb.State() != ProgressCode::ERRWaitingForUser)
|
||||
return false;
|
||||
if (mm::motion.Enabled(mm::Selector))
|
||||
return false;
|
||||
|
||||
// do a few steps before pushing the button
|
||||
WhileTopState(cb, ProgressCode::ERRWaitingForUser, 5);
|
||||
|
||||
if (mm::motion.Enabled(mm::Selector))
|
||||
return false;
|
||||
|
||||
PressButtonAndDebounce(cb, mb::Middle);
|
||||
|
||||
// it shall start homing again
|
||||
if (cb.Error() != ErrorCode::RUNNING)
|
||||
return false;
|
||||
if (cb.State() != ProgressCode::Homing)
|
||||
return false;
|
||||
if (ms::selector.HomingValid())
|
||||
return false;
|
||||
if (!mm::motion.Enabled(mm::Selector))
|
||||
return false;
|
||||
|
||||
ClearButtons(cb);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimulateFailedHomeFirstTime(logic::CommandBase &cb) {
|
||||
if (mi::idler.HomingValid())
|
||||
return false;
|
||||
if (ms::selector.HomingValid())
|
||||
return false;
|
||||
|
||||
{
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
main_loop();
|
||||
cb.Step();
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
}
|
||||
// now do a correct amount of steps of each axis towards the other end
|
||||
uint32_t idlerSteps = mm::unitToSteps<mm::I_pos_t>(config::idlerLimits.lenght);
|
||||
// now do LESS steps than expected to simulate something is blocking the selector
|
||||
uint32_t selectorSteps = mm::unitToSteps<mm::S_pos_t>(config::selectorLimits.lenght) + 1;
|
||||
uint32_t selectorTriggerShort = std::min(idlerSteps, selectorSteps) / 2;
|
||||
uint32_t maxSteps = selectorTriggerShort + 1;
|
||||
{
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
|
||||
if (i == selectorTriggerShort) {
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the Idler finishes its homing procedure (makes further checks much easier)
|
||||
for (uint32_t i = maxSteps; i < idlerSteps + 1; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
if (i == idlerSteps) {
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
}
|
||||
}
|
||||
|
||||
while (ms::selector.State() != mm::MovableBase::HomingFailed) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
}
|
||||
|
||||
return SimulateFailedHomeSelectorPostfix(cb);
|
||||
}
|
||||
|
||||
bool SimulateFailedHomeSelectorRepeated(logic::CommandBase &cb) {
|
||||
// we leave Idler aside in this case
|
||||
if (ms::selector.HomingValid())
|
||||
return false;
|
||||
|
||||
{
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
main_loop();
|
||||
cb.Step();
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
uint32_t selectorSteps = mm::unitToSteps<mm::S_pos_t>(config::selectorLimits.lenght) + 1;
|
||||
uint32_t selectorTriggerShort = selectorSteps / 2;
|
||||
uint32_t maxSteps = selectorTriggerShort + 1;
|
||||
{
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
|
||||
if (i == selectorTriggerShort) {
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
}
|
||||
|
||||
while (ms::selector.State() != mm::MovableBase::HomingFailed) {
|
||||
main_loop();
|
||||
cb.Step();
|
||||
}
|
||||
}
|
||||
|
||||
return SimulateFailedHomeSelectorPostfix(cb);
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
namespace logic {
|
||||
class CommandBase;
|
||||
}
|
||||
|
||||
void SimulateIdlerHoming(logic::CommandBase &cb);
|
||||
void SimulateSelectorHoming(logic::CommandBase &cb);
|
||||
void SimulateIdlerAndSelectorHoming(logic::CommandBase &cb);
|
||||
bool SimulateFailedHomeFirstTime(logic::CommandBase &cb);
|
||||
bool SimulateFailedHomeSelectorRepeated(logic::CommandBase &cb);
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include "main_loop_stub.h"
|
||||
#include "homing.h"
|
||||
|
||||
#include "../../modules/stubs/stub_adc.h"
|
||||
#include "../../modules/stubs/stub_eeprom.h"
|
||||
|
|
@ -16,6 +17,8 @@
|
|||
#include "../../../../src/modules/selector.h"
|
||||
#include "../../../../src/modules/user_input.h"
|
||||
|
||||
#include "../../../../src/logic/no_command.h"
|
||||
|
||||
#include "../stubs/stub_motion.h"
|
||||
|
||||
#include <new> // bring in placement new
|
||||
|
|
@ -77,102 +80,8 @@ void ForceReinitAllAutomata() {
|
|||
void HomeIdlerAndSelector() {
|
||||
ms::selector.InvalidateHoming();
|
||||
mi::idler.InvalidateHoming();
|
||||
SimulateIdlerAndSelectorHoming();
|
||||
}
|
||||
|
||||
void SimulateIdlerAndSelectorHoming() {
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
main_loop();
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
|
||||
// now do a correct amount of steps of each axis towards the other end
|
||||
uint32_t idlerSteps = mm::unitToSteps<mm::I_pos_t>(config::idlerLimits.lenght);
|
||||
uint32_t selectorSteps = mm::unitToSteps<mm::S_pos_t>(config::selectorLimits.lenght);
|
||||
uint32_t maxSteps = std::max(idlerSteps, selectorSteps) + 1;
|
||||
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
|
||||
if (i == idlerSteps) {
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
}
|
||||
if (i == selectorSteps) {
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
}
|
||||
|
||||
// now the Selector and Idler shall perform a move into their parking positions
|
||||
while (ms::selector.State() != mm::MovableBase::Ready || mi::idler.State() != mm::MovableBase::Ready)
|
||||
main_loop();
|
||||
}
|
||||
|
||||
void SimulateIdlerHoming() {
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
main_loop();
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
|
||||
// now do a correct amount of steps of each axis towards the other end
|
||||
uint32_t idlerSteps = mm::unitToSteps<mm::I_pos_t>(config::idlerLimits.lenght);
|
||||
uint32_t maxSteps = idlerSteps + 1;
|
||||
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
|
||||
if (i == idlerSteps) {
|
||||
mm::TriggerStallGuard(mm::Idler);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Idler);
|
||||
}
|
||||
}
|
||||
|
||||
// now the Idler shall perform a move into their parking positions
|
||||
while (mi::idler.State() != mm::MovableBase::Ready)
|
||||
main_loop();
|
||||
}
|
||||
|
||||
void SimulateSelectorHoming() {
|
||||
// do 5 steps until we trigger the simulated stallguard
|
||||
for (uint8_t i = 0; i < 5; ++i) {
|
||||
main_loop();
|
||||
}
|
||||
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
main_loop();
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
|
||||
// now do a correct amount of steps of each axis towards the other end
|
||||
uint32_t selectorSteps = mm::unitToSteps<mm::S_pos_t>(config::selectorLimits.lenght) + 1;
|
||||
uint32_t maxSteps = selectorSteps + 1;
|
||||
|
||||
for (uint32_t i = 0; i < maxSteps; ++i) {
|
||||
main_loop();
|
||||
|
||||
if (i == selectorSteps) {
|
||||
mm::TriggerStallGuard(mm::Selector);
|
||||
} else {
|
||||
mm::motion.StallGuardReset(mm::Selector);
|
||||
}
|
||||
}
|
||||
|
||||
// now the Selector shall perform a move into their parking positions
|
||||
while (ms::selector.State() != mm::MovableBase::Ready)
|
||||
main_loop();
|
||||
logic::NoCommand nc; // just a dummy instance which has an empty Step()
|
||||
SimulateIdlerAndSelectorHoming(nc);
|
||||
}
|
||||
|
||||
void EnsureActiveSlotIndex(uint8_t slot, mg::FilamentLoadState loadState) {
|
||||
|
|
@ -207,3 +116,19 @@ bool SimulateUnloadToFINDA(uint32_t step, uint32_t fsOff, uint32_t findaOff) {
|
|||
}
|
||||
return mf::finda.Pressed();
|
||||
}
|
||||
|
||||
void PressButtonAndDebounce(logic::CommandBase &cb, uint8_t btnIndex) {
|
||||
hal::adc::SetADC(config::buttonsADCIndex, config::buttonADCLimits[btnIndex][0] + 1);
|
||||
while (!mb::buttons.ButtonPressed(btnIndex)) {
|
||||
main_loop();
|
||||
cb.Step(); // Inner
|
||||
}
|
||||
}
|
||||
|
||||
void ClearButtons(logic::CommandBase &cb) {
|
||||
hal::adc::SetADC(config::buttonsADCIndex, config::buttonADCMaxValue);
|
||||
while (mb::buttons.AnyButtonPressed()) {
|
||||
main_loop();
|
||||
cb.Step(); // Inner
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,13 @@ bool WhileTopState(SM &sm, ProgressCode state, uint32_t maxLoops = 5000) {
|
|||
}
|
||||
|
||||
void EnsureActiveSlotIndex(uint8_t slot, modules::globals::FilamentLoadState loadState);
|
||||
|
||||
void SetFINDAStateAndDebounce(bool press);
|
||||
void SimulateIdlerHoming();
|
||||
void SimulateSelectorHoming();
|
||||
void SimulateIdlerAndSelectorHoming();
|
||||
bool SimulateUnloadToFINDA(uint32_t step, uint32_t fsOff, uint32_t findaOff);
|
||||
|
||||
void PressButtonAndDebounce(logic::CommandBase &cb, uint8_t btnIndex);
|
||||
void ClearButtons(logic::CommandBase &cb);
|
||||
|
||||
// these are recommended max steps for simulated movement of the idler and selector
|
||||
// - roughly the amount of motion steps from one end to the other + some margin
|
||||
// ... could be computed in the future from the pre-set number of microsteps and real positions
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_tool_change.cpp
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_unload_filament.cpp
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "../../modules/stubs/stub_adc.h"
|
||||
|
||||
#include "../stubs/homing.h"
|
||||
#include "../stubs/main_loop_stub.h"
|
||||
#include "../stubs/stub_motion.h"
|
||||
|
||||
|
|
@ -39,7 +40,8 @@ void RegularUnloadFromSlot04Init(uint8_t slot, logic::UnloadFilament &uf) {
|
|||
uf.Reset(slot);
|
||||
}
|
||||
|
||||
void RegularUnloadFromSlot04(uint8_t slot, logic::UnloadFilament &uf, uint8_t entryIdlerSlotIndex, bool selectorShallHomeAtEnd) {
|
||||
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
|
||||
|
|
@ -47,7 +49,7 @@ void RegularUnloadFromSlot04(uint8_t slot, logic::UnloadFilament &uf, uint8_t en
|
|||
// FINDA on
|
||||
// green LED should blink, red off
|
||||
REQUIRE(VerifyState(uf, (mg::FilamentLoadState)(mg::FilamentLoadState::InNozzle | mg::FilamentLoadState::InSelector),
|
||||
entryIdlerSlotIndex, slot, true, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda));
|
||||
entryIdlerSlotIndex, slot, true, true, entryGreenLED, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda));
|
||||
|
||||
// run the automaton
|
||||
// Stage 1 - unloading to FINDA
|
||||
|
|
@ -74,7 +76,7 @@ void RegularUnloadFromSlot04(uint8_t slot, logic::UnloadFilament &uf, uint8_t en
|
|||
REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps));
|
||||
|
||||
if (selectorShallHomeAtEnd) {
|
||||
SimulateSelectorHoming();
|
||||
SimulateSelectorHoming(uf);
|
||||
}
|
||||
|
||||
// filament unloaded
|
||||
|
|
@ -95,7 +97,7 @@ 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);
|
||||
RegularUnloadFromSlot04(slot, uf, mi::Idler::IdleSlotIndex(), false, ml::off);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -256,7 +258,7 @@ void FindaDidntTriggerResolveTryAgain(uint8_t slot, logic::UnloadFilament &uf) {
|
|||
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();
|
||||
SimulateIdlerHoming(uf);
|
||||
}
|
||||
|
||||
TEST_CASE("unload_filament::finda_didnt_trigger_resolve_try_again", "[unload_filament]") {
|
||||
|
|
@ -264,7 +266,7 @@ TEST_CASE("unload_filament::finda_didnt_trigger_resolve_try_again", "[unload_fil
|
|||
logic::UnloadFilament uf;
|
||||
FindaDidntTriggerCommonSetup(slot, uf);
|
||||
FindaDidntTriggerResolveTryAgain(slot, uf);
|
||||
RegularUnloadFromSlot04(slot, uf, slot, true);
|
||||
RegularUnloadFromSlot04(slot, uf, slot, true, ml::blink0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +300,7 @@ void FailedUnloadResolveManual(uint8_t slot, logic::UnloadFilament &uf) {
|
|||
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();
|
||||
SimulateIdlerHoming(uf);
|
||||
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::FeedingToFinda, 5000));
|
||||
|
||||
|
|
@ -306,7 +308,7 @@ void FailedUnloadResolveManual(uint8_t slot, logic::UnloadFilament &uf) {
|
|||
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps));
|
||||
|
||||
SimulateSelectorHoming();
|
||||
SimulateSelectorHoming(uf);
|
||||
|
||||
REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
|
||||
}
|
||||
|
|
@ -354,3 +356,31 @@ TEST_CASE("unload_filament::failed_unload_to_finda_0-4_resolve_manual_FSensor_on
|
|||
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);
|
||||
SimulateIdlerHoming(uf); // make Idler happy
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::FeedingToFinda, 5000));
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::RetractingFromFinda, idlerEngageDisengageMaxSteps));
|
||||
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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# define the test executable
|
||||
add_executable(
|
||||
unload_to_finda_tests
|
||||
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/buttons.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/debouncer.cpp
|
||||
|
|
@ -21,6 +22,7 @@ add_executable(
|
|||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_timebase.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
${LOGIC_STUBS_DIR}/homing.cpp
|
||||
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
|
||||
${LOGIC_STUBS_DIR}/stub_motion.cpp
|
||||
test_unload_to_finda.cpp
|
||||
|
|
|
|||
Loading…
Reference in New Issue