From 161e46b09a93aedaee8c8ff1334ed4d626a83724 Mon Sep 17 00:00:00 2001 From: "D.R.racer" Date: Fri, 27 Aug 2021 16:54:32 +0200 Subject: [PATCH] Add unit tests for failing TMC more stuff will follow as these situations seem to cause various issues --- src/hal/tmc2130.h | 8 ++ tests/unit/logic/CMakeLists.txt | 2 + tests/unit/logic/failing_tmc/CMakeLists.txt | 38 +++++++++ .../logic/failing_tmc/test_failing_tmc.cpp | 85 +++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 tests/unit/logic/failing_tmc/CMakeLists.txt create mode 100644 tests/unit/logic/failing_tmc/test_failing_tmc.cpp diff --git a/src/hal/tmc2130.h b/src/hal/tmc2130.h index 68af305..9c8ac5f 100644 --- a/src/hal/tmc2130.h +++ b/src/hal/tmc2130.h @@ -126,6 +126,14 @@ public: return errorFlags; } +#ifdef UNITTEST + /// A very brutal way of fiddling with the error flags from the outside of this class + /// Intended only for the UNIT TESTS! + inline void SetErrorFlags(ErrorFlags ef) { + errorFlags = ef; + } +#endif + /// Reads a driver register and updates the status flags uint32_t ReadRegister(const MotorParams ¶ms, Registers reg); diff --git a/tests/unit/logic/CMakeLists.txt b/tests/unit/logic/CMakeLists.txt index 48def39..ae20670 100644 --- a/tests/unit/logic/CMakeLists.txt +++ b/tests/unit/logic/CMakeLists.txt @@ -13,3 +13,5 @@ add_subdirectory(load_filament) add_subdirectory(tool_change) add_subdirectory(unload_filament) + +add_subdirectory(failing_tmc) diff --git a/tests/unit/logic/failing_tmc/CMakeLists.txt b/tests/unit/logic/failing_tmc/CMakeLists.txt new file mode 100644 index 0000000..8967899 --- /dev/null +++ b/tests/unit/logic/failing_tmc/CMakeLists.txt @@ -0,0 +1,38 @@ +# define the test executable +add_executable( + failing_tmc_tests + ${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp + ${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp + ${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp + ${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp + ${CMAKE_SOURCE_DIR}/src/modules/buttons.cpp + ${CMAKE_SOURCE_DIR}/src/modules/debouncer.cpp + ${CMAKE_SOURCE_DIR}/src/modules/finda.cpp + ${CMAKE_SOURCE_DIR}/src/modules/fsensor.cpp + ${CMAKE_SOURCE_DIR}/src/modules/globals.cpp + ${CMAKE_SOURCE_DIR}/src/modules/idler.cpp + ${CMAKE_SOURCE_DIR}/src/modules/leds.cpp + ${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp + ${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp + ${CMAKE_SOURCE_DIR}/src/modules/selector.cpp + ${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp + ${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp + ${MODULES_STUBS_DIR}/stub_adc.cpp + ${MODULES_STUBS_DIR}/stub_eeprom.cpp + ${MODULES_STUBS_DIR}/stub_gpio.cpp + ${MODULES_STUBS_DIR}/stub_shr16.cpp + ${MODULES_STUBS_DIR}/stub_timebase.cpp + ${MODULES_STUBS_DIR}/stub_tmc2130.cpp + ${LOGIC_STUBS_DIR}/main_loop_stub.cpp + ${LOGIC_STUBS_DIR}/stub_motion.cpp + test_failing_tmc.cpp + ) + +# define required search paths +target_include_directories( + failing_tmc_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(failing_tmc_tests) diff --git a/tests/unit/logic/failing_tmc/test_failing_tmc.cpp b/tests/unit/logic/failing_tmc/test_failing_tmc.cpp new file mode 100644 index 0000000..7afceb3 --- /dev/null +++ b/tests/unit/logic/failing_tmc/test_failing_tmc.cpp @@ -0,0 +1,85 @@ +// This test checks reporting errors while some logic operation is in progress +// As a base for this test, unload_filament was chosen. +// Moreover, I didn't want to spoil the unit tests of the state machines themself with this. + +#include "catch2/catch.hpp" + +#include "../../../../src/modules/buttons.h" +#include "../../../../src/modules/finda.h" +#include "../../../../src/modules/fsensor.h" +#include "../../../../src/modules/globals.h" +#include "../../../../src/modules/idler.h" +#include "../../../../src/modules/leds.h" +#include "../../../../src/modules/motion.h" +#include "../../../../src/modules/permanent_storage.h" +#include "../../../../src/modules/selector.h" + +#include "../../../../src/logic/unload_filament.h" + +#include "../../modules/stubs/stub_adc.h" + +#include "../stubs/main_loop_stub.h" +#include "../stubs/stub_motion.h" + +using Catch::Matchers::Equals; + +#include "../helpers/helpers.ipp" + +void CauseTMCError(mm::Axis axis, hal::tmc2130::ErrorFlags ef) { + hal::tmc2130::TMC2130 &tmc = const_cast(mm::motion.DriverForAxis(axis)); + tmc.SetErrorFlags(ef); +} + +inline ErrorCode operator|(ErrorCode a, ErrorCode b) { + return (ErrorCode)((uint16_t)a | (uint16_t)b); +} + +void FailingIdler(hal::tmc2130::ErrorFlags ef, ErrorCode ec) { + // prepare startup conditions + ForceReinitAllAutomata(); + + // change the startup to what we need here + EnsureActiveSlotIndex(0); + + mg::globals.SetFilamentLoaded(true); + + // set FINDA ON + debounce + SetFINDAStateAndDebounce(true); + + logic::UnloadFilament uf; + + // verify startup conditions + REQUIRE(VerifyState(uf, true, mi::Idler::IdleSlotIndex(), 0, true, ml::off, ml::off, ErrorCode::OK, ProgressCode::OK)); + + // UnloadFilament starts by engaging the idler (through the UnloadToFinda state machine) + uf.Reset(0); + + REQUIRE(VerifyState(uf, true, mi::Idler::IdleSlotIndex(), 0, true, ml::blink0, ml::off, ErrorCode::RUNNING, ProgressCode::UnloadingToFinda)); + + REQUIRE(WhileCondition( + uf, + [&](int step) -> bool { + if(step == 5){ // on 5th step make the TMC report some error + CauseTMCError(mm::Idler, ef); + } + return uf.TopLevelState() == ProgressCode::UnloadingToFinda; }, + 5000)); + + // and this must cause the state machine to run into a TMC error state and report the error correctly + // Please note we are leaving the Idler in an intermediate position due to the TMC failure, + // so we cannot use the usual VerifyState(), but have to check the stuff manually + // REQUIRE(VerifyState(uf, true, raw_6, 0, false, ml::blink0, ml::blink0, ec, ProgressCode::ERRTMCFailed)); + REQUIRE(mm::axes[mm::Idler].pos == 6); + REQUIRE(ml::leds.Mode(0, ml::red) == ml::off); + REQUIRE(ml::leds.Mode(0, ml::green) == ml::blink0); + REQUIRE(uf.Error() == ec); + REQUIRE(uf.TopLevelState() == ProgressCode::ERRTMCFailed); + + // repeated calls to step this logic automaton shall produce no change +} + +TEST_CASE("failing_tmc::failing_idler", "[failing_tmc]") { + hal::tmc2130::ErrorFlags ef; + ef.ot = 1; // make the TMC hot like hell + FailingIdler(ef, ErrorCode::TMC_OVER_TEMPERATURE_ERROR | ErrorCode::TMC_IDLER_BIT); +}