Fix setup/FINDA init state

It turned out FINDA needs running timer to perform BlockingInit() correctly.
Therefore setup() was split into setup() (no IRQ) and setup2() (IRQ enabled).

Then, finally, the check for FINDA state became reliable upon start of the FW.
pull/179/head
D.R.racer 2022-06-09 16:16:17 +02:00 committed by DRracer
parent 7ae9c9019c
commit de8a2f35ae
9 changed files with 60 additions and 8 deletions

View File

@ -175,6 +175,8 @@ ProgressCode ToolChange::State() const {
return ProgressCode::FeedingToFSensor; return ProgressCode::FeedingToFSensor;
case FeedToBondtech::PushingFilamentIntoNozzle: case FeedToBondtech::PushingFilamentIntoNozzle:
return ProgressCode::FeedingToNozzle; return ProgressCode::FeedingToNozzle;
case FeedToBondtech::DisengagingIdler:
return ProgressCode::DisengagingIdler;
} }
// [[fallthrough]] // everything else is reported as FeedingToBondtech // [[fallthrough]] // everything else is reported as FeedingToBondtech
default: default:

View File

@ -32,7 +32,8 @@
/// One-time setup of HW and SW components /// One-time setup of HW and SW components
/// Called before entering the loop() function /// Called before entering the loop() function
/// Green LEDs signalize the progress of initialization. If anything goes wrong we shall turn on a red LED /// Green LEDs signalize the progress of initialization. If anything goes wrong we shall turn on a red LED
void setup() { /// Executed with interrupts disabled
static void setup() {
hal::cpu::Init(); hal::cpu::Init();
mt::timebase.Init(); mt::timebase.Init();
@ -80,7 +81,10 @@ void setup() {
ml::leds.Step(); ml::leds.Step();
mu::cdc.Init(); mu::cdc.Init();
}
/// Second part of setup - executed with interrupts enabled
static void setup2() {
// waits at least finda debounce period // waits at least finda debounce period
// which is abused to let the LEDs shine for ~100ms // which is abused to let the LEDs shine for ~100ms
mf::finda.BlockingInit(); mf::finda.BlockingInit();
@ -93,9 +97,7 @@ void setup() {
// Ideally this should be signalled as an error state and displayed on the printer and recovered properly. // Ideally this should be signalled as an error state and displayed on the printer and recovered properly.
mg::globals.SetFilamentLoaded(2, mg::InFSensor); mg::globals.SetFilamentLoaded(2, mg::InFSensor);
logic::noCommand.SetInitError(ErrorCode::FINDA_VS_EEPROM_DISREPANCY); logic::noCommand.SetInitError(ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
} } else if (!mf::finda.Pressed() && mg::globals.FilamentLoaded() >= mg::InSelector) {
if (!mf::finda.Pressed() && mg::globals.FilamentLoaded() >= mg::InSelector) {
// Opposite situation - not so dangerous, but definitely confusing to users. // Opposite situation - not so dangerous, but definitely confusing to users.
// FINDA is not pressed but we have a record in the EEPROM. // FINDA is not pressed but we have a record in the EEPROM.
// It has been decided, that we shall clear such a record from EEPROM automagically // It has been decided, that we shall clear such a record from EEPROM automagically
@ -158,6 +160,7 @@ void loop() {
int main() { int main() {
setup(); setup();
sei(); ///enable interrupts sei(); ///enable interrupts
setup2();
for (;;) { for (;;) {
loop(); loop();
} }

View File

@ -14,10 +14,10 @@ void FINDA::Step() {
} }
void FINDA::BlockingInit() { void FINDA::BlockingInit() {
auto tgtMs = mt::timebase.Millis() + config::findaDebounceMs + 1; uint16_t start = mt::timebase.Millis();
Step(); // let FINDA settle down - we're gonna need its state for selector homing // let FINDA settle down - we're gonna need its state for selector homing
while (tgtMs < mt::timebase.Millis()) { while (!mt::timebase.Elapsed(start, config::findaDebounceMs + 1)) {
mf::finda.Step(); Step();
} }
} }

View File

@ -20,6 +20,12 @@ void Timebase::Isr() {
ms++; ms++;
} }
bool Timebase::Elapsed(uint16_t start, uint16_t timeout) const {
uint16_t ms_from_start = Millis(); // beware the uint16_t!
ms_from_start -= start;
return ms_from_start > timeout;
}
uint16_t Timebase::Millis() const { uint16_t Timebase::Millis() const {
return ms; return ms;
} }

View File

@ -24,6 +24,10 @@ public:
void Isr(); void Isr();
/// @returns true if the timeout elapsed from the start
/// handles correctly timer counter overflows
bool Elapsed(uint16_t start, uint16_t timeout) const;
private: private:
uint16_t ms; uint16_t ms;
}; };

View File

@ -4,3 +4,4 @@ add_subdirectory(protocol)
add_subdirectory(speed_table) add_subdirectory(speed_table)
add_subdirectory(pulse_gen) add_subdirectory(pulse_gen)
add_subdirectory(motion) add_subdirectory(motion)
add_subdirectory(timebase)

View File

@ -24,5 +24,11 @@ void IncMillis(uint16_t inc /* = 1*/) {
millis += inc; millis += inc;
} }
bool Timebase::Elapsed(uint16_t start, uint16_t timeout) const {
uint16_t ms_from_start = Millis(); // beware the uint16_t!
ms_from_start -= start;
return ms_from_start > timeout;
}
} // namespace time } // namespace time
} // namespace modules } // namespace modules

View File

@ -0,0 +1,8 @@
# define the test executable
add_executable(timebase_tests ${MODULES_STUBS_DIR}/stub_timebase.cpp test_timebase.cpp)
# define required search paths
target_include_directories(timebase_tests PUBLIC ${CMAKE_SOURCE_DIR}/src/modules)
# tell build system about the test case
add_catch_test(timebase_tests)

View File

@ -0,0 +1,22 @@
#include "catch2/catch.hpp"
#include "timebase.h"
#include "../stubs/stub_timebase.h"
using Catch::Matchers::Equals;
// this is not a pure test of the real implementation (it would require splitting the timebase.cpp into 2 parts)
// but serves the sole purpose of debugging the Elapsed() impl.
TEST_CASE("timebase::Elapsed", "[timebase]") {
{
mt::ReinitTimebase(0);
uint16_t start = mt::timebase.Millis();
mt::IncMillis(5);
REQUIRE(mt::timebase.Elapsed(start, 4));
}
{
mt::ReinitTimebase(0xffff);
uint16_t start = mt::timebase.Millis();
mt::IncMillis(5);
REQUIRE(mt::timebase.Elapsed(start, 4));
}
}