diff --git a/src/modules/finda.h b/src/modules/finda.h index b54a4f7..fc74779 100644 --- a/src/modules/finda.h +++ b/src/modules/finda.h @@ -7,7 +7,7 @@ namespace finda { class FINDA : protected debounce::Debouncer { public: - inline FINDA() + inline constexpr FINDA() : debounce::Debouncer(debounce) {}; void Step(uint16_t time); using debounce::Debouncer::Pressed; diff --git a/src/modules/fsensor.h b/src/modules/fsensor.h index f62fa9e..6cee4bb 100644 --- a/src/modules/fsensor.h +++ b/src/modules/fsensor.h @@ -11,8 +11,9 @@ namespace fsensor { class FSensor : protected debounce::Debouncer { public: - inline FSensor() - : debounce::Debouncer(debounce) {}; + inline constexpr FSensor() + : debounce::Debouncer(debounce) + , reportedFSensorState(false) {}; void Step(uint16_t time); using debounce::Debouncer::Pressed; diff --git a/src/modules/idler.h b/src/modules/idler.h index a2b77f4..58000b8 100644 --- a/src/modules/idler.h +++ b/src/modules/idler.h @@ -11,12 +11,12 @@ namespace idler { class Idler { public: enum { - Ready = 0, + Ready = 0, // intentionally set as zero in order to allow zeroing the Idler structure upon startup -> avoid explicit initialization code Moving, Failed }; - inline Idler() + inline constexpr Idler() : state(Ready) , plannedEngage(false) , plannedSlot(0) diff --git a/src/modules/motion.h b/src/modules/motion.h index 865742b..208f701 100644 --- a/src/modules/motion.h +++ b/src/modules/motion.h @@ -61,6 +61,8 @@ public: /// @@TODO this is subject of discussion and change in the future class Motion { public: + inline constexpr Motion() = default; + /// Init axis driver - @@TODO this should be probably hidden somewhere deeper ... something should manage the axes and their state /// especially when the TMC may get randomly reset (deinited) void InitAxis(Axis axis); diff --git a/src/modules/selector.h b/src/modules/selector.h index 7ec09a6..c48f2b6 100644 --- a/src/modules/selector.h +++ b/src/modules/selector.h @@ -16,7 +16,7 @@ public: Failed }; - inline Selector() + inline constexpr Selector() : state(Ready) , plannedSlot(0) , currentSlot(0) {} 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 27b6555..dca5729 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 @@ -31,17 +31,7 @@ bool WhileCondition(logic::FeedToFinda &ff, COND cond, uint32_t maxLoops = 5000) TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") { using namespace logic; - // no buttons involved ;) - hal::adc::TADCData noButtons({ 0 }); - hal::adc::ReinitADC(0, std::move(noButtons), 1); - - // finda OFF - hal::adc::TADCData findaOFF({ 0 }); - hal::adc::ReinitADC(1, std::move(findaOFF), 1); - - // let's assume we have the filament NOT loaded and active slot 0 - modules::globals::globals.SetFilamentLoaded(false); - modules::globals::globals.SetActiveSlot(0); + ForceReinitAllAutomata(); FeedToFinda ff; main_loop(); @@ -103,20 +93,7 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") { TEST_CASE("feed_to_finda::FINDA_failed", "[feed_to_finda]") { using namespace logic; - // This is a problem - how to reset all the state machines at once? - // May be add an #ifdef unit_tests and a reset function for each of the automatons - - // no buttons involved ;) - hal::adc::TADCData noButtons({ 0 }); - hal::adc::ReinitADC(0, std::move(noButtons), 1); - - // finda OFF - hal::adc::TADCData findaOFF({ 0 }); - hal::adc::ReinitADC(1, std::move(findaOFF), 1); - - // let's assume we have the filament NOT loaded and active slot 0 - modules::globals::globals.SetFilamentLoaded(false); - modules::globals::globals.SetActiveSlot(0); + ForceReinitAllAutomata(); FeedToFinda ff; main_loop(); diff --git a/tests/unit/logic/stubs/main_loop_stub.cpp b/tests/unit/logic/stubs/main_loop_stub.cpp index b35118d..cc56a14 100644 --- a/tests/unit/logic/stubs/main_loop_stub.cpp +++ b/tests/unit/logic/stubs/main_loop_stub.cpp @@ -1,4 +1,7 @@ #include "main_loop_stub.h" + +#include "../../modules/stubs/stub_adc.h" + #include "../../../../src/modules/buttons.h" #include "../../../../src/modules/finda.h" #include "../../../../src/modules/fsensor.h" @@ -9,6 +12,8 @@ #include "../../../../src/modules/permanent_storage.h" #include "../../../../src/modules/selector.h" +#include // bring in placement new + logic::CommandBase *currentCommand = nullptr; // just like in the real FW, step all the known automata @@ -26,3 +31,34 @@ void main_loop() { currentCommand->Step(); ++tmpTiming; } + +void ForceReinitAllAutomata() { + // This woodoo magic with placement new is just a forced reinit of global instances of firmware's state machines + // just for the purposes of separate unit tests. Each unit test needs a "freshly booted firmware" and since all unit tests + // in the test binary share the same global data structures, we need some way of making them fresh each time. + // + // This approach mimics the firmware behavior closely as the firmware initializes its global data structures + // on its very start once (by copying static init data from PROGMEM into RAM) - and we need exactly this approach in the unit tests. + // + // There are multiple other approaches, one of them is adding a special Init() function into each of these state machines. + // As this approach might look like a standard and safer way of doing stuff, it has several drawbacks, especially + // it needs an explicit call to the Init function every time an object like this is created - this can have negative influence on firmware's code size + + new (&modules::buttons::buttons) modules::buttons::Buttons(); + new (&modules::leds::leds) modules::leds::LEDs(); + new (&modules::finda::finda) modules::finda::FINDA(); + new (&modules::fsensor::fsensor) modules::fsensor::FSensor(); + new (&modules::idler::idler) modules::idler::Idler(); + new (&modules::selector::selector) modules::selector::Selector(); + new (&modules::motion::motion) modules::motion::Motion(); + + // no buttons involved ;) + hal::adc::ReinitADC(0, hal::adc::TADCData({ 0 }), 1); + + // finda OFF + hal::adc::ReinitADC(1, hal::adc::TADCData({ 0 }), 1); + + // 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 3392d83..a30b66e 100644 --- a/tests/unit/logic/stubs/main_loop_stub.h +++ b/tests/unit/logic/stubs/main_loop_stub.h @@ -2,5 +2,6 @@ #include "../../../../src/logic/command_base.h" extern void main_loop(); +extern void ForceReinitAllAutomata(); extern logic::CommandBase *currentCommand;