Fix unit tests

- circular buffer can return its count of elements (even though a better solution may be implemeted later)
- stub_motion can handle multiple planned moves
- improved load/unload filament tests
pull/165/head
D.R.racer 2022-05-04 09:07:03 +02:00 committed by DRracer
parent 1d8c1e8f3f
commit 8ce029a28c
13 changed files with 110 additions and 55 deletions

View File

@ -56,8 +56,15 @@ public:
} }
/// @returns number of elements in the buffer /// @returns number of elements in the buffer
/// @@TODO better solution if it exists
inline index_t count() const { inline index_t count() const {
return 0; // @@TODO index_t i = tail;
index_t c = 0;
while (i != head) {
i = next(i);
++c;
}
return c;
} }
protected: protected:
@ -122,6 +129,10 @@ public:
return true; return true;
} }
index_t count() const {
return index.count();
}
protected: protected:
T data[size]; ///< array of stored elements T data[size]; ///< array of stored elements
CircularIndex<index_t, size> index; ///< circular index CircularIndex<index_t, size> index; ///< circular index

View File

@ -21,7 +21,7 @@ void LoadFilament::Reset(uint8_t param) {
} }
dbg_logic_P(PSTR("Load Filament")); dbg_logic_P(PSTR("Load Filament"));
mg::globals.SetFilamentLoaded(param, mg::FilamentLoadState::AtPulley); // still at pulley, haven't moved yet mg::globals.SetFilamentLoaded(param, mg::FilamentLoadState::AtPulley); // still at pulley, haven't moved yet
Reset2(false); Reset2(true);
} }
void LoadFilament::ResetUnlimited(uint8_t param) { void LoadFilament::ResetUnlimited(uint8_t param) {
@ -30,13 +30,13 @@ void LoadFilament::ResetUnlimited(uint8_t param) {
} }
dbg_logic_P(PSTR("Load Filament")); dbg_logic_P(PSTR("Load Filament"));
mg::globals.SetFilamentLoaded(param, mg::FilamentLoadState::AtPulley); // still at pulley, haven't moved yet mg::globals.SetFilamentLoaded(param, mg::FilamentLoadState::AtPulley); // still at pulley, haven't moved yet
Reset2(true); Reset2(false);
} }
void logic::LoadFilament::Reset2(bool unlimited) { void logic::LoadFilament::Reset2(bool feedPhaseLimited) {
state = ProgressCode::FeedingToFinda; state = ProgressCode::FeedingToFinda;
error = ErrorCode::RUNNING; error = ErrorCode::RUNNING;
feed.Reset(unlimited, true); feed.Reset(feedPhaseLimited, true);
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::blink0, ml::off); ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::blink0, ml::off);
} }
@ -100,7 +100,7 @@ bool LoadFilament::StepInner() {
case mui::Event::Middle: // try again the whole sequence case mui::Event::Middle: // try again the whole sequence
// however it depends on the state of FINDA - if it is on, we must perform unload first // however it depends on the state of FINDA - if it is on, we must perform unload first
if (!mf::finda.Pressed()) { if (!mf::finda.Pressed()) {
Reset2(); Reset2(false);
} else { } else {
GoToRetractingFromFinda(); GoToRetractingFromFinda();
} }

View File

@ -26,7 +26,7 @@ public:
private: private:
void GoToRetractingFromFinda(); void GoToRetractingFromFinda();
void Reset2(bool unlimited); void Reset2(bool feedPhaseLimited);
/// Common code for a correct completion of UnloadFilament /// Common code for a correct completion of UnloadFilament
void FinishedCorrectly(); void FinishedCorrectly();

View File

@ -313,11 +313,15 @@ public:
bool QueueEmpty(Axis axis) const; bool QueueEmpty(Axis axis) const;
#endif #endif
#if !defined(UNITTEST) || defined(UNITTEST_MOTION)
/// @returns number of planned moves on an axis /// @returns number of planned moves on an axis
uint8_t PlannedMoves(Axis axis) const { uint8_t PlannedMoves(Axis axis) const {
return axisData[axis].ctrl.QueueEmpty(); return axisData[axis].ctrl.PlannedMoves();
} }
#else
// Force STUB for testing
uint8_t PlannedMoves(Axis axis) const;
#endif
/// @returns false if new moves can still be planned for one axis /// @returns false if new moves can still be planned for one axis
/// @param axis axis requested /// @param axis axis requested
bool Full(Axis axis) const { return axisData[axis].ctrl.Full(); } bool Full(Axis axis) const { return axisData[axis].ctrl.Full(); }

View File

@ -14,6 +14,7 @@ TEST_CASE("circular_buffer::basic", "[circular_buffer]") {
// since its capacity was defined as 32, at least one element must be successfully inserted // since its capacity was defined as 32, at least one element must be successfully inserted
CHECK(cb.push(1)); CHECK(cb.push(1));
CHECK(cb.count() == 1);
// is the element there? // is the element there?
REQUIRE(!cb.empty()); REQUIRE(!cb.empty());
@ -24,6 +25,7 @@ TEST_CASE("circular_buffer::basic", "[circular_buffer]") {
CHECK(cb.pop(b)); CHECK(cb.pop(b));
CHECK(b == 1); CHECK(b == 1);
CHECK(cb.empty()); CHECK(cb.empty());
CHECK(cb.count() == 0);
} }
TEST_CASE("circular_buffer::fill", "[circular_buffer]") { TEST_CASE("circular_buffer::fill", "[circular_buffer]") {
@ -34,24 +36,30 @@ TEST_CASE("circular_buffer::fill", "[circular_buffer]") {
// start with an empty buffer // start with an empty buffer
CB cb; CB cb;
REQUIRE(cb.empty()); REQUIRE(cb.empty());
REQUIRE(cb.count() == 0);
// ensure we can fill the buffer // ensure we can fill the buffer
for (auto i = 0; i != size; ++i) { for (auto i = 0; i != size; ++i) {
CHECK(!cb.full()); CHECK(!cb.full());
cb.push(i); cb.push(i);
CHECK(cb.count() == i + 1);
} }
REQUIRE(cb.full()); REQUIRE(cb.full());
REQUIRE(cb.count() == size);
// ensure another push fails // ensure another push fails
REQUIRE(!cb.push(0)); REQUIRE(!cb.push(0));
REQUIRE(cb.count() == size);
// retrieve all elements // retrieve all elements
for (auto i = 0; i != size; ++i) { for (auto i = 0; i != size; ++i) {
uint8_t v; uint8_t v;
CHECK(cb.pop(v)); CHECK(cb.pop(v));
CHECK(v == i); CHECK(v == i);
REQUIRE(cb.count() == size - i - 1);
} }
REQUIRE(cb.empty()); REQUIRE(cb.empty());
REQUIRE(cb.count() == 0);
} }
TEST_CASE("circular_buffer::wrap_around", "[circular_buffer]") { TEST_CASE("circular_buffer::wrap_around", "[circular_buffer]") {
@ -84,15 +92,18 @@ TEST_CASE("circular_buffer::wrap_around", "[circular_buffer]") {
CHECK(!cb.full()); CHECK(!cb.full());
cb.push(i); cb.push(i);
CHECK(!cb.empty()); CHECK(!cb.empty());
CHECK(cb.count() == i + 1);
} }
REQUIRE(cb.full()); REQUIRE(cb.full());
REQUIRE(!cb.empty()); REQUIRE(!cb.empty());
REQUIRE(cb.count() == size);
// retrieve all elements // retrieve all elements
for (auto i = 0; i != size; ++i) { for (auto i = 0; i != size; ++i) {
uint8_t v; uint8_t v;
CHECK(cb.pop(v)); CHECK(cb.pop(v));
CHECK(v == i); CHECK(v == i);
CHECK(cb.count() == size - i - 1);
} }
REQUIRE(cb.empty()); REQUIRE(cb.empty());
} }

View File

@ -36,8 +36,8 @@ TEST_CASE("eject_filament::eject0", "[eject_filament][.]") {
// it should have instructed the selector and idler to move to slot 1 // it should have instructed the selector and idler to move to slot 1
// check if the idler and selector have the right command // check if the idler and selector have the right command
CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(4).v); CHECK(mm::AxisNearestTargetPos(mm::Selector) == ms::Selector::SlotPosition(4).v);
// now cycle at most some number of cycles (to be determined yet) and then verify, that the idler and selector reached their target positions // 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(WhileTopState(ef, ProgressCode::SelectingFilamentSlot, 5000)); REQUIRE(WhileTopState(ef, ProgressCode::SelectingFilamentSlot, 5000));

View File

@ -37,8 +37,8 @@ TEST_CASE("feed_to_bondtech::feed_phase_unlimited", "[feed_to_bondtech]") {
// it should have instructed the selector and idler to move to slot 0 // it should have instructed the selector and idler to move to slot 0
// check if the idler and selector have the right command // check if the idler and selector have the right command
CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Selector) == ms::Selector::SlotPosition(0).v);
CHECK(mm::axes[mm::Idler].enabled == true); CHECK(mm::axes[mm::Idler].enabled == true);
// engaging idler // engaging idler

View File

@ -37,8 +37,8 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
// it should have instructed the selector and idler to move to slot 1 // it should have instructed the selector and idler to move to slot 1
// check if the idler and selector have the right command // check if the idler and selector have the right command
CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Selector) == ms::Selector::SlotPosition(0).v);
// engaging idler // engaging idler
REQUIRE(WhileCondition( REQUIRE(WhileCondition(
@ -51,7 +51,7 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
CHECK(mm::axes[mm::Pulley].enabled == true); CHECK(mm::axes[mm::Pulley].enabled == true);
// idler engaged, selector in position, we'll start pushing filament // idler engaged, selector in position, we'll start pushing filament
REQUIRE(ff.State() == FeedToFinda::PushingFilament); REQUIRE(ff.State() == FeedToFinda::PushingFilamentUnlimited);
// 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) // 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); REQUIRE(ml::leds.Mode(mg::globals.ActiveSlot(), ml::green) == ml::blink0);
@ -60,7 +60,7 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
REQUIRE(WhileCondition( REQUIRE(WhileCondition(
ff, ff,
[&](uint32_t) { return ff.State() == FeedToFinda::PushingFilament; }, [&](uint32_t) { return ff.State() == FeedToFinda::PushingFilamentUnlimited; },
1500)); 1500));
// From now on the FINDA is reported as ON // From now on the FINDA is reported as ON
@ -105,8 +105,8 @@ TEST_CASE("feed_to_finda::FINDA_failed", "[feed_to_finda]") {
// it should have instructed the selector and idler to move to slot 1 // it should have instructed the selector and idler to move to slot 1
// check if the idler and selector have the right command // check if the idler and selector have the right command
CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Selector) == ms::Selector::SlotPosition(0).v);
// engaging idler // engaging idler
REQUIRE(WhileCondition( REQUIRE(WhileCondition(

View File

@ -19,10 +19,11 @@
#include "../stubs/stub_motion.h" #include "../stubs/stub_motion.h"
using Catch::Matchers::Equals; using Catch::Matchers::Equals;
using namespace std::placeholders;
#include "../helpers/helpers.ipp" #include "../helpers/helpers.ipp"
void LoadFilamentCommonSetup(uint8_t slot, logic::LoadFilament &lf) { void LoadFilamentCommonSetup(uint8_t slot, logic::LoadFilament &lf, bool feedUnlimited) {
ForceReinitAllAutomata(); ForceReinitAllAutomata();
// change the startup to what we need here // change the startup to what we need here
@ -32,7 +33,11 @@ void LoadFilamentCommonSetup(uint8_t slot, logic::LoadFilament &lf) {
REQUIRE(VerifyState(lf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK)); REQUIRE(VerifyState(lf, mg::FilamentLoadState::AtPulley, mi::Idler::IdleSlotIndex(), slot, false, false, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK));
// restart the automaton // restart the automaton
lf.Reset(slot); if (feedUnlimited) {
lf.ResetUnlimited(slot);
} else {
lf.Reset(slot);
}
// Stage 0 - verify state just after Reset() // Stage 0 - verify state just after Reset()
// we assume the filament is not loaded // we assume the filament is not loaded
@ -76,7 +81,7 @@ void LoadFilamentSuccessful(uint8_t slot, logic::LoadFilament &lf) {
TEST_CASE("load_filament::regular_load_to_slot_0-4", "[load_filament]") { TEST_CASE("load_filament::regular_load_to_slot_0-4", "[load_filament]") {
for (uint8_t slot = 0; slot < config::toolCount; ++slot) { for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
logic::LoadFilament lf; logic::LoadFilament lf;
LoadFilamentCommonSetup(slot, lf); LoadFilamentCommonSetup(slot, lf, false);
LoadFilamentSuccessful(slot, lf); LoadFilamentSuccessful(slot, lf);
} }
} }
@ -207,7 +212,7 @@ void FailedLoadToFindaResolveTryAgain(uint8_t slot, logic::LoadFilament &lf) {
TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_help_second_ok", "[load_filament]") { TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_help_second_ok", "[load_filament]") {
for (uint8_t slot = 0; slot < config::toolCount; ++slot) { for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
logic::LoadFilament lf; logic::LoadFilament lf;
LoadFilamentCommonSetup(slot, lf); LoadFilamentCommonSetup(slot, lf, false);
FailedLoadToFinda(slot, lf); FailedLoadToFinda(slot, lf);
FailedLoadToFindaResolveHelp(slot, lf); FailedLoadToFindaResolveHelp(slot, lf);
FailedLoadToFindaResolveHelpFindaTriggered(slot, lf); FailedLoadToFindaResolveHelpFindaTriggered(slot, lf);
@ -217,7 +222,7 @@ TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_help_second_ok", "[lo
TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_help_second_fail", "[load_filament]") { TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_help_second_fail", "[load_filament]") {
for (uint8_t slot = 0; slot < config::toolCount; ++slot) { for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
logic::LoadFilament lf; logic::LoadFilament lf;
LoadFilamentCommonSetup(slot, lf); LoadFilamentCommonSetup(slot, lf, false);
FailedLoadToFinda(slot, lf); FailedLoadToFinda(slot, lf);
FailedLoadToFindaResolveHelp(slot, lf); FailedLoadToFindaResolveHelp(slot, lf);
FailedLoadToFindaResolveHelpFindaDidntTrigger(slot, lf); FailedLoadToFindaResolveHelpFindaDidntTrigger(slot, lf);
@ -240,7 +245,7 @@ TEST_CASE("load_filament::state_machine_reusal", "[load_filament]") {
if (toSlot >= config::toolCount) { if (toSlot >= config::toolCount) {
InvalidSlot<logic::LoadFilament>(lf, fromSlot, toSlot); InvalidSlot<logic::LoadFilament>(lf, fromSlot, toSlot);
} else { } else {
LoadFilamentCommonSetup(toSlot, lf); LoadFilamentCommonSetup(toSlot, lf, false);
LoadFilamentSuccessful(toSlot, lf); LoadFilamentSuccessful(toSlot, lf);
} }
} }
@ -250,7 +255,7 @@ TEST_CASE("load_filament::state_machine_reusal", "[load_filament]") {
TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_manual", "[load_filament]") { TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_manual", "[load_filament]") {
for (uint8_t slot = 0; slot < config::toolCount; ++slot) { for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
logic::LoadFilament lf; logic::LoadFilament lf;
LoadFilamentCommonSetup(slot, lf); LoadFilamentCommonSetup(slot, lf, false);
FailedLoadToFinda(slot, lf); FailedLoadToFinda(slot, lf);
FailedLoadToFindaResolveManual(slot, lf); FailedLoadToFindaResolveManual(slot, lf);
} }
@ -259,7 +264,7 @@ TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_manual", "[load_filam
TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_manual_no_FINDA", "[load_filament]") { TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_manual_no_FINDA", "[load_filament]") {
for (uint8_t slot = 0; slot < config::toolCount; ++slot) { for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
logic::LoadFilament lf; logic::LoadFilament lf;
LoadFilamentCommonSetup(slot, lf); LoadFilamentCommonSetup(slot, lf, false);
FailedLoadToFinda(slot, lf); FailedLoadToFinda(slot, lf);
FailedLoadToFindaResolveManualNoFINDA(slot, lf); FailedLoadToFindaResolveManualNoFINDA(slot, lf);
} }
@ -268,7 +273,7 @@ TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_manual_no_FINDA", "[l
TEST_CASE("load_filament::failed_load_to_finda_0-4_try_again", "[load_filament]") { TEST_CASE("load_filament::failed_load_to_finda_0-4_try_again", "[load_filament]") {
for (uint8_t slot = 0; slot < config::toolCount; ++slot) { for (uint8_t slot = 0; slot < config::toolCount; ++slot) {
logic::LoadFilament lf; logic::LoadFilament lf;
LoadFilamentCommonSetup(slot, lf); LoadFilamentCommonSetup(slot, lf, false);
FailedLoadToFinda(slot, lf); FailedLoadToFinda(slot, lf);
FailedLoadToFindaResolveTryAgain(slot, lf); FailedLoadToFindaResolveTryAgain(slot, lf);
} }

View File

@ -10,9 +10,9 @@ Motion motion;
// Intentionally inited with strange values // Intentionally inited with strange values
// Need to call ReinitMotion() each time we start some unit test // Need to call ReinitMotion() each time we start some unit test
AxisSim axes[3] = { AxisSim axes[3] = {
{ -32767, -32767, false, false, false }, // pulley { -32767, false, false, false, {} }, // pulley
{ -32767, -32767, false, false, false }, // selector //@@TODO proper selector positions once defined { -32767, false, false, false, {} }, // selector //@@TODO proper selector positions once defined
{ -32767, -32767, false, false, false }, // idler { -32767, false, false, false, {} }, // idler
}; };
bool Motion::InitAxis(Axis axis) { bool Motion::InitAxis(Axis axis) {
@ -37,7 +37,7 @@ void TriggerStallGuard(Axis axis) {
} }
void Motion::PlanMoveTo(Axis axis, pos_t pos, steps_t feed_rate, steps_t end_rate) { void Motion::PlanMoveTo(Axis axis, pos_t pos, steps_t feed_rate, steps_t end_rate) {
axes[axis].targetPos = pos; axes[axis].plannedMoves.push_back(pos);
if (!axisData[axis].enabled) if (!axisData[axis].enabled)
SetEnabled(axis, true); SetEnabled(axis, true);
} }
@ -60,10 +60,15 @@ void Motion::SetMode(Axis axis, hal::tmc2130::MotorMode mode) {
st_timer_t Motion::Step() { st_timer_t Motion::Step() {
for (uint8_t i = 0; i < 3; ++i) { for (uint8_t i = 0; i < 3; ++i) {
if (axes[i].pos != axes[i].targetPos) { if (!axes[i].plannedMoves.empty()) {
int8_t dirInc = (axes[i].pos < axes[i].targetPos) ? 1 : -1; pos_t axisTargetPos = axes[i].plannedMoves.front();
axes[i].pos += dirInc; if (axes[i].pos != axisTargetPos) {
axisData[i].ctrl.SetPosition(axes[i].pos); int8_t dirInc = (axes[i].pos < axisTargetPos) ? 1 : -1;
axes[i].pos += dirInc;
axisData[i].ctrl.SetPosition(axes[i].pos);
} else if (!axes[i].plannedMoves.empty()) {
axes[i].plannedMoves.pop_front(); // one move completed, plan the next one
}
} }
} }
return 0; return 0;
@ -71,14 +76,18 @@ st_timer_t Motion::Step() {
bool Motion::QueueEmpty() const { bool Motion::QueueEmpty() const {
for (uint8_t i = 0; i < 3; ++i) { for (uint8_t i = 0; i < 3; ++i) {
if (axes[i].pos != axes[i].targetPos) if (!axes[i].plannedMoves.empty())
return false; return false;
} }
return true; return true;
} }
bool Motion::QueueEmpty(Axis axis) const { bool Motion::QueueEmpty(Axis axis) const {
return axes[axis].pos == axes[axis].targetPos; return axes[axis].plannedMoves.empty();
}
uint8_t Motion::PlannedMoves(Axis axis) const {
return axes[axis].plannedMoves.size();
} }
void Motion::AbortPlannedMoves(bool halt) { void Motion::AbortPlannedMoves(bool halt) {
@ -88,25 +97,31 @@ void Motion::AbortPlannedMoves(bool halt) {
} }
void Motion::AbortPlannedMoves(config::Axis i, bool) { void Motion::AbortPlannedMoves(config::Axis i, bool) {
axes[i].targetPos = axes[i].pos; // leave the axis where it was at the time of abort axes[i].plannedMoves.clear(); // leave the axis where it was at the time of abort
axisData[i].ctrl.SetPosition(axes[i].pos); axisData[i].ctrl.SetPosition(axes[i].pos);
} }
void ReinitMotion() { void ReinitMotion() {
// reset the simulation data to defaults // reset the simulation data to defaults
axes[0] = AxisSim({ 0, 0, false, false, false }); // pulley axes[0] = AxisSim({ 0, false, false, false, {} }); // pulley
axes[1] = AxisSim({ unitToSteps<S_pos_t>(config::selectorSlotPositions[0]), axes[1] = AxisSim({ unitToSteps<S_pos_t>(config::selectorSlotPositions[0]),
unitToSteps<S_pos_t>(config::selectorSlotPositions[0]), false, false, false, {} }); // selector
false, false, false }); // selector
axes[2] = AxisSim({ unitToSteps<I_pos_t>(config::idlerSlotPositions[mi::Idler::IdleSlotIndex()]), axes[2] = AxisSim({ unitToSteps<I_pos_t>(config::idlerSlotPositions[mi::Idler::IdleSlotIndex()]),
unitToSteps<I_pos_t>(config::idlerSlotPositions[mi::Idler::IdleSlotIndex()]), false, false, false, {} }); // idler
false, false, false }); // idler
} }
bool PulleyEnabled() { bool PulleyEnabled() {
return axes[0].enabled; return axes[0].enabled;
} }
pos_t AxisNearestTargetPos(Axis axis) {
if (axes[axis].plannedMoves.empty()) {
return axes[axis].pos;
} else {
return axes[axis].plannedMoves.front();
}
}
/// probably higher-level operations knowing the semantic meaning of axes /// probably higher-level operations knowing the semantic meaning of axes
} // namespace motion } // namespace motion

View File

@ -1,15 +1,16 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <deque>
namespace modules { namespace modules {
namespace motion { namespace motion {
struct AxisSim { struct AxisSim {
pos_t pos; pos_t pos;
pos_t targetPos;
bool enabled; bool enabled;
bool homed; bool homed;
bool stallGuard; bool stallGuard;
std::deque<pos_t> plannedMoves;
}; };
extern AxisSim axes[3]; extern AxisSim axes[3];
@ -17,6 +18,7 @@ extern AxisSim axes[3];
void ReinitMotion(); void ReinitMotion();
bool PulleyEnabled(); bool PulleyEnabled();
void TriggerStallGuard(Axis axis); void TriggerStallGuard(Axis axis);
pos_t AxisNearestTargetPos(Axis axis);
} // namespace motion } // namespace motion
} // namespace modules } // namespace modules

View File

@ -303,9 +303,11 @@ void FailedUnloadResolveManual(uint8_t slot, logic::UnloadFilament &uf) {
// we still need to feed to FINDA and back to verify the position of the filament // we still need to feed to FINDA and back to verify the position of the filament
SimulateIdlerHoming(uf); SimulateIdlerHoming(uf);
REQUIRE(WhileTopState(uf, ProgressCode::FeedingToFinda, 5000)); REQUIRE(WhileCondition(uf, std::bind(SimulateFeedToFINDA, _1, 100), 5000));
REQUIRE(WhileTopState(uf, ProgressCode::RetractingFromFinda, idlerEngageDisengageMaxSteps)); 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)); REQUIRE(VerifyState(uf, mg::FilamentLoadState::AtPulley, config::toolCount, config::toolCount, false, true, ml::off, ml::off, ErrorCode::RUNNING, ProgressCode::DisengagingIdler));
SimulateSelectorHoming(uf); SimulateSelectorHoming(uf);
@ -367,8 +369,13 @@ TEST_CASE("unload_filament::unload_homing_retry", "[unload_filament][homing]") {
hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low); hal::gpio::WritePin(FINDA_PIN, hal::gpio::Level::low);
PressButtonAndDebounce(uf, mb::Right); PressButtonAndDebounce(uf, mb::Right);
SimulateIdlerHoming(uf); // make Idler happy SimulateIdlerHoming(uf); // make Idler happy
REQUIRE(WhileTopState(uf, ProgressCode::FeedingToFinda, 5000));
REQUIRE(WhileTopState(uf, ProgressCode::RetractingFromFinda, idlerEngageDisengageMaxSteps)); 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)); REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, idlerEngageDisengageMaxSteps));
// now fail homing of the Selector // now fail homing of the Selector

View File

@ -44,8 +44,8 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") {
// it should have instructed the selector and idler to move to slot 1 // it should have instructed the selector and idler to move to slot 1
// check if the idler and selector have the right command // check if the idler and selector have the right command
CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Selector) == ms::Selector::SlotPosition(0).v);
// engaging idler // engaging idler
REQUIRE(WhileCondition( REQUIRE(WhileCondition(
@ -96,8 +96,8 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]")
// it should have instructed the selector and idler to move to slot 1 // it should have instructed the selector and idler to move to slot 1
// check if the idler and selector have the right command // check if the idler and selector have the right command
CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Selector) == ms::Selector::SlotPosition(0).v);
CHECK(mm::axes[mm::Idler].enabled == true); CHECK(mm::axes[mm::Idler].enabled == true);
// engaging idler // engaging idler
@ -137,8 +137,8 @@ TEST_CASE("unload_to_finda::unload_without_FSensor_trigger", "[unload_to_finda]"
// it should have instructed the selector and idler to move to slot 1 // it should have instructed the selector and idler to move to slot 1
// check if the idler and selector have the right command // check if the idler and selector have the right command
CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Idler) == mi::Idler::SlotPosition(0).v);
CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0).v); CHECK(mm::AxisNearestTargetPos(mm::Selector) == ms::Selector::SlotPosition(0).v);
CHECK(mm::axes[mm::Idler].enabled == true); CHECK(mm::axes[mm::Idler].enabled == true);
// engaging idler // engaging idler