From ce20f0b001966a72de07a65bc01a93f6a42d6311 Mon Sep 17 00:00:00 2001 From: "D.R.racer" Date: Tue, 22 Jun 2021 21:47:39 +0200 Subject: [PATCH] Greatly improve unload filament unit test + relevant changes for other unit tests -> prepare for improving of the other unit tests as well --- src/logic/tool_change.cpp | 57 ++++-- src/logic/tool_change.h | 4 + src/logic/unload_filament.cpp | 10 +- src/logic/unload_filament.h | 3 +- src/modules/debouncer.cpp | 2 +- src/modules/finda.h | 11 +- .../logic/cut_filament/test_cut_filament.cpp | 22 +- .../eject_filament/test_eject_filament.cpp | 15 +- .../test_feed_to_bondtech.cpp | 137 ++++--------- .../feed_to_finda/test_feed_to_finda.cpp | 23 +-- .../load_filament/test_load_filament.cpp | 2 +- tests/unit/logic/stubs/main_loop_stub.cpp | 10 +- tests/unit/logic/stubs/main_loop_stub.h | 15 +- tests/unit/logic/stubs/stub_motion.cpp | 16 +- tests/unit/logic/stubs/stub_motion.h | 2 + .../logic/tool_change/test_tool_change.cpp | 19 +- .../unload_filament/test_unload_filament.cpp | 192 ++++++++++++++++-- .../unload_to_finda/test_unload_to_finda.cpp | 31 ++- tests/unit/modules/stubs/stub_adc.cpp | 4 + tests/unit/modules/stubs/stub_adc.h | 4 + 20 files changed, 354 insertions(+), 225 deletions(-) diff --git a/src/logic/tool_change.cpp b/src/logic/tool_change.cpp index ad565ac..b06bf15 100644 --- a/src/logic/tool_change.cpp +++ b/src/logic/tool_change.cpp @@ -12,9 +12,6 @@ namespace logic { ToolChange toolChange; -namespace mm = modules::motion; -namespace mi = modules::idler; -namespace ms = modules::selector; namespace mg = modules::globals; void ToolChange::Reset(uint8_t param) { @@ -36,35 +33,51 @@ bool ToolChange::Step() { switch (state) { case ProgressCode::UnloadingFilament: if (unl.Step()) { - // unloading sequence finished - switch (unl.Error()) { - case ErrorCode::OK: // finished successfully - state = ProgressCode::LoadingFilament; - load.Reset(plannedSlot); - break; - case ErrorCode::UNLOAD_ERROR2: // @@TODO what shall we do in case of this error? - case ErrorCode::FINDA_DIDNT_TRIGGER: - break; - } + // unloading sequence finished - basically, no errors can occurr here + // as UnloadFilament should handle all the possible error states on its own + // There is no way the UnloadFilament to finish in an error state + state = ProgressCode::LoadingFilament; + load.Reset(plannedSlot); } break; case ProgressCode::LoadingFilament: if (load.Step()) { - // unloading sequence finished - switch (load.Error()) { - case ErrorCode::OK: // finished successfully - state = ProgressCode::OK; - break; - // case ErrorCode::LOAD_ERROR2: // @@TODO load errors? - // case ErrorCode::LOAD_FINDA_DIDNT_TRIGGER: - break; - } + // loading sequence finished - basically, no errors can occurr here + // as LoadFilament should handle all the possible error states on its own + // There is no way the LoadFilament to finish in an error state + state = ProgressCode::OK; } break; case ProgressCode::OK: return true; + default: // we got into an unhandled state, better report it + state = ProgressCode::ERRInternal; + error = ErrorCode::INTERNAL; + return true; } return false; } +ProgressCode ToolChange::State() const { + switch (state) { + case ProgressCode::UnloadingFilament: + return unl.State(); // report sub-automaton states properly + case ProgressCode::LoadingFilament: + return load.State(); // report sub-automaton states properly + default: + return state; + } +} + +ErrorCode ToolChange::Error() const { + switch (state) { + case ProgressCode::UnloadingFilament: + return unl.Error(); // report sub-automaton errors properly + case ProgressCode::LoadingFilament: + return load.Error(); // report sub-automaton errors properly + default: + return error; + } +} + } // namespace logic diff --git a/src/logic/tool_change.h b/src/logic/tool_change.h index 2453a73..d346d64 100644 --- a/src/logic/tool_change.h +++ b/src/logic/tool_change.h @@ -19,6 +19,10 @@ public: /// @returns true if the state machine finished its job, false otherwise bool Step() override; + ProgressCode State() const override; + + ErrorCode Error() const override; + private: UnloadFilament unl; ///< a high-level command/operation may be used as a building block of other operations as well LoadFilament load; diff --git a/src/logic/unload_filament.cpp b/src/logic/unload_filament.cpp index 16a4c22..1c31a12 100644 --- a/src/logic/unload_filament.cpp +++ b/src/logic/unload_filament.cpp @@ -17,12 +17,14 @@ namespace mi = modules::idler; namespace ml = modules::leds; namespace mg = modules::globals; -void UnloadFilament::Reset(uint8_t param) { +void UnloadFilament::Reset(uint8_t /*param*/) { // unloads filament from extruder - filament is above Bondtech gears mm::motion.InitAxis(mm::Pulley); state = ProgressCode::UnloadingToFinda; error = ErrorCode::OK; unl.Reset(maxRetries); + ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::blink0); + ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::off); } bool UnloadFilament::Step() { @@ -33,7 +35,9 @@ bool UnloadFilament::Step() { if (unl.State() == UnloadToFinda::Failed) { // couldn't unload to FINDA, report error and wait for user to resolve it state = ProgressCode::ERR1DisengagingIdler; + error = ErrorCode::FINDA_DIDNT_TRIGGER; ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::blink0); + ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off); } else { state = ProgressCode::DisengagingIdler; } @@ -59,10 +63,11 @@ bool UnloadFilament::Step() { if (mm::motion.QueueEmpty()) { state = ProgressCode::OK; mm::motion.DisableAxis(mm::Pulley); + mg::globals.SetFilamentLoaded(false); // filament unloaded + ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::on); } return false; case ProgressCode::ERR1DisengagingIdler: // couldn't unload to FINDA - error = ErrorCode::FINDA_DIDNT_TRIGGER; if (!mi::idler.Engaged()) { state = ProgressCode::ERR1WaitingForUser; } @@ -88,7 +93,6 @@ bool UnloadFilament::Step() { return false; } case ProgressCode::OK: - mg::globals.SetFilamentLoaded(false); // filament unloaded return true; // successfully finished default: // we got into an unhandled state, better report it state = ProgressCode::ERRInternal; diff --git a/src/logic/unload_filament.h b/src/logic/unload_filament.h index 5be0964..7381059 100644 --- a/src/logic/unload_filament.h +++ b/src/logic/unload_filament.h @@ -13,7 +13,8 @@ public: : CommandBase() {} /// Restart the automaton - void Reset(uint8_t param) override; + /// @param param is not used, always unloads from the active slot + void Reset(uint8_t /*param*/) override; /// @returns true if the state machine finished its job, false otherwise bool Step() override; diff --git a/src/modules/debouncer.cpp b/src/modules/debouncer.cpp index eaffd0a..3c54d9b 100644 --- a/src/modules/debouncer.cpp +++ b/src/modules/debouncer.cpp @@ -15,7 +15,7 @@ void Debouncer::Step(uint16_t time, bool press) { break; case State::Detected: if (f.tmp == press) { - if (time - timeLastChange > debounceTimeout) { + if (time - timeLastChange >= debounceTimeout) { f.state = State::WaitForRelease; } } else { diff --git a/src/modules/finda.h b/src/modules/finda.h index f2815b1..535da1f 100644 --- a/src/modules/finda.h +++ b/src/modules/finda.h @@ -7,16 +7,15 @@ namespace finda { class FINDA : protected debounce::Debouncer { public: - inline constexpr FINDA() - : debounce::Debouncer(debounce) {}; - void Step(); - using debounce::Debouncer::Pressed; - -private: /// time interval for debouncing @@TODO specify units constexpr static const uint16_t debounce = 100; /// ADC decision level when a FINDA is considered pressed/not pressed constexpr static const uint16_t adcDecisionLevel = 512; + + inline constexpr FINDA() + : debounce::Debouncer(debounce) {}; + void Step(); + using debounce::Debouncer::Pressed; }; extern FINDA finda; diff --git a/tests/unit/logic/cut_filament/test_cut_filament.cpp b/tests/unit/logic/cut_filament/test_cut_filament.cpp index 5bf70f9..ffe465a 100644 --- a/tests/unit/logic/cut_filament/test_cut_filament.cpp +++ b/tests/unit/logic/cut_filament/test_cut_filament.cpp @@ -34,7 +34,6 @@ TEST_CASE("cut_filament::cut0", "[cut_filament]") { CutFilament cf; // restart the automaton - currentCommand = &cf; cf.Reset(0); main_loop(); @@ -45,7 +44,7 @@ TEST_CASE("cut_filament::cut0", "[cut_filament]") { CHECK(modules::motion::axes[modules::motion::Selector].targetPos == ms::Selector::SlotPosition(0)); // 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 cf.TopLevelState() == ProgressCode::SelectingFilamentSlot; }, 5000)); + REQUIRE(WhileTopState(cf, ProgressCode::SelectingFilamentSlot, 5000)); CHECK(modules::motion::axes[modules::motion::Idler].pos == mi::Idler::SlotPosition(0)); CHECK(modules::motion::axes[modules::motion::Selector].pos == ms::Selector::SlotPosition(0)); @@ -53,27 +52,32 @@ TEST_CASE("cut_filament::cut0", "[cut_filament]") { // idler and selector reached their target positions and the CF automaton will start feeding to FINDA as the next step REQUIRE(cf.TopLevelState() == 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 cf.TopLevelState() == ProgressCode::FeedingToFinda; }, 5000)); + REQUIRE(WhileCondition( + cf, + [&](int step) -> bool { + if( step == 1000 ){ // simulate FINDA trigger - will get pressed in 100 steps (due to debouncing) + hal::adc::SetADC(1, 900); + } + return cf.TopLevelState() == ProgressCode::FeedingToFinda; }, 5000)); // filament fed into FINDA, cutting... REQUIRE(cf.TopLevelState() == ProgressCode::PreparingBlade); - REQUIRE(WhileCondition([&]() { return cf.TopLevelState() == ProgressCode::PreparingBlade; }, 5000)); + REQUIRE(WhileTopState(cf, ProgressCode::PreparingBlade, 5000)); REQUIRE(cf.TopLevelState() == ProgressCode::EngagingIdler); - REQUIRE(WhileCondition([&]() { return cf.TopLevelState() == ProgressCode::EngagingIdler; }, 5000)); + REQUIRE(WhileTopState(cf, ProgressCode::EngagingIdler, 5000)); // the idler should be at the active slot @@TODO REQUIRE(cf.TopLevelState() == ProgressCode::PushingFilament); - REQUIRE(WhileCondition([&]() { return cf.TopLevelState() == ProgressCode::PushingFilament; }, 5000)); + REQUIRE(WhileTopState(cf, ProgressCode::PushingFilament, 5000)); // filament pushed - performing cut REQUIRE(cf.TopLevelState() == ProgressCode::PerformingCut); - REQUIRE(WhileCondition([&]() { return cf.TopLevelState() == ProgressCode::PerformingCut; }, 5000)); + REQUIRE(WhileTopState(cf, ProgressCode::PerformingCut, 5000)); // returning selector REQUIRE(cf.TopLevelState() == ProgressCode::ReturningSelector); - REQUIRE(WhileCondition([&]() { return cf.TopLevelState() == ProgressCode::ReturningSelector; }, 5000)); + REQUIRE(WhileTopState(cf, ProgressCode::ReturningSelector, 5000)); // the next states are still @@TODO } diff --git a/tests/unit/logic/eject_filament/test_eject_filament.cpp b/tests/unit/logic/eject_filament/test_eject_filament.cpp index e1d9f1d..8810923 100644 --- a/tests/unit/logic/eject_filament/test_eject_filament.cpp +++ b/tests/unit/logic/eject_filament/test_eject_filament.cpp @@ -34,7 +34,6 @@ TEST_CASE("eject_filament::eject0", "[eject_filament]") { EjectFilament ef; // restart the automaton - currentCommand = &ef; ef.Reset(0); main_loop(); @@ -45,32 +44,32 @@ TEST_CASE("eject_filament::eject0", "[eject_filament]") { CHECK(modules::motion::axes[modules::motion::Selector].targetPos == ms::Selector::SlotPosition(4)); // 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.TopLevelState() == ProgressCode::SelectingFilamentSlot; }, 5000)); + REQUIRE(WhileTopState(ef, 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.TopLevelState() == 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.TopLevelState() == ProgressCode::FeedingToFinda; }, 50000)); + REQUIRE(WhileTopState(ef, ProgressCode::FeedingToFinda, 50000)); // filament fed into FINDA, cutting... REQUIRE(ef.TopLevelState() == ProgressCode::PreparingBlade); - REQUIRE(WhileCondition([&]() { return ef.TopLevelState() == ProgressCode::PreparingBlade; }, 5000)); + REQUIRE(WhileTopState(ef, ProgressCode::PreparingBlade, 5000)); REQUIRE(ef.TopLevelState() == ProgressCode::EngagingIdler); - REQUIRE(WhileCondition([&]() { return ef.TopLevelState() == ProgressCode::EngagingIdler; }, 5000)); + REQUIRE(WhileTopState(ef, ProgressCode::EngagingIdler, 5000)); // the idler should be at the active slot @@TODO REQUIRE(ef.TopLevelState() == ProgressCode::PushingFilament); - REQUIRE(WhileCondition([&]() { return ef.TopLevelState() == ProgressCode::PushingFilament; }, 5000)); + REQUIRE(WhileTopState(ef, ProgressCode::PushingFilament, 5000)); // filament pushed - performing cut REQUIRE(ef.TopLevelState() == ProgressCode::PerformingCut); - REQUIRE(WhileCondition([&]() { return ef.TopLevelState() == ProgressCode::PerformingCut; }, 5000)); + REQUIRE(WhileTopState(ef, ProgressCode::PerformingCut, 5000)); // returning selector REQUIRE(ef.TopLevelState() == ProgressCode::ReturningSelector); - REQUIRE(WhileCondition([&]() { return ef.TopLevelState() == ProgressCode::ReturningSelector; }, 5000)); + REQUIRE(WhileTopState(ef, ProgressCode::ReturningSelector, 5000)); // the next states are still @@TODO } diff --git a/tests/unit/logic/feed_to_bondtech/test_feed_to_bondtech.cpp b/tests/unit/logic/feed_to_bondtech/test_feed_to_bondtech.cpp index edd02eb..0f77ff0 100644 --- a/tests/unit/logic/feed_to_bondtech/test_feed_to_bondtech.cpp +++ b/tests/unit/logic/feed_to_bondtech/test_feed_to_bondtech.cpp @@ -29,15 +29,6 @@ namespace ms = modules::selector; namespace ha = hal::adc; -template -bool WhileCondition(logic::FeedToBondtech &ff, COND cond, uint32_t maxLoops = 5000) { - while (cond() && --maxLoops) { - main_loop(); - ff.Step(); - } - return maxLoops > 0; -} - TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") { using namespace logic; @@ -47,108 +38,50 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") { main_loop(); // restart the automaton - fb.Reset(false); + fb.Reset(1); - // REQUIRE(ff.State() == FeedToBondtech::EngagingIdler); + REQUIRE(fb.State() == FeedToBondtech::EngagingIdler); - // // it should have instructed the selector and idler to move to slot 1 - // // check if the idler and selector have the right command - // CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0)); - // CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0)); - // CHECK(mm::axes[mm::Idler].enabled == true); + // it should have instructed the selector and idler to move to slot 0 + // check if the idler and selector have the right command + CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0)); + CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0)); + CHECK(mm::axes[mm::Idler].enabled == true); - // // engaging idler - // REQUIRE(WhileCondition( - // ff, - // [&]() { return !mi::idler.Engaged(); }, - // 5000)); + // engaging idler + REQUIRE(WhileCondition( + fb, + [&](int) { return !mi::idler.Engaged(); }, + 5000)); - // CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(0)); - // CHECK(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(0)); + CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(0)); + CHECK(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(0)); - // // idler engaged, selector in position, we'll start pushing filament - // REQUIRE(ff.State() == FeedToBondtech::PushingFilament); - // // at least at the beginning the LED should shine green (it should be blinking, but this mode has been already verified in the LED's unit test) - // REQUIRE(ml::leds.LedOn(mg::globals.ActiveSlot(), ml::Color::green)); + // idler engaged, selector in position, we'll start pushing filament + REQUIRE(fb.State() == FeedToBondtech::PushingFilament); + // at least at the beginning the LED should shine green (it should be blinking, but this mode has been already verified in the LED's unit test) + REQUIRE(ml::leds.LedOn(mg::globals.ActiveSlot(), ml::Color::green)); - // // now let the filament be pushed into the FINDA - do 500 steps without triggering the condition - // // and then let the simulated ADC channel 1 create a FINDA switch - // ha::ReinitADC(1, ha::TADCData({ 600, 700, 800, 900 }), 1); + // @@TODO simulate incoming message from the printer - fsensor triggered - // REQUIRE(WhileCondition( - // ff, - // [&]() { return ff.State() == FeedToBondtech::PushingFilament; }, - // 1500)); - // // From now on the FINDA is reported as ON + REQUIRE(WhileCondition( + fb, + [&](int) { return fb.State() == FeedToBondtech::PushingFilament; }, + 1500)); - // // unloading back to PTFE - // REQUIRE(ff.State() == FeedToBondtech::UnloadBackToPTFE); - // REQUIRE(WhileCondition( - // ff, - // [&]() { return ff.State() == FeedToBondtech::UnloadBackToPTFE; }, - // 5000)); + // disengaging idler + REQUIRE(fb.State() == FeedToBondtech::DisengagingIdler); + REQUIRE(WhileCondition( + fb, + [&](int) { return fb.State() == FeedToBondtech::DisengagingIdler; }, + 5000)); - // // disengaging idler - // REQUIRE(ff.State() == FeedToBondtech::DisengagingIdler); - // REQUIRE(WhileCondition( - // ff, - // [&]() { return mi::idler.Engaged(); }, - // 5000)); + CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // @@TODO constants + CHECK(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(0)); - // CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // @@TODO constants - // CHECK(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(0)); + // state machine finished ok, the green LED should be on + REQUIRE(fb.State() == FeedToBondtech::OK); + REQUIRE(ml::leds.LedOn(mg::globals.ActiveSlot(), ml::Color::green)); - // // state machine finished ok, the green LED should be on - // REQUIRE(ff.State() == FeedToBondtech::OK); - // REQUIRE(ml::leds.LedOn(mg::globals.ActiveSlot(), ml::Color::green)); - - // REQUIRE(ff.Step() == true); // the automaton finished its work, any consecutive calls to Step must return true - //} - - //TEST_CASE("feed_to_finda::FINDA_failed", "[feed_to_finda]") { - // using namespace logic; - - // ForceReinitAllAutomata(); - - // FeedToBondtech ff; - // main_loop(); - - // // restart the automaton - we want the limited version of the feed - // ff.Reset(true); - - // REQUIRE(ff.State() == FeedToBondtech::EngagingIdler); - - // // it should have instructed the selector and idler to move to slot 1 - // // check if the idler and selector have the right command - // CHECK(mm::axes[mm::Idler].targetPos == mi::Idler::SlotPosition(0)); - // CHECK(mm::axes[mm::Selector].targetPos == ms::Selector::SlotPosition(0)); - - // // engaging idler - // REQUIRE(WhileCondition( - // ff, - // [&]() { return !mi::idler.Engaged(); }, - // 5000)); - - // CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(0)); - // CHECK(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(0)); - - // // idler engaged, we'll start pushing filament - // REQUIRE(ff.State() == FeedToBondtech::PushingFilament); - // // 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::Color::green) == ml::blink0); - - // // now let the filament be pushed into the FINDA - but we make sure the FINDA doesn't trigger at all - // ha::ReinitADC(1, ha::TADCData({ 0 }), 100); - - // REQUIRE(WhileCondition( - // ff, // boo, this formatting is UGLY! - // [&]() { return ff.State() == FeedToBondtech::PushingFilament; }, - // 5000)); - - // // the FINDA didn't trigger, we should be in the Failed state - // REQUIRE(ff.State() == FeedToBondtech::Failed); - // REQUIRE(ml::leds.Mode(mg::globals.ActiveSlot(), ml::Color::green) == ml::off); - // REQUIRE(ml::leds.Mode(mg::globals.ActiveSlot(), ml::Color::red) == ml::blink0); - - // REQUIRE(ff.Step() == true); // the automaton finished its work, any consecutive calls to Step must return true + REQUIRE(fb.Step() == true); // the automaton finished its work, any consecutive calls to Step must return true } diff --git a/tests/unit/logic/feed_to_finda/test_feed_to_finda.cpp b/tests/unit/logic/feed_to_finda/test_feed_to_finda.cpp index 7bbeacf..5e14c7d 100644 --- a/tests/unit/logic/feed_to_finda/test_feed_to_finda.cpp +++ b/tests/unit/logic/feed_to_finda/test_feed_to_finda.cpp @@ -29,15 +29,6 @@ namespace ms = modules::selector; namespace ha = hal::adc; -template -bool WhileCondition(logic::FeedToFinda &ff, COND cond, uint32_t maxLoops = 5000) { - while (cond() && --maxLoops) { - main_loop(); - ff.Step(); - } - return maxLoops > 0; -} - TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") { using namespace logic; @@ -60,7 +51,7 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") { // engaging idler REQUIRE(WhileCondition( ff, - [&]() { return !mi::idler.Engaged(); }, + [&](int) { return !mi::idler.Engaged(); }, 5000)); CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(0)); @@ -77,7 +68,7 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") { REQUIRE(WhileCondition( ff, - [&]() { return ff.State() == FeedToFinda::PushingFilament; }, + [&](int) { return ff.State() == FeedToFinda::PushingFilament; }, 1500)); // From now on the FINDA is reported as ON @@ -85,14 +76,14 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") { REQUIRE(ff.State() == FeedToFinda::UnloadBackToPTFE); REQUIRE(WhileCondition( ff, - [&]() { return ff.State() == FeedToFinda::UnloadBackToPTFE; }, + [&](int) { return ff.State() == FeedToFinda::UnloadBackToPTFE; }, 5000)); // disengaging idler REQUIRE(ff.State() == FeedToFinda::DisengagingIdler); REQUIRE(WhileCondition( ff, - [&]() { return mi::idler.Engaged(); }, + [&](int) { return mi::idler.Engaged(); }, 5000)); CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // @@TODO constants @@ -126,7 +117,7 @@ TEST_CASE("feed_to_finda::FINDA_failed", "[feed_to_finda]") { // engaging idler REQUIRE(WhileCondition( ff, - [&]() { return !mi::idler.Engaged(); }, + [&](int) { return !mi::idler.Engaged(); }, 5000)); CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(0)); @@ -141,8 +132,8 @@ TEST_CASE("feed_to_finda::FINDA_failed", "[feed_to_finda]") { ha::ReinitADC(1, ha::TADCData({ 0 }), 100); REQUIRE(WhileCondition( - ff, // boo, this formatting is UGLY! - [&]() { return ff.State() == FeedToFinda::PushingFilament; }, + ff, + [&](int) { return ff.State() == FeedToFinda::PushingFilament; }, 5000)); // the FINDA didn't trigger, we should be in the Failed state diff --git a/tests/unit/logic/load_filament/test_load_filament.cpp b/tests/unit/logic/load_filament/test_load_filament.cpp index 4e65f52..304c127 100644 --- a/tests/unit/logic/load_filament/test_load_filament.cpp +++ b/tests/unit/logic/load_filament/test_load_filament.cpp @@ -34,7 +34,6 @@ TEST_CASE("unload_filament::unload0", "[unload_filament]") { LoadFilament lf; // restart the automaton - currentCommand = &lf; lf.Reset(0); main_loop(); @@ -53,4 +52,5 @@ TEST_CASE("unload_filament::unload0", "[unload_filament]") { // REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::FinishingMoves; }, 5000)); // REQUIRE(uf.TopLevelState() == ProgressCode::OK); + REQUIRE(modules::globals::globals.FilamentLoaded() == true); } diff --git a/tests/unit/logic/stubs/main_loop_stub.cpp b/tests/unit/logic/stubs/main_loop_stub.cpp index e3eaed2..d115b47 100644 --- a/tests/unit/logic/stubs/main_loop_stub.cpp +++ b/tests/unit/logic/stubs/main_loop_stub.cpp @@ -13,9 +13,9 @@ #include "../../../../src/modules/permanent_storage.h" #include "../../../../src/modules/selector.h" -#include // bring in placement new +#include "../stubs/stub_motion.h" -logic::CommandBase *currentCommand = nullptr; +#include // bring in placement new void main_loop() { modules::buttons::buttons.Step(); @@ -25,8 +25,6 @@ void main_loop() { modules::idler::idler.Step(); modules::selector::selector.Step(); modules::motion::motion.Step(); - if (currentCommand) - currentCommand->Step(); modules::time::IncMillis(); } @@ -57,8 +55,12 @@ void ForceReinitAllAutomata() { // finda OFF hal::adc::ReinitADC(1, hal::adc::TADCData({ 0 }), 1); + // reinit timing modules::time::ReinitTimebase(); + // reinit axes positions + modules::motion::ReinitMotion(); + // let's assume we have the filament NOT loaded and active slot 0 modules::globals::globals.SetFilamentLoaded(false); modules::globals::globals.SetActiveSlot(0); diff --git a/tests/unit/logic/stubs/main_loop_stub.h b/tests/unit/logic/stubs/main_loop_stub.h index 7078078..a22d664 100644 --- a/tests/unit/logic/stubs/main_loop_stub.h +++ b/tests/unit/logic/stubs/main_loop_stub.h @@ -4,12 +4,17 @@ extern void main_loop(); extern void ForceReinitAllAutomata(); -extern logic::CommandBase *currentCommand; - -template -bool WhileCondition(COND cond, uint32_t maxLoops = 5000) { - while (cond() && --maxLoops) { +template +bool WhileCondition(SM &sm, COND cond, uint32_t maxLoops = 5000) { + while (cond(maxLoops) && --maxLoops) { main_loop(); + sm.Step(); } return maxLoops > 0; } + +template +bool WhileTopState(SM &sm, ProgressCode state, uint32_t maxLoops = 5000) { + return WhileCondition( + sm, [&](int) { return sm.TopLevelState() == state; }, maxLoops); +} diff --git a/tests/unit/logic/stubs/stub_motion.cpp b/tests/unit/logic/stubs/stub_motion.cpp index 8df9a38..07e5d50 100644 --- a/tests/unit/logic/stubs/stub_motion.cpp +++ b/tests/unit/logic/stubs/stub_motion.cpp @@ -5,10 +5,13 @@ namespace modules { namespace motion { Motion motion; + +// Intentionally inited with strange values +// Need to call ReinitMotion() each time we start some unit test AxisSim axes[3] = { - { 0, 0, false, false, false }, // pulley - { 1, 1, false, false, false }, // selector //@@TODO proper selector positions once defined - { 0, 0, false, false, false }, // idler + { -32767, -32767, false, false, false }, // pulley + { -32767, -32767, false, false, false }, // selector //@@TODO proper selector positions once defined + { -32767, -32767, false, false, false }, // idler }; void Motion::InitAxis(Axis axis) { @@ -72,6 +75,13 @@ void Motion::AbortPlannedMoves() { } } +void ReinitMotion() { + // reset the simulation data to defaults + axes[0] = AxisSim({ 0, 0, false, false, false }); // pulley + axes[1] = AxisSim({ 1, 1, false, false, false }); // selector //@@TODO proper selector positions once defined + axes[2] = AxisSim({ 0, 0, false, false, false }); // idler +} + /// probably higher-level operations knowing the semantic meaning of axes } // namespace motion diff --git a/tests/unit/logic/stubs/stub_motion.h b/tests/unit/logic/stubs/stub_motion.h index 528b69c..bc1a814 100644 --- a/tests/unit/logic/stubs/stub_motion.h +++ b/tests/unit/logic/stubs/stub_motion.h @@ -14,5 +14,7 @@ struct AxisSim { extern AxisSim axes[3]; +extern void ReinitMotion(); + } // namespace motion } // namespace modules diff --git a/tests/unit/logic/tool_change/test_tool_change.cpp b/tests/unit/logic/tool_change/test_tool_change.cpp index cdc8e8d..e7c585a 100644 --- a/tests/unit/logic/tool_change/test_tool_change.cpp +++ b/tests/unit/logic/tool_change/test_tool_change.cpp @@ -34,23 +34,16 @@ TEST_CASE("tool_change::test0", "[tool_change]") { ToolChange tc; // restart the automaton - currentCommand = &tc; tc.Reset(0); main_loop(); - // REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::UnloadingToFinda; }, 5000)); + REQUIRE(WhileTopState(tc, ProgressCode::UnloadingFilament, 5000)); + REQUIRE(modules::globals::globals.FilamentLoaded() == false); - // REQUIRE(uf.TopLevelState() == ProgressCode::DisengagingIdler); - // REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::DisengagingIdler; }, 5000)); + REQUIRE(tc.TopLevelState() == ProgressCode::LoadingFilament); + REQUIRE(WhileTopState(tc, ProgressCode::LoadingFilament, 5000)); - // CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); - - // REQUIRE(uf.TopLevelState() == ProgressCode::AvoidingGrind); - // REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::AvoidingGrind; }, 5000)); - - // REQUIRE(uf.TopLevelState() == ProgressCode::FinishingMoves); - // REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::FinishingMoves; }, 5000)); - - // REQUIRE(uf.TopLevelState() == ProgressCode::OK); + REQUIRE(tc.TopLevelState() == ProgressCode::OK); + REQUIRE(modules::globals::globals.FilamentLoaded() == true); } diff --git a/tests/unit/logic/unload_filament/test_unload_filament.cpp b/tests/unit/logic/unload_filament/test_unload_filament.cpp index b581b8c..ecd7a78 100644 --- a/tests/unit/logic/unload_filament/test_unload_filament.cpp +++ b/tests/unit/logic/unload_filament/test_unload_filament.cpp @@ -27,30 +27,198 @@ namespace mb = modules::buttons; namespace mg = modules::globals; namespace ms = modules::selector; -TEST_CASE("unload_filament::unload0", "[unload_filament]") { - using namespace logic; - +void RegularUnloadFromSlot04(uint8_t slot) { + // prepare startup conditions ForceReinitAllAutomata(); - UnloadFilament uf; + // change the startup to what we need here + // move selector to the right spot + ms::selector.MoveToSlot(slot); + while (ms::selector.Slot() != slot) + main_loop(); + + mg::globals.SetActiveSlot(slot); + mg::globals.SetFilamentLoaded(true); + + // set FINDA ON + debounce + hal::adc::SetADC(1, mf::FINDA::adcDecisionLevel + 1); + for (size_t i = 0; i < mf::FINDA::debounce + 1; ++i) + main_loop(); + + // verify startup conditions + REQUIRE(mg::globals.FilamentLoaded() == true); + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); + REQUIRE(!mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == true); + // restart the automaton - currentCommand = &uf; - uf.Reset(0); + logic::UnloadFilament uf; + uf.Reset(slot); - main_loop(); + // Stage 0 - verify state just after Reset() + REQUIRE(mg::globals.FilamentLoaded() == true); // we still think we have filament loaded at this stage + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // idler should have been activated by the underlying automaton + REQUIRE(!mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); // no change in selector's position + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == true); // FINDA triggered off + REQUIRE(ml::leds.Mode(slot, ml::green) == ml::blink0); // green LED should blink + REQUIRE(uf.Error() == ErrorCode::OK); // no error so far - REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::UnloadingToFinda; }, 5000)); + // run the automaton + // Stage 1 - unloading to FINDA + REQUIRE(WhileCondition( + uf, + [&](int step) -> bool { + if(step == 100){ // on 100th step make FINDA trigger + hal::adc::SetADC(1, 0); + } + return uf.TopLevelState() == ProgressCode::UnloadingToFinda; }, + 5000)); + REQUIRE(mg::globals.FilamentLoaded() == true); // we still think we have filament loaded at this stage + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(slot)); // idler should have been activated by the underlying automaton + REQUIRE(mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); // no change in selector's position + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == false); // FINDA triggered off + REQUIRE(ml::leds.Mode(slot, ml::green) == ml::blink0); // green LED should blink + REQUIRE(uf.Error() == ErrorCode::OK); // no error so far + + // Stage 2 - idler was engaged, disengage it REQUIRE(uf.TopLevelState() == ProgressCode::DisengagingIdler); - REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::DisengagingIdler; }, 5000)); + REQUIRE(WhileTopState(uf, ProgressCode::DisengagingIdler, 5000)); - CHECK(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); + REQUIRE(mg::globals.FilamentLoaded() == true); // we still think we have filament loaded at this stage + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // idler should have been disengaged + REQUIRE(!mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); // no change in selector's position + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == false); // FINDA still triggered off + REQUIRE(ml::leds.Mode(slot, ml::green) == ml::blink0); // green LED should blink + REQUIRE(uf.Error() == ErrorCode::OK); // no error so far + // Stage 3 - avoiding grind (whatever is that @@TODO) REQUIRE(uf.TopLevelState() == ProgressCode::AvoidingGrind); - REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::AvoidingGrind; }, 5000)); + REQUIRE(WhileTopState(uf, ProgressCode::AvoidingGrind, 5000)); + REQUIRE(mg::globals.FilamentLoaded() == true); // we still think we have filament loaded at this stage + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // idler should have been disengaged + REQUIRE(!mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); // no change in selector's position + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == false); // FINDA still triggered off + REQUIRE(ml::leds.Mode(slot, ml::green) == ml::blink0); // green LED should blink + REQUIRE(uf.Error() == ErrorCode::OK); // no error so far + + // Stage 4 - finishing moves and setting global state correctly REQUIRE(uf.TopLevelState() == ProgressCode::FinishingMoves); - REQUIRE(WhileCondition([&]() { return uf.TopLevelState() == ProgressCode::FinishingMoves; }, 5000)); + REQUIRE(WhileTopState(uf, ProgressCode::FinishingMoves, 5000)); + REQUIRE(mg::globals.FilamentLoaded() == false); // filament unloaded + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // idler should have been disengaged + REQUIRE(!mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); // no change in selector's position + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == false); // FINDA still triggered off + REQUIRE(ml::leds.Mode(slot, ml::green) == ml::on); // green LED should be ON + REQUIRE(uf.Error() == ErrorCode::OK); // no error so far + + // Stage 5 - repeated calls to TopLevelState should return "OK" REQUIRE(uf.TopLevelState() == ProgressCode::OK); + REQUIRE(mg::globals.FilamentLoaded() == false); + 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 < 5; ++slot) { + RegularUnloadFromSlot04(slot); + } +} + +void FindaDidntTrigger(uint8_t slot) { + // prepare startup conditions + ForceReinitAllAutomata(); + + // change the startup to what we need here + + // move selector to the right spot + ms::selector.MoveToSlot(slot); + while (ms::selector.Slot() != slot) + main_loop(); + + // set FINDA ON + debounce + hal::adc::SetADC(1, mf::FINDA::adcDecisionLevel + 1); + for (size_t i = 0; i < mf::FINDA::debounce + 1; ++i) + main_loop(); + + mg::globals.SetActiveSlot(slot); + mg::globals.SetFilamentLoaded(true); + + // verify startup conditions + REQUIRE(mg::globals.FilamentLoaded() == true); + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); + REQUIRE(!mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == true); + + // restart the automaton + logic::UnloadFilament uf; + uf.Reset(slot); + + // Stage 0 - verify state just after Reset() + REQUIRE(mg::globals.FilamentLoaded() == true); // we still think we have filament loaded at this stage + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // idler should have been activated by the underlying automaton + REQUIRE(!mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); // no change in selector's position + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == true); // FINDA triggered off + REQUIRE(ml::leds.Mode(slot, ml::green) == ml::blink0); // green LED should blink + REQUIRE(uf.Error() == ErrorCode::OK); // no error so far + + // 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(WhileTopState(uf, ProgressCode::UnloadingToFinda, 50000)); + + REQUIRE(mg::globals.FilamentLoaded() == true); // we still think we have filament loaded at this stage + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(slot)); // idler should have been activated by the underlying automaton + REQUIRE(mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); // no change in selector's position + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == true); // FINDA still on + REQUIRE(ml::leds.Mode(slot, ml::red) == ml::blink0); // red LED should blink + REQUIRE(ml::leds.Mode(slot, ml::green) == ml::off); // green LED should be off + REQUIRE(uf.Error() == ErrorCode::FINDA_DIDNT_TRIGGER); // didn't get any response from FINDA + REQUIRE(uf.TopLevelState() == ProgressCode::ERR1DisengagingIdler); + + // Stage 2 - idler should get disengaged + REQUIRE(WhileTopState(uf, ProgressCode::ERR1DisengagingIdler, 5000)); + + REQUIRE(mg::globals.FilamentLoaded() == true); // we still think we have filament loaded at this stage + REQUIRE(mm::axes[mm::Idler].pos == mi::Idler::SlotPosition(5)); // idler should have been disengaged + REQUIRE(!mi::idler.Engaged()); + REQUIRE(mm::axes[mm::Selector].pos == ms::Selector::SlotPosition(slot)); // no change in selector's position + REQUIRE(ms::selector.Slot() == slot); + REQUIRE(mf::finda.Pressed() == true); // FINDA still on + REQUIRE(ml::leds.Mode(slot, ml::red) == ml::blink0); // red LED should blink + REQUIRE(ml::leds.Mode(slot, ml::green) == ml::off); // green LED should be off + REQUIRE(uf.Error() == ErrorCode::FINDA_DIDNT_TRIGGER); + REQUIRE(uf.TopLevelState() == ProgressCode::ERR1WaitingForUser); + + // 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? +} + +TEST_CASE("unload_filament::finda_didnt_trigger", "[unload_filament]") { + for (uint8_t slot = 0; slot < 5; ++slot) { + FindaDidntTrigger(slot); + } } diff --git a/tests/unit/logic/unload_to_finda/test_unload_to_finda.cpp b/tests/unit/logic/unload_to_finda/test_unload_to_finda.cpp index 24f50ca..b5d8c9f 100644 --- a/tests/unit/logic/unload_to_finda/test_unload_to_finda.cpp +++ b/tests/unit/logic/unload_to_finda/test_unload_to_finda.cpp @@ -29,15 +29,6 @@ namespace ms = modules::selector; namespace ha = hal::adc; -template -bool WhileConditionFF(logic::UnloadToFinda &ff, COND cond, uint32_t maxLoops = 5000) { - while (cond() && --maxLoops) { - main_loop(); - ff.Step(); - } - return maxLoops > 0; -} - TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") { using namespace logic; @@ -50,7 +41,8 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") { // wait for FINDA to debounce REQUIRE(WhileCondition( - [&]() { return !mf::finda.Pressed(); }, + ff, + [&](int) { return !mf::finda.Pressed(); }, 5000)); // restart the automaton - just 1 attempt @@ -65,17 +57,17 @@ TEST_CASE("unload_to_finda::regular_unload", "[unload_to_finda]") { CHECK(mm::axes[mm::Idler].enabled == true); // engaging idler - REQUIRE(WhileConditionFF( + REQUIRE(WhileCondition( ff, - [&]() { return !mi::idler.Engaged(); }, + [&](int) { return !mi::idler.Engaged(); }, 5000)); // now pulling the filament until finda triggers REQUIRE(ff.State() == UnloadToFinda::WaitingForFINDA); hal::adc::ReinitADC(1, hal::adc::TADCData({ 1023, 900, 800, 500, 0 }), 10); - REQUIRE(WhileConditionFF( + REQUIRE(WhileCondition( ff, - [&]() { return mf::finda.Pressed(); }, + [&](int) { return mf::finda.Pressed(); }, 50000)); REQUIRE(ff.State() == UnloadToFinda::OK); @@ -108,7 +100,8 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]") // wait for FINDA to debounce REQUIRE(WhileCondition( - [&]() { return !mf::finda.Pressed(); }, + ff, + [&](int) { return !mf::finda.Pressed(); }, 5000)); // restart the automaton - just 1 attempt @@ -123,18 +116,18 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]") CHECK(mm::axes[mm::Idler].enabled == true); // engaging idler - REQUIRE(WhileConditionFF( + REQUIRE(WhileCondition( ff, - [&]() { return !mi::idler.Engaged(); }, + [&](int) { return !mi::idler.Engaged(); }, 5000)); // now pulling the filament until finda triggers REQUIRE(ff.State() == UnloadToFinda::WaitingForFINDA); // no changes to FINDA during unload - we'll pretend it never triggers - REQUIRE(!WhileConditionFF( + REQUIRE(!WhileCondition( ff, - [&]() { return mf::finda.Pressed(); }, + [&](int) { return mf::finda.Pressed(); }, 50000)); REQUIRE(ff.State() == UnloadToFinda::Failed); diff --git a/tests/unit/modules/stubs/stub_adc.cpp b/tests/unit/modules/stubs/stub_adc.cpp index 36921b4..e50aa7a 100644 --- a/tests/unit/modules/stubs/stub_adc.cpp +++ b/tests/unit/modules/stubs/stub_adc.cpp @@ -29,5 +29,9 @@ uint16_t ReadADC(uint8_t adc) { return rdptr[adc] != values2Return[adc].end() ? *rdptr[adc] : values2Return[adc].back(); } +void SetADC(uint8_t channel, uint16_t value) { + ReinitADC(channel, TADCData({ value }), 1); +} + } // namespace adc } // namespace hal diff --git a/tests/unit/modules/stubs/stub_adc.h b/tests/unit/modules/stubs/stub_adc.h index 2e2f360..16f6ee0 100644 --- a/tests/unit/modules/stubs/stub_adc.h +++ b/tests/unit/modules/stubs/stub_adc.h @@ -8,7 +8,11 @@ namespace adc { using TADCData = std::vector; +/// plan a vector of ADC values for the next steps void ReinitADC(uint8_t channel, TADCData &&d, uint8_t ovsmpl); +/// set ADC value on a channel to some fixed value from now on +void SetADC(uint8_t channel, uint16_t value); + } // namespace adc } // namespace hal