Add unit tests for failing TMC

more stuff will follow as these situations seem to cause various issues
pull/112/head
D.R.racer 2021-08-27 16:54:32 +02:00 committed by DRracer
parent 1d884d9099
commit 161e46b09a
4 changed files with 133 additions and 0 deletions

View File

@ -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 &params, Registers reg);

View File

@ -13,3 +13,5 @@ add_subdirectory(load_filament)
add_subdirectory(tool_change)
add_subdirectory(unload_filament)
add_subdirectory(failing_tmc)

View File

@ -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)

View File

@ -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<hal::tmc2130::TMC2130 &>(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);
}