Logic layer Eject filament unit tests
initial setup, it compiles, but is blocked by Unload filamentpull/27/head^2
parent
1f8934c2c1
commit
317a486d1e
|
|
@ -48,6 +48,9 @@ bool CutFilament::Step() {
|
||||||
case ErrorCode::UNLOAD_ERROR2: // @@TODO what shall we do in case of this error?
|
case ErrorCode::UNLOAD_ERROR2: // @@TODO what shall we do in case of this error?
|
||||||
case ErrorCode::FINDA_DIDNT_TRIGGER:
|
case ErrorCode::FINDA_DIDNT_TRIGGER:
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
state = ProgressCode::ERRInternal;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -98,6 +101,10 @@ bool CutFilament::Step() {
|
||||||
feed.Reset(true);
|
feed.Reset(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default: // we got into an unhandled state, better report it
|
||||||
|
state = ProgressCode::ERRInternal;
|
||||||
|
error = ErrorCode::INTERNAL;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,24 +37,20 @@ void EjectFilament::MoveSelectorAside() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EjectFilament::Step() {
|
bool EjectFilament::Step() {
|
||||||
constexpr const uint16_t eject_steps = 500; //@@TODO
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case ProgressCode::UnloadingFilament:
|
case ProgressCode::UnloadingFilament:
|
||||||
if (unl.Step()) {
|
if (unl.Step()) {
|
||||||
// unloading sequence finished
|
// unloading sequence finished - basically, no errors can occurr here
|
||||||
switch (unl.Error()) {
|
// as UnloadFilament should handle all the possible error states on its own
|
||||||
case ErrorCode::OK: // finished successfully
|
// There is no way the UnloadFilament to finish in an error state
|
||||||
case ErrorCode::UNLOAD_ERROR2: // @@TODO what shall we do in case of this error?
|
MoveSelectorAside();
|
||||||
case ErrorCode::FINDA_DIDNT_TRIGGER:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::ParkingSelector:
|
case ProgressCode::ParkingSelector:
|
||||||
if (mm::motion.QueueEmpty()) { // selector parked aside
|
if (mm::motion.QueueEmpty()) { // selector parked aside
|
||||||
state = ProgressCode::EjectingFilament;
|
state = ProgressCode::EjectingFilament;
|
||||||
mm::motion.InitAxis(mm::Pulley);
|
mm::motion.InitAxis(mm::Pulley);
|
||||||
mm::motion.PlanMove(eject_steps, 0, 0, 1500, 0, 0);
|
mm::motion.PlanMove(ejectSteps, 0, 0, 1500, 0, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::EjectingFilament:
|
case ProgressCode::EjectingFilament:
|
||||||
|
|
@ -64,15 +60,37 @@ bool EjectFilament::Step() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::DisengagingIdler:
|
case ProgressCode::DisengagingIdler:
|
||||||
if (mm::motion.QueueEmpty()) { // idler disengaged
|
if (!mi::idler.Engaged()) { // idler disengaged
|
||||||
mm::motion.DisableAxis(mm::Pulley);
|
mm::motion.DisableAxis(mm::Pulley);
|
||||||
state = ProgressCode::OK;
|
state = ProgressCode::OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ProgressCode::OK:
|
case ProgressCode::OK:
|
||||||
return true;
|
return true;
|
||||||
|
default: // we got into an unhandled state, better report it
|
||||||
|
state = ProgressCode::ERRInternal;
|
||||||
|
error = ErrorCode::INTERNAL;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProgressCode EjectFilament::State() const {
|
||||||
|
switch (state) {
|
||||||
|
case ProgressCode::UnloadingFilament:
|
||||||
|
return unl.State(); // report sub-automaton states properly
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode EjectFilament::Error() const {
|
||||||
|
switch (state) {
|
||||||
|
case ProgressCode::UnloadingFilament:
|
||||||
|
return unl.Error(); // report sub-automaton errors properly
|
||||||
|
default:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace logic
|
} // namespace logic
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,12 @@ public:
|
||||||
/// @returns true if the state machine finished its job, false otherwise
|
/// @returns true if the state machine finished its job, false otherwise
|
||||||
bool Step() override;
|
bool Step() override;
|
||||||
|
|
||||||
|
virtual ProgressCode State() const override;
|
||||||
|
|
||||||
|
virtual ErrorCode Error() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
constexpr static const uint16_t ejectSteps = 500; //@@TODO
|
||||||
UnloadFilament unl; ///< a high-level command/operation may be used as a building block of other operations as well
|
UnloadFilament unl; ///< a high-level command/operation may be used as a building block of other operations as well
|
||||||
uint8_t slot;
|
uint8_t slot;
|
||||||
void MoveSelectorAside();
|
void MoveSelectorAside();
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,5 @@ enum class ErrorCode : int_fast8_t {
|
||||||
FINDA_DIDNT_TRIGGER = -1, ///< FINDA didn't trigger while unloading filament - either there is something blocking the metal ball or a cable is broken/disconnected
|
FINDA_DIDNT_TRIGGER = -1, ///< FINDA didn't trigger while unloading filament - either there is something blocking the metal ball or a cable is broken/disconnected
|
||||||
UNLOAD_ERROR2 = -2,
|
UNLOAD_ERROR2 = -2,
|
||||||
|
|
||||||
|
INTERNAL = -127, ///< internal runtime error (software)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ enum class ProgressCode : uint_fast8_t {
|
||||||
|
|
||||||
ERR1DisengagingIdler,
|
ERR1DisengagingIdler,
|
||||||
ERR1WaitingForUser,
|
ERR1WaitingForUser,
|
||||||
|
ERRInternal,
|
||||||
|
|
||||||
UnloadingFilament,
|
UnloadingFilament,
|
||||||
LoadingFilament,
|
LoadingFilament,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ add_subdirectory(feed_to_finda)
|
||||||
|
|
||||||
# add_subdirectory(unload_to_finda)
|
# add_subdirectory(unload_to_finda)
|
||||||
|
|
||||||
# add_subdirectory(eject_filament)
|
add_subdirectory(eject_filament)
|
||||||
|
|
||||||
# add_subdirectory(load_filament)
|
# add_subdirectory(load_filament)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
# define the test executable
|
||||||
|
add_executable(
|
||||||
|
eject_filament_tests
|
||||||
|
../../../../src/logic/eject_filament.cpp
|
||||||
|
../../../../src/logic/feed_to_finda.cpp
|
||||||
|
../../../../src/logic/unload_filament.cpp
|
||||||
|
../../../../src/logic/unload_to_finda.cpp
|
||||||
|
../../../../src/modules/buttons.cpp
|
||||||
|
../../../../src/modules/debouncer.cpp
|
||||||
|
../../../../src/modules/finda.cpp
|
||||||
|
../../../../src/modules/fsensor.cpp
|
||||||
|
../../../../src/modules/globals.cpp
|
||||||
|
../../../../src/modules/idler.cpp
|
||||||
|
../../../../src/modules/leds.cpp
|
||||||
|
../../../../src/modules/permanent_storage.cpp
|
||||||
|
../../../../src/modules/selector.cpp
|
||||||
|
../../modules/stubs/stub_adc.cpp
|
||||||
|
../../modules/stubs/stub_eeprom.cpp
|
||||||
|
../../modules/stubs/stub_shr16.cpp
|
||||||
|
../../modules/stubs/stub_timebase.cpp
|
||||||
|
../stubs/main_loop_stub.cpp
|
||||||
|
../stubs/stub_motion.cpp
|
||||||
|
test_eject_filament.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# define required search paths
|
||||||
|
target_include_directories(
|
||||||
|
eject_filament_tests PUBLIC ${CMAKE_SOURCE_DIR}/src/modules ${CMAKE_SOURCE_DIR}/src/hal
|
||||||
|
${CMAKE_SOURCE_DIR}/src/logic
|
||||||
|
)
|
||||||
|
|
||||||
|
# tell build system about the test case
|
||||||
|
add_catch_test(eject_filament_tests)
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
#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/eject_filament.h"
|
||||||
|
|
||||||
|
#include "../../modules/stubs/stub_adc.h"
|
||||||
|
|
||||||
|
#include "../stubs/main_loop_stub.h"
|
||||||
|
#include "../stubs/stub_motion.h"
|
||||||
|
|
||||||
|
using Catch::Matchers::Equals;
|
||||||
|
|
||||||
|
template <typename COND>
|
||||||
|
bool WhileCondition(COND cond, uint32_t maxLoops = 5000) {
|
||||||
|
while (cond() && --maxLoops) {
|
||||||
|
main_loop();
|
||||||
|
}
|
||||||
|
return maxLoops > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("eject_filament::eject0", "[eject_filament]") {
|
||||||
|
using namespace logic;
|
||||||
|
|
||||||
|
ForceReinitAllAutomata();
|
||||||
|
|
||||||
|
EjectFilament ef;
|
||||||
|
// restart the automaton
|
||||||
|
currentCommand = &ef;
|
||||||
|
ef.Reset(0);
|
||||||
|
|
||||||
|
main_loop();
|
||||||
|
|
||||||
|
// it should have instructed the selector and idler to move to slot 1
|
||||||
|
// check if the idler and selector have the right command
|
||||||
|
CHECK(modules::motion::axes[modules::motion::Idler].targetPos == 0); // @@TODO constants
|
||||||
|
CHECK(modules::motion::axes[modules::motion::Selector].targetPos == 0); // @@TODO constants
|
||||||
|
|
||||||
|
// now cycle at most some number of cycles (to be determined yet) and then verify, that the idler and selector reached their target positions
|
||||||
|
REQUIRE(WhileCondition([&]() { return ef.State() == ProgressCode::SelectingFilamentSlot; }, 5000));
|
||||||
|
|
||||||
|
// idler and selector reached their target positions and the CF automaton will start feeding to FINDA as the next step
|
||||||
|
REQUIRE(ef.State() == ProgressCode::FeedingToFinda);
|
||||||
|
// prepare for simulated finda trigger
|
||||||
|
hal::adc::ReinitADC(1, hal::adc::TADCData({ 0, 0, 0, 0, 600, 700, 800, 900 }), 10);
|
||||||
|
REQUIRE(WhileCondition([&]() { return ef.State() == ProgressCode::FeedingToFinda; }, 50000));
|
||||||
|
|
||||||
|
// filament fed into FINDA, cutting...
|
||||||
|
REQUIRE(ef.State() == ProgressCode::PreparingBlade);
|
||||||
|
REQUIRE(WhileCondition([&]() { return ef.State() == ProgressCode::PreparingBlade; }, 5000));
|
||||||
|
|
||||||
|
REQUIRE(ef.State() == ProgressCode::EngagingIdler);
|
||||||
|
REQUIRE(WhileCondition([&]() { return ef.State() == ProgressCode::EngagingIdler; }, 5000));
|
||||||
|
|
||||||
|
// the idler should be at the active slot @@TODO
|
||||||
|
REQUIRE(ef.State() == ProgressCode::PushingFilament);
|
||||||
|
REQUIRE(WhileCondition([&]() { return ef.State() == ProgressCode::PushingFilament; }, 5000));
|
||||||
|
|
||||||
|
// filament pushed - performing cut
|
||||||
|
REQUIRE(ef.State() == ProgressCode::PerformingCut);
|
||||||
|
REQUIRE(WhileCondition([&]() { return ef.State() == ProgressCode::PerformingCut; }, 5000));
|
||||||
|
|
||||||
|
// returning selector
|
||||||
|
REQUIRE(ef.State() == ProgressCode::ReturningSelector);
|
||||||
|
REQUIRE(WhileCondition([&]() { return ef.State() == ProgressCode::ReturningSelector; }, 5000));
|
||||||
|
|
||||||
|
// the next states are still @@TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// comments:
|
||||||
|
// The tricky part of the whole state machine are the edge cases - filament not loaded, stall guards etc.
|
||||||
|
// ... all the external influence we can get on the real HW
|
||||||
|
// But the good news is we can simulate them all in the unit test and thus ensure proper handling
|
||||||
Loading…
Reference in New Issue