Separate NoCommand and StartUp (new state machine)

The reasons for this change are:
- NoCommand is used during the lifetime of the firmware as a fallback in case an unknown command is received (simplifies command handling code). It must remain not doing anything.
- StartUp became a complex infrastructure which needs to "live" until an error is fixed (if any). That requires a "standard" StateInner() function which waits for the user to resolve the error.

Unit tests renamed as well.
pull/246/head
D.R.racer 2022-12-20 15:53:05 +01:00 committed by DRracer
parent 35344f5a5e
commit 98daf765af
21 changed files with 128 additions and 77 deletions

View File

@ -18,6 +18,7 @@
#include "logic/move_selector.h"
#include "logic/no_command.h"
#include "logic/set_mode.h"
#include "logic/start_up.h"
#include "logic/tool_change.h"
#include "logic/unload_filament.h"
@ -32,7 +33,7 @@ Application application;
Application::Application()
: lastCommandProcessedMs(0)
, currentCommand(&logic::noCommand)
, currentCommand(&logic::startUp)
, currentCommandRq(mp::RequestMsgCodes::Reset, 0) {}
void __attribute__((noinline)) Application::CheckManualOperation() {

View File

@ -12,6 +12,7 @@ target_sources(
no_command.cpp
retract_from_finda.cpp
set_mode.cpp
start_up.cpp
tool_change.cpp
unload_filament.cpp
unload_to_finda.cpp

View File

@ -1,46 +1,8 @@
/// @file no_command.cpp
#include "no_command.h"
#include "../modules/buttons.h"
#include "../modules/finda.h"
#include "../modules/user_input.h"
namespace logic {
NoCommand noCommand;
bool NoCommand::StepInner() {
switch (state) {
case ProgressCode::OK:
return true;
case ProgressCode::ERRWaitingForUser: {
// waiting for user buttons and/or a command from the printer
mui::Event ev = mui::userInput.ConsumeEvent();
switch (ev) {
case mui::Event::Middle:
switch (error) {
case ErrorCode::FINDA_VS_EEPROM_DISREPANCY:
// Retry
if (!mf::finda.CheckFINDAvsEEPROM()) {
error = ErrorCode::FINDA_VS_EEPROM_DISREPANCY;
state = ProgressCode::ERRWaitingForUser;
} else {
error = ErrorCode::OK;
state = ProgressCode::OK;
}
break;
default:
break;
}
break; // mui::Event::Middle
default:
break;
}
break; // ProgressCode::ERRWaitingForUser
}
default:
// Do nothing
break;
}
return false;
}
} // namespace logic

View File

@ -15,15 +15,12 @@ public:
bool Reset(uint8_t /*param*/) override { return true; }
/// @returns true if the state machine finished its job, false otherwise
bool StepInner() override;
bool StepInner() override { return true; }
/// Used to report initialization errors (which can be reported if the UART started up).
/// Intentionally only available in the "noCommand" operation
/// which is only active when the MMU starts and before it gets any other command from the printer.
inline void SetInitError(ErrorCode ec) {
error = ec;
state = ProgressCode::ERRWaitingForUser;
}
inline void SetInitError(ErrorCode ec) { error = ec; }
};
/// The one and only instance of NoCommand state machine in the FW

46
src/logic/start_up.cpp Normal file
View File

@ -0,0 +1,46 @@
/// @file
#include "start_up.h"
#include "../modules/buttons.h"
#include "../modules/finda.h"
#include "../modules/user_input.h"
namespace logic {
StartUp startUp;
bool StartUp::StepInner() {
switch (state) {
case ProgressCode::OK:
return true;
case ProgressCode::ERRWaitingForUser: {
// waiting for user buttons and/or a command from the printer
mui::Event ev = mui::userInput.ConsumeEvent();
switch (ev) {
case mui::Event::Middle:
switch (error) {
case ErrorCode::FINDA_VS_EEPROM_DISREPANCY:
// Retry
if (!mf::finda.CheckFINDAvsEEPROM()) {
error = ErrorCode::FINDA_VS_EEPROM_DISREPANCY;
state = ProgressCode::ERRWaitingForUser;
} else {
error = ErrorCode::OK;
state = ProgressCode::OK;
}
break;
default:
break;
}
break; // mui::Event::Middle
default:
break;
}
break; // ProgressCode::ERRWaitingForUser
}
default:
// Do nothing
break;
}
return false;
}
} // namespace logic

32
src/logic/start_up.h Normal file
View File

@ -0,0 +1,32 @@
/// @file no_command.h
#pragma once
#include <stdint.h>
#include "command_base.h"
namespace logic {
/// @brief Firmware start up sequence with error handling & reporting
class StartUp : public CommandBase {
public:
inline StartUp()
: CommandBase() {}
/// Restart the automaton
bool Reset(uint8_t /*param*/) override { return true; }
/// @returns true if the state machine finished its job, false otherwise
bool StepInner() override;
/// Used to report initialization errors (which can be reported if the UART started up).
/// Intentionally only available in the "noCommand" operation
/// which is only active when the MMU starts and before it gets any other command from the printer.
inline void SetInitError(ErrorCode ec) {
error = ec;
state = ProgressCode::ERRWaitingForUser;
}
};
/// The one and only instance of StartUp state machine in the FW
extern StartUp startUp;
} // namespace logic

View File

@ -28,7 +28,7 @@
#include "application.h"
#include "logic/hw_sanity.h"
#include "logic/no_command.h"
#include "logic/start_up.h"
/// One-time setup of HW and SW components
/// Called before entering the loop() function
@ -91,7 +91,7 @@ static void setup2() {
mf::finda.BlockingInit();
if (!mf::finda.CheckFINDAvsEEPROM()) {
logic::noCommand.SetInitError(ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
logic::startUp.SetInitError(ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
}
/// Turn off all leds
@ -110,7 +110,7 @@ static void setup2() {
if (logic::hwSanity.Error() != ErrorCode::OK) {
// forward the issue to the logic startup handler.
logic::noCommand.SetInitError(logic::hwSanity.Error());
logic::startUp.SetInitError(logic::hwSanity.Error());
} else {
// Idler and Selector decide whether homing is possible/safe
mi::idler.Init();

View File

@ -39,6 +39,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp

View File

@ -12,7 +12,7 @@ add_subdirectory(eject_filament)
add_subdirectory(load_filament)
add_subdirectory(no_command)
add_subdirectory(start_up)
add_subdirectory(tool_change)

View File

@ -14,6 +14,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp

View File

@ -14,6 +14,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp

View File

@ -14,6 +14,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp

View File

@ -14,6 +14,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp

View File

@ -14,6 +14,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp

View File

@ -14,6 +14,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp

View File

@ -15,6 +15,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp

View File

@ -1,6 +1,6 @@
# define the test executable
add_executable(
no_command_tests
start_up_tests
${CMAKE_SOURCE_DIR}/src/application.cpp
${CMAKE_SOURCE_DIR}/src/registers.cpp
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
@ -14,6 +14,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp
@ -42,14 +43,14 @@ add_executable(
${LOGIC_STUBS_DIR}/homing.cpp
${LOGIC_STUBS_DIR}/main_loop_stub.cpp
${LOGIC_STUBS_DIR}/stub_motion.cpp
test_no_command.cpp
test_start_up.cpp
)
# define required search paths
target_include_directories(
no_command_tests PUBLIC "${CMAKE_SOURCE_DIR}/src/modules" "${CMAKE_SOURCE_DIR}/src/hal"
start_up_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(no_command_tests)
add_catch_test(start_up_tests)

View File

@ -12,7 +12,7 @@
#include "../../../../src/modules/pulley.h"
#include "../../../../src/modules/user_input.h"
#include "../../../../src/logic/no_command.h"
#include "../../../../src/logic/start_up.h"
#include "../../modules/stubs/stub_adc.h"
@ -23,30 +23,30 @@
#include "../helpers/helpers.ipp"
TEST_CASE("no_command::SetInitError", "[no_command]") {
logic::NoCommand nc;
logic::StartUp su;
// Step 1 - Check there are no errors
REQUIRE(nc.Error() == ErrorCode::OK);
REQUIRE(nc.State() == ProgressCode::OK);
REQUIRE(su.Error() == ErrorCode::OK);
REQUIRE(su.State() == ProgressCode::OK);
// Step 2 - Create error
nc.SetInitError(ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
su.SetInitError(ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
// Step 3 - Check error is waiting for user input
REQUIRE(nc.Error() == ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
REQUIRE(nc.State() == ProgressCode::ERRWaitingForUser);
REQUIRE(su.Error() == ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
REQUIRE(su.State() == ProgressCode::ERRWaitingForUser);
// Step 4 - Loop through a few iterations, error remains unchanged
for (size_t i = 0; i < 100; ++i) {
nc.Step();
su.Step();
}
REQUIRE(nc.Error() == ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
REQUIRE(nc.State() == ProgressCode::ERRWaitingForUser);
REQUIRE(su.Error() == ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
REQUIRE(su.State() == ProgressCode::ERRWaitingForUser);
}
TEST_CASE("no_command::FINDA_VS_EEPROM_DISREPANCY_retry", "[no_command]") {
logic::NoCommand nc;
logic::StartUp su;
// Initalise the ADC
hal::adc::SetADC(config::buttonsADCIndex, config::buttonADCMaxValue);
@ -56,33 +56,33 @@ TEST_CASE("no_command::FINDA_VS_EEPROM_DISREPANCY_retry", "[no_command]") {
SetFINDAStateAndDebounce(true);
// Step 1 - Check there are no errors
REQUIRE(nc.Error() == ErrorCode::OK);
REQUIRE(nc.State() == ProgressCode::OK);
REQUIRE(su.Error() == ErrorCode::OK);
REQUIRE(su.State() == ProgressCode::OK);
// Step 2 - Create error
nc.SetInitError(ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
su.SetInitError(ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
// Step 3 - Check error is waiting for user input
REQUIRE(nc.Error() == ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
REQUIRE(nc.State() == ProgressCode::ERRWaitingForUser);
REQUIRE(su.Error() == ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
REQUIRE(su.State() == ProgressCode::ERRWaitingForUser);
// Step 4 - Press and release button (from Printer)
PressButtonAndDebounce(nc, mb::Middle, true);
ClearButtons(nc);
PressButtonAndDebounce(su, mb::Middle, true);
ClearButtons(su);
// Check that the error is still present
REQUIRE(nc.Error() == ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
REQUIRE(nc.State() == ProgressCode::ERRWaitingForUser);
REQUIRE(su.Error() == ErrorCode::FINDA_VS_EEPROM_DISREPANCY);
REQUIRE(su.State() == ProgressCode::ERRWaitingForUser);
// Untrigger FINDA and FSensor
SetFSensorStateAndDebounce(false);
SetFINDAStateAndDebounce(false);
// Step 4 - Press and release button
PressButtonAndDebounce(nc, mb::Middle, true);
ClearButtons(nc);
PressButtonAndDebounce(su, mb::Middle, true);
ClearButtons(su);
// Now the error should be gone :)
REQUIRE(nc.Error() == ErrorCode::OK);
REQUIRE(nc.State() == ProgressCode::OK);
REQUIRE(su.Error() == ErrorCode::OK);
REQUIRE(su.State() == ProgressCode::OK);
}

View File

@ -15,6 +15,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp

View File

@ -14,6 +14,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp

View File

@ -14,6 +14,7 @@ add_executable(
${CMAKE_SOURCE_DIR}/src/logic/no_command.cpp
${CMAKE_SOURCE_DIR}/src/logic/retract_from_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/set_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/start_up.cpp
${CMAKE_SOURCE_DIR}/src/logic/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp