Detect successful end of logic::command + start idle countdown

This commit looks horribly complex, but the main idea is to have each of the logic::commands
report their terminal OK state in the same way. That allow for leveraging this very moment
to initiate the idle timeout.

Additionally, I wanted to hide the logic of idle mode detection, which resulted in moving the
top level logic from main.cpp into logic/idle_mode.cpp and a set of additional files to compile
in unit tests.
pull/165/head
D.R.racer 2022-05-06 12:42:06 +02:00 committed by DRracer
parent 1f061405f6
commit ff1a89d369
36 changed files with 606 additions and 320 deletions

View File

@ -6,6 +6,7 @@ target_sources(
feed_to_bondtech.cpp
feed_to_finda.cpp
home.cpp
idle_mode.cpp
load_filament.cpp
move_selector.cpp
no_command.cpp

View File

@ -1,5 +1,6 @@
/// @file command_base.cpp
#include "command_base.h"
#include "idle_mode.h"
#include "../modules/globals.h"
#include "../modules/finda.h"
#include "../modules/fsensor.h"
@ -206,4 +207,10 @@ void CommandBase::GoToErrEngagingIdler() {
mi::idler.Engage(mg::globals.ActiveSlot());
}
void CommandBase::FinishedOK() {
state = ProgressCode::OK;
error = ErrorCode::OK;
idleMode.CommandFinishedCorrectly();
}
} // namespace logic

View File

@ -109,6 +109,9 @@ protected:
/// Transit the state machine into ErrEngagingIdler
void GoToErrEngagingIdler();
/// Process end of command which finished OK
void FinishedOK();
ProgressCode state; ///< current progress state of the state machine
ErrorCode error; ///< current error code
ProgressCode stateBeforeModuleFailed; ///< saved state of the state machine before a common error happened

View File

@ -92,8 +92,7 @@ bool CutFilament::StepInner() {
break;
case ProgressCode::ReturningSelector:
if (ms::selector.Slot() == 5) { // selector returned to position, feed the filament back to FINDA
state = ProgressCode::OK;
error = ErrorCode::OK;
FinishedOK();
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::on, ml::off);
feed.Reset(true, true);
}

View File

@ -24,7 +24,7 @@ void EjectFilament::Reset(uint8_t param) {
slot = param;
if (mg::globals.FilamentLoaded() == mg::FilamentLoadState::NotLoaded) {
state = ProgressCode::OK;
FinishedOK();
dbg_logic_P(PSTR("Already ejected"));
} else if (mg::globals.FilamentLoaded() >= mg::FilamentLoadState::AtPulley) {
state = ProgressCode::UnloadingFilament;
@ -68,8 +68,7 @@ bool EjectFilament::StepInner() {
if (!mi::idler.Engaged()) { // idler disengaged
mpu::pulley.Disable();
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::NotLoaded);
state = ProgressCode::OK;
error = ErrorCode::OK;
FinishedOK();
}
break;
case ProgressCode::OK:

View File

@ -22,8 +22,7 @@ bool Home::StepInner() {
switch (state) {
case ProgressCode::Homing:
if (mi::idler.State() == mi::Idler::Ready && ms::selector.State() == ms::selector.Ready) {
state = ProgressCode::OK;
error = ErrorCode::OK;
FinishedOK();
}
break;
case ProgressCode::OK:

264
src/logic/idle_mode.cpp Normal file
View File

@ -0,0 +1,264 @@
/// @file
#include "idle_mode.h"
#include "../modules/timebase.h"
#include "../modules/leds.h"
#include "../modules/globals.h"
#include "../modules/user_input.h"
#include "../modules/finda.h"
#include "../modules/fsensor.h"
#include "../modules/serial.h"
#include "command_base.h"
#include "cut_filament.h"
#include "eject_filament.h"
#include "home.h"
#include "load_filament.h"
#include "move_selector.h"
#include "no_command.h"
#include "set_mode.h"
#include "tool_change.h"
#include "unload_filament.h"
#include "../version.h"
#include "../panic.h"
/// Global instance of the protocol codec
static mp::Protocol protocol;
namespace logic {
IdleMode idleMode;
IdleMode::IdleMode()
: lastCommandProcessedMs(0)
, currentCommand(&noCommand)
, currentCommandRq(mp::RequestMsgCodes::Reset, 0) {}
void IdleMode::CheckManualOperation() {
uint16_t ms = mt::timebase.Millis();
constexpr uint16_t idleDelay = 1000U;
if (ms - lastCommandProcessedMs < idleDelay) {
if (currentCommand->State() == ProgressCode::OK) {
mui::userInput.Clear(); // consume bogus UI events while no command in progress and not in idle state yet
}
return;
}
lastCommandProcessedMs = ms - idleDelay; // prevent future overflows
if (currentCommand->State() == ProgressCode::OK && mg::globals.FilamentLoaded() <= mg::FilamentLoadState::AtPulley) {
if (mui::userInput.AnyEvent()) {
switch (mui::userInput.ConsumeEvent()) {
case mui::Event::Left:
// move selector left if possible
if (mg::globals.ActiveSlot() > 0) {
moveSelector.Reset(mg::globals.ActiveSlot() - 1);
currentCommand = &moveSelector;
}
break;
case mui::Event::Middle:
// plan load
if (mg::globals.ActiveSlot() < config::toolCount) { // do we have a meaningful selector position?
loadFilament.ResetUnlimited(mg::globals.ActiveSlot());
currentCommand = &loadFilament;
}
break;
case mui::Event::Right:
// move selector right if possible (including the park position)
if (mg::globals.ActiveSlot() < config::toolCount) {
moveSelector.Reset(mg::globals.ActiveSlot() + 1); // we allow also the park position
currentCommand = &moveSelector;
}
break;
default:
break;
}
}
}
}
mp::ResponseCommandStatus IdleMode::RunningCommandStatus() const {
switch (currentCommand->Error()) {
case ErrorCode::RUNNING:
return mp::ResponseCommandStatus(mp::ResponseMsgParamCodes::Processing, (uint16_t)currentCommand->State());
case ErrorCode::OK:
return mp::ResponseCommandStatus(mp::ResponseMsgParamCodes::Finished, 0);
default:
return mp::ResponseCommandStatus(mp::ResponseMsgParamCodes::Error, (uint16_t)currentCommand->Error());
}
}
static constexpr const uint8_t maxMsgLen = 10;
void IdleMode::ReportCommandAccepted(const mp::RequestMsg &rq, mp::ResponseMsgParamCodes status) {
uint8_t tmp[maxMsgLen];
uint8_t len = protocol.EncodeResponseCmdAR(rq, status, tmp);
modules::serial::WriteToUSART(tmp, len);
}
void IdleMode::PlanCommand(const modules::protocol::RequestMsg &rq) {
if (currentCommand->State() == ProgressCode::OK) {
// We are allowed to start a new command as the previous one is in the OK finished state
// The previous command may be in an error state, but as long as it is in ProgressCode::OK (aka finished)
// we are safe here. It is the responsibility of the printer to ask for a command error code
// before issuing another one - if needed.
switch (rq.code) {
case mp::RequestMsgCodes::Cut:
currentCommand = &cutFilament;
break;
case mp::RequestMsgCodes::Eject:
currentCommand = &ejectFilament;
break;
case mp::RequestMsgCodes::Home:
currentCommand = &logic::home;
break;
case mp::RequestMsgCodes::Load:
currentCommand = &loadFilament;
break;
case mp::RequestMsgCodes::Tool:
currentCommand = &toolChange;
break;
case mp::RequestMsgCodes::Unload:
currentCommand = &unloadFilament;
break;
case mp::RequestMsgCodes::Mode:
currentCommand = &setMode;
break;
default:
currentCommand = &noCommand;
break;
}
currentCommandRq = rq; // save the Current Command Request for indentification of responses
currentCommand->Reset(rq.value);
ReportCommandAccepted(rq, mp::ResponseMsgParamCodes::Accepted);
} else {
ReportCommandAccepted(rq, mp::ResponseMsgParamCodes::Rejected);
}
}
void IdleMode::ReportFINDA(const mp::RequestMsg &rq) {
#ifdef DEBUG_FINDA
using namespace hal;
hu::usart1.puts("FINDA:");
if (hal::gpio::ReadPin(FINDA_PIN) == hal::gpio::Level::high) {
hu::usart1.puts(" TIRGGERED\n");
} else {
hu::usart1.puts(" NOT TRIGGERED\n");
}
#endif //DEBUG_FINDA
uint8_t rsp[maxMsgLen];
uint8_t len = protocol.EncodeResponseReadFINDA(rq, mf::finda.Pressed(), rsp);
modules::serial::WriteToUSART(rsp, len);
}
void IdleMode::ReportVersion(const mp::RequestMsg &rq) {
uint8_t v = 0;
switch (rq.value) {
case 0:
v = project_version_major;
break;
case 1:
v = project_version_minor;
break;
case 2:
v = project_version_revision;
break;
case 3:
// @@TODO may be allow reporting uint16_t number of errors,
// but anything beyond 255 errors means there is something seriously wrong with the MMU
v = mg::globals.DriveErrors();
break;
default:
v = 0;
break;
}
uint8_t rsp[10];
uint8_t len = protocol.EncodeResponseVersion(rq, v, rsp);
modules::serial::WriteToUSART(rsp, len);
}
void IdleMode::ReportRunningCommand() {
uint8_t rsp[maxMsgLen];
uint8_t len = protocol.EncodeResponseQueryOperation(currentCommandRq, logic::idleMode.RunningCommandStatus(), rsp);
modules::serial::WriteToUSART(rsp, len);
}
void IdleMode::ProcessRequestMsg(const mp::RequestMsg &rq) {
switch (rq.code) {
case mp::RequestMsgCodes::Button:
// behave just like if the user pressed a button
mui::userInput.ProcessMessage(rq.value);
break;
case mp::RequestMsgCodes::Finda:
// immediately report FINDA status
ReportFINDA(rq);
break;
case mp::RequestMsgCodes::Query:
// immediately report progress of currently running command
ReportRunningCommand();
break;
case mp::RequestMsgCodes::Reset:
// immediately reset the board - there is no response in this case
hal::cpu::Reset();
break;
case mp::RequestMsgCodes::Version:
ReportVersion(rq);
break;
case mp::RequestMsgCodes::Wait:
break; // @@TODO - not used anywhere yet
case mp::RequestMsgCodes::Cut:
case mp::RequestMsgCodes::Eject:
case mp::RequestMsgCodes::Home:
case mp::RequestMsgCodes::Load:
case mp::RequestMsgCodes::Tool:
case mp::RequestMsgCodes::Unload:
PlanCommand(rq);
break;
case mp::RequestMsgCodes::FilamentSensor: // set filament sensor state in the printer
mfs::fsensor.ProcessMessage(rq.value != 0);
ReportCommandAccepted(rq, mp::ResponseMsgParamCodes::Accepted);
break;
default:
// respond with an error message
break;
}
}
bool IdleMode::CheckMsgs() {
using mpd = mp::DecodeStatus;
while (modules::serial::Available()) {
switch (protocol.DecodeRequest(modules::serial::ConsumeByte())) {
case mpd::MessageCompleted:
// process the input message
return true;
break;
case mpd::NeedMoreData:
// just continue reading
break;
case mpd::Error:
// @@TODO what shall we do? Start some watchdog? We cannot send anything spontaneously
break;
}
}
return false;
}
void IdleMode::Panic(ErrorCode ec) {
currentCommand->Panic(ec);
}
void IdleMode::Step() {
CheckManualOperation();
if (CheckMsgs()) {
ProcessRequestMsg(protocol.GetRequestMsg());
}
currentCommand->Step();
}
} // namespace logic

60
src/logic/idle_mode.h Normal file
View File

@ -0,0 +1,60 @@
/// @file
#pragma once
#include <stdint.h>
#include "../modules/timebase.h"
#include "../modules/protocol.h"
#include "error_codes.h"
namespace logic {
class CommandBase;
class IdleMode {
public:
IdleMode();
inline void CommandFinishedCorrectly() {
lastCommandProcessedMs = mt::timebase.Millis();
}
/// Perform firmware panic handling
void Panic(ErrorCode ec);
/// Perform one step of top level
void Step();
private:
/// Checks if the MMU can enter manual mode (user can move the selector with buttons)
/// The MMU enters idle mode after 5s from the last command finished and there must be no filament present in the selector.
void CheckManualOperation();
/// Checks messages on the UART
bool CheckMsgs();
/// Tries to plan a logic::command if possible
void PlanCommand(const mp::RequestMsg &rq);
mp::ResponseCommandStatus RunningCommandStatus() const;
void ReportCommandAccepted(const mp::RequestMsg &rq, mp::ResponseMsgParamCodes status);
void ReportFINDA(const mp::RequestMsg &rq);
void ReportVersion(const mp::RequestMsg &rq);
void ReportRunningCommand();
void ProcessRequestMsg(const mp::RequestMsg &rq);
uint16_t lastCommandProcessedMs;
/// A command that resulted in the currently on-going operation
CommandBase *currentCommand;
/// Remember the request message that started the currently running command
/// For the start we report "Reset finished" which in fact corresponds with the MMU state pretty closely
/// and plays nicely even with the protocol implementation.
/// And, since the default startup command is the noCommand, which always returns "Finished"
/// the implementation is clean and straightforward - the response to the first Q0 messages
/// will look like "X0 F" until a command (T, L, U ...) has been issued.
mp::RequestMsg currentCommandRq;
};
extern IdleMode idleMode;
} // namespace logic

View File

@ -47,9 +47,8 @@ void logic::LoadFilament::GoToRetractingFromFinda() {
retract.Reset();
}
void logic::LoadFilament::FinishedCorrectly() {
state = ProgressCode::OK;
error = ErrorCode::OK;
void logic::LoadFilament::LoadFinishedCorrectly() {
FinishedOK();
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off);
mpu::pulley.Disable();
}
@ -69,7 +68,7 @@ bool LoadFilament::StepInner() {
case FeedToFinda::Stopped:
// the user stopped the load for whatever reason
// - we are considering the LoadFlament operation as completed
state = ProgressCode::OK;
FinishedOK();
break;
}
}
@ -89,7 +88,7 @@ bool LoadFilament::StepInner() {
// and if the selector decided to re-home, we have to wait for it as well
// therefore: 'if (!mi::idler.Engaged())' : alone is not enough
if (!mi::idler.Engaged() && ms::selector.Slot() == mg::globals.ActiveSlot()) {
FinishedCorrectly();
LoadFinishedCorrectly();
}
break;
case ProgressCode::OK:

View File

@ -29,7 +29,7 @@ private:
void Reset2(bool feedPhaseLimited);
/// Common code for a correct completion of UnloadFilament
void FinishedCorrectly();
void LoadFinishedCorrectly();
FeedToFinda feed;
RetractFromFinda retract;

View File

@ -23,8 +23,8 @@ bool MoveSelector::StepInner() {
switch (state) {
case ProgressCode::MovingSelector:
if (ms::selector.State() == ms::selector.Ready) {
state = ProgressCode::OK;
error = ErrorCode::OK;
mg::globals.SetFilamentLoaded(ms::selector.Slot(), mg::FilamentLoadState::AtPulley);
FinishedOK();
}
break;
case ProgressCode::OK:

View File

@ -11,8 +11,7 @@ void SetMode::Reset(uint8_t param) {
mg::globals.SetMotorsMode(param != 0); // remember the last mode set
// distribute the mode to all motors immediately
mm::motion.SetMode((param == 0) ? mm::Normal : mm::Stealth);
state = ProgressCode::OK;
error = ErrorCode::OK;
FinishedOK();
}
} // namespace logic

View File

@ -52,10 +52,9 @@ void logic::ToolChange::GoToFeedingToBondtech() {
error = ErrorCode::RUNNING;
}
void logic::ToolChange::FinishedCorrectly() {
void logic::ToolChange::ToolChangeFinishedCorrectly() {
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::on, ml::off);
state = ProgressCode::OK;
error = ErrorCode::OK;
FinishedOK();
}
bool ToolChange::StepInner() {
@ -85,7 +84,7 @@ bool ToolChange::StepInner() {
if (james.State() == FeedToBondtech::Failed) {
GoToErrDisengagingIdler(ErrorCode::FSENSOR_DIDNT_SWITCH_ON); // signal loading error
} else {
FinishedCorrectly();
ToolChangeFinishedCorrectly();
}
}
break;
@ -122,7 +121,7 @@ bool ToolChange::StepInner() {
} else {
// all sensors are ok, we assume the user pushed the filament into the nozzle
mg::globals.SetFilamentLoaded(plannedSlot, mg::FilamentLoadState::InNozzle);
FinishedCorrectly();
ToolChangeFinishedCorrectly();
}
break;
default: // no event, continue waiting for user input

View File

@ -31,7 +31,7 @@ private:
void GoToFeedingToBondtech();
/// Common code for a correct completion of UnloadFilament
void FinishedCorrectly();
void ToolChangeFinishedCorrectly();
UnloadFilament unl; ///< a high-level command/operation may be used as a building block of other operations as well
FeedToFinda feed;

View File

@ -32,9 +32,8 @@ void UnloadFilament::Reset(uint8_t /*param*/) {
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off);
}
void UnloadFilament::FinishedCorrectly() {
state = ProgressCode::OK;
error = ErrorCode::OK;
void UnloadFilament::UnloadFinishedCorrectly() {
FinishedOK();
mpu::pulley.Disable();
mg::globals.SetFilamentLoaded(mg::globals.ActiveSlot(), mg::FilamentLoadState::AtPulley); // filament unloaded
ml::leds.SetPairButOffOthers(mg::globals.ActiveSlot(), ml::off, ml::off);
@ -80,7 +79,7 @@ bool UnloadFilament::StepInner() {
return false;
case ProgressCode::DisengagingIdler:
if (!mi::idler.Engaged() && ms::selector.State() == ms::Selector::Ready) {
FinishedCorrectly();
UnloadFinishedCorrectly();
}
return false;
case ProgressCode::ERRDisengagingIdler: // couldn't unload to FINDA

View File

@ -25,7 +25,7 @@ private:
constexpr static const uint8_t maxRetries = 1;
/// Common code for a correct completion of UnloadFilament
void FinishedCorrectly();
void UnloadFinishedCorrectly();
void GoToRetractingFromFinda();
void GoToRecheckFilamentAgainstFINDA();

View File

@ -25,35 +25,7 @@
#include "modules/motion.h"
#include "modules/usb_cdc.h"
#include "logic/command_base.h"
#include "logic/cut_filament.h"
#include "logic/eject_filament.h"
#include "logic/home.h"
#include "logic/load_filament.h"
#include "logic/move_selector.h"
#include "logic/no_command.h"
#include "logic/set_mode.h"
#include "logic/tool_change.h"
#include "logic/unload_filament.h"
#include "version.h"
#include "panic.h"
/// Global instance of the protocol codec
static mp::Protocol protocol;
/// A command that resulted in the currently on-going operation
static logic::CommandBase *currentCommand = &logic::noCommand;
/// Remember the request message that started the currently running command
/// For the start we report "Reset finished" which in fact corresponds with the MMU state pretty closely
/// and plays nicely even with the protocol implementation.
/// And, since the default startup command is the noCommand, which always returns "Finished"
/// the implementation is clean and straightforward - the response to the first Q0 messages
/// will look like "X0 F" until a command (T, L, U ...) has been issued.
static mp::RequestMsg currentCommandRq(mp::RequestMsgCodes::Reset, 0);
static uint16_t lastCommandProcessedMs = 0;
#include "logic/idle_mode.h"
/// One-time setup of HW and SW components
/// Called before entering the loop() function
@ -128,237 +100,8 @@ void setup() {
}
}
static constexpr const uint8_t maxMsgLen = 10;
bool WriteToUSART(const uint8_t *src, uint8_t len) {
// How to properly enqueue the message? Especially in case of a full buffer.
// We neither can stay here in an endless loop until the buffer drains.
// Nor can we save the message elsewhere ... it must be just skipped and the protocol must handle it.
// Under normal circumstances, such a situation should not happen.
// The MMU cannot produce response messages on its own - it only responds to requests from the printer.
// That means there is only one message in the output buffer at once as long as the printer waits for the response before sending another request.
for (uint8_t i = 0; i < len; ++i) {
if (hu::usart1.CanWrite()) {
// should not block waiting for the TX buffer to drain as there was an empty spot for at least 1 byte
hu::usart1.Write(src[i]);
} else {
//buffer full - must skip the rest of the message - the communication will drop out anyway
return false;
}
}
return true; // not sure if we can actually leverage the knowledge of success while sending the message
}
void ReportCommandAccepted(const mp::RequestMsg &rq, mp::ResponseMsgParamCodes status) {
uint8_t tmp[maxMsgLen];
uint8_t len = protocol.EncodeResponseCmdAR(rq, status, tmp);
WriteToUSART(tmp, len);
}
void ReportFINDA(const mp::RequestMsg &rq) {
#ifdef DEBUG_FINDA
using namespace hal;
hu::usart1.puts("FINDA:");
if (hal::gpio::ReadPin(FINDA_PIN) == hal::gpio::Level::high) {
hu::usart1.puts(" TIRGGERED\n");
} else {
hu::usart1.puts(" NOT TRIGGERED\n");
}
#endif //DEBUG_FINDA
uint8_t rsp[maxMsgLen];
uint8_t len = protocol.EncodeResponseReadFINDA(rq, mf::finda.Pressed(), rsp);
WriteToUSART(rsp, len);
}
void ReportVersion(const mp::RequestMsg &rq) {
uint8_t v = 0;
switch (rq.value) {
case 0:
v = project_version_major;
break;
case 1:
v = project_version_minor;
break;
case 2:
v = project_version_revision;
break;
case 3:
// @@TODO may be allow reporting uint16_t number of errors,
// but anything beyond 255 errors means there is something seriously wrong with the MMU
v = mg::globals.DriveErrors();
break;
default:
v = 0;
break;
}
uint8_t rsp[10];
uint8_t len = protocol.EncodeResponseVersion(rq, v, rsp);
WriteToUSART(rsp, len);
}
void ReportRunningCommand() {
mp::ResponseMsgParamCodes commandStatus;
uint16_t value = 0;
switch (currentCommand->Error()) {
case ErrorCode::RUNNING:
commandStatus = mp::ResponseMsgParamCodes::Processing;
value = (uint16_t)currentCommand->State();
break;
case ErrorCode::OK:
commandStatus = mp::ResponseMsgParamCodes::Finished;
lastCommandProcessedMs = mt::timebase.Millis();
break;
default:
commandStatus = mp::ResponseMsgParamCodes::Error;
value = (uint16_t)currentCommand->Error();
break;
}
uint8_t rsp[maxMsgLen];
uint8_t len = protocol.EncodeResponseQueryOperation(currentCommandRq, commandStatus, value, rsp);
WriteToUSART(rsp, len);
}
void PlanCommand(const mp::RequestMsg &rq) {
if (currentCommand->State() == ProgressCode::OK) {
// We are allowed to start a new command as the previous one is in the OK finished state
// The previous command may be in an error state, but as long as it is in ProgressCode::OK (aka finished)
// we are safe here. It is the responsibility of the printer to ask for a command error code
// before issuing another one - if needed.
switch (rq.code) {
case mp::RequestMsgCodes::Cut:
currentCommand = &logic::cutFilament;
break;
case mp::RequestMsgCodes::Eject:
currentCommand = &logic::ejectFilament;
break;
case mp::RequestMsgCodes::Home:
currentCommand = &logic::home;
break;
case mp::RequestMsgCodes::Load:
currentCommand = &logic::loadFilament;
break;
case mp::RequestMsgCodes::Tool:
currentCommand = &logic::toolChange;
break;
case mp::RequestMsgCodes::Unload:
currentCommand = &logic::unloadFilament;
break;
case mp::RequestMsgCodes::Mode:
currentCommand = &logic::setMode;
break;
default:
currentCommand = &logic::noCommand;
break;
}
currentCommandRq = rq; // save the Current Command Request for indentification of responses
currentCommand->Reset(rq.value);
ReportCommandAccepted(rq, mp::ResponseMsgParamCodes::Accepted);
} else {
ReportCommandAccepted(rq, mp::ResponseMsgParamCodes::Rejected);
}
}
void ProcessRequestMsg(const mp::RequestMsg &rq) {
switch (rq.code) {
case mp::RequestMsgCodes::Button:
// behave just like if the user pressed a button
mui::userInput.ProcessMessage(rq.value);
break;
case mp::RequestMsgCodes::Finda:
// immediately report FINDA status
ReportFINDA(rq);
break;
case mp::RequestMsgCodes::Query:
// immediately report progress of currently running command
ReportRunningCommand();
break;
case mp::RequestMsgCodes::Reset:
// immediately reset the board - there is no response in this case
hal::cpu::Reset();
break;
case mp::RequestMsgCodes::Version:
ReportVersion(rq);
break;
case mp::RequestMsgCodes::Wait:
break; // @@TODO - not used anywhere yet
case mp::RequestMsgCodes::Cut:
case mp::RequestMsgCodes::Eject:
case mp::RequestMsgCodes::Home:
case mp::RequestMsgCodes::Load:
case mp::RequestMsgCodes::Tool:
case mp::RequestMsgCodes::Unload:
PlanCommand(rq);
break;
case mp::RequestMsgCodes::FilamentSensor: // set filament sensor state in the printer
mfs::fsensor.ProcessMessage(rq.value != 0);
ReportCommandAccepted(rq, mp::ResponseMsgParamCodes::Accepted);
break;
default:
// respond with an error message
break;
}
}
/// @returns true if a request was successfully finished
bool CheckMsgs() {
using mpd = mp::DecodeStatus;
while (!hu::usart1.ReadEmpty()) {
switch (protocol.DecodeRequest(hu::usart1.Read())) {
case mpd::MessageCompleted:
// process the input message
return true;
break;
case mpd::NeedMoreData:
// just continue reading
break;
case mpd::Error:
// @@TODO what shall we do? Start some watchdog? We cannot send anything spontaneously
break;
}
}
return false;
}
void Panic(ErrorCode ec) {
currentCommand->Panic(ec);
}
bool CheckManualOperation() {
if (currentCommand == &logic::noCommand
&& mg::globals.FilamentLoaded() <= mg::FilamentLoadState::AtPulley
&& lastCommandProcessedMs + 5000 < mt::timebase.Millis()) {
lastCommandProcessedMs = mt::timebase.Millis() - 5000; // @@TODO prevent future overflows - must be called every time
if (mui::userInput.AnyEvent()) {
switch (mui::userInput.ConsumeEvent()) {
case mui::Event::Left:
// move selector left if possible
if (mg::globals.ActiveSlot() > 0) {
currentCommand = &logic::moveSelector;
currentCommand->Reset(mg::globals.ActiveSlot() - 1);
}
break;
case mui::Event::Middle:
// plan load
if (mg::globals.ActiveSlot() < config::toolCount) { // do we have a meaningful selector position?
logic::loadFilament.ResetUnlimited(mg::globals.ActiveSlot());
currentCommand = &logic::loadFilament;
}
break;
case mui::Event::Right:
// move selector right if possible (including the park position)
if (mg::globals.ActiveSlot() < config::toolCount) {
currentCommand = &logic::moveSelector;
currentCommand->Reset(mg::globals.ActiveSlot() + 1); // we allow also the park position
}
break;
default:
break;
}
}
}
logic::idleMode.Panic(ec);
}
/// Main loop of the firmware
@ -376,12 +119,6 @@ bool CheckManualOperation() {
/// The idea behind the Step* routines is to keep each automaton non-blocking allowing for some “concurrency”.
/// Some FW components will leverage ISR to do their stuff (UART, motor stepping?, etc.)
void loop() {
CheckManualOperation();
if (CheckMsgs()) {
ProcessRequestMsg(protocol.GetRequestMsg());
}
mb::buttons.Step();
ml::leds.Step();
mf::finda.Step();
@ -390,10 +127,11 @@ void loop() {
ms::selector.Step();
mpu::pulley.Step();
mui::userInput.Step();
currentCommand->Step();
hal::cpu::Step();
mu::cdc.Step();
logic::idleMode.Step();
hal::watchdog::Reset();
}

View File

@ -14,6 +14,7 @@ target_sources(
pulley.cpp
pulse_gen.cpp
selector.cpp
serial.cpp
speed_table.cpp
timebase.cpp
usb_cdc.cpp

View File

@ -210,33 +210,33 @@ uint8_t Protocol::EncodeResponseVersion(const RequestMsg &msg, uint8_t value, ui
return dst - txbuff + 1;
}
uint8_t Protocol::EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint16_t value, uint8_t *txbuff) {
uint8_t Protocol::EncodeResponseQueryOperation(const RequestMsg &msg, ResponseCommandStatus rcs, uint8_t *txbuff) {
txbuff[0] = (uint8_t)msg.code;
txbuff[1] = msg.value + '0';
txbuff[2] = ' ';
txbuff[3] = (uint8_t)code;
txbuff[3] = (uint8_t)rcs.code;
uint8_t *dst = txbuff + 4;
if (code != ResponseMsgParamCodes::Finished) {
if (value < 10) {
*dst++ = value + '0';
} else if (value < 100) {
*dst++ = value / 10 + '0';
*dst++ = value % 10 + '0';
} else if (value < 1000) {
*dst++ = value / 100 + '0';
*dst++ = (value / 10) % 10 + '0';
*dst++ = value % 10 + '0';
} else if (value < 10000) {
*dst++ = value / 1000 + '0';
*dst++ = (value / 100) % 10 + '0';
*dst++ = (value / 10) % 10 + '0';
*dst++ = value % 10 + '0';
if (rcs.code != ResponseMsgParamCodes::Finished) {
if (rcs.value < 10) {
*dst++ = rcs.value + '0';
} else if (rcs.value < 100) {
*dst++ = rcs.value / 10 + '0';
*dst++ = rcs.value % 10 + '0';
} else if (rcs.value < 1000) {
*dst++ = rcs.value / 100 + '0';
*dst++ = (rcs.value / 10) % 10 + '0';
*dst++ = rcs.value % 10 + '0';
} else if (rcs.value < 10000) {
*dst++ = rcs.value / 1000 + '0';
*dst++ = (rcs.value / 100) % 10 + '0';
*dst++ = (rcs.value / 10) % 10 + '0';
*dst++ = rcs.value % 10 + '0';
} else {
*dst++ = value / 10000 + '0';
*dst++ = (value / 1000) % 10 + '0';
*dst++ = (value / 100) % 10 + '0';
*dst++ = (value / 10) % 10 + '0';
*dst++ = value % 10 + '0';
*dst++ = rcs.value / 10000 + '0';
*dst++ = (rcs.value / 1000) % 10 + '0';
*dst++ = (rcs.value / 100) % 10 + '0';
*dst++ = (rcs.value / 10) % 10 + '0';
*dst++ = rcs.value % 10 + '0';
}
}
*dst = '\n';

View File

@ -47,7 +47,7 @@ struct RequestMsg {
/// @param code of the request message
/// @param value of the request message
inline RequestMsg(RequestMsgCodes code, uint8_t value)
inline constexpr RequestMsg(RequestMsgCodes code, uint8_t value)
: code(code)
, value(value) {}
};
@ -61,12 +61,21 @@ struct ResponseMsg {
/// @param request the source request message this response is a reply to
/// @param paramCode code of the parameter
/// @param paramValue value of the parameter
inline ResponseMsg(RequestMsg request, ResponseMsgParamCodes paramCode, uint16_t paramValue)
inline constexpr ResponseMsg(RequestMsg request, ResponseMsgParamCodes paramCode, uint16_t paramValue)
: request(request)
, paramCode(paramCode)
, paramValue(paramValue) {}
};
/// Combined commandStatus and its value into one data structure (optimization purposes)
struct ResponseCommandStatus {
ResponseMsgParamCodes code;
uint16_t value;
inline constexpr ResponseCommandStatus(ResponseMsgParamCodes code, uint16_t value)
: code(code)
, value(value) {}
};
/// Message decoding return values
enum class DecodeStatus : uint_fast8_t {
MessageCompleted, ///< message completed and successfully lexed
@ -131,7 +140,7 @@ public:
/// @param value related to status of operation(e.g. error code or progress)
/// @param txbuff where to format the message
/// @returns number of bytes written into txbuff
static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint16_t value, uint8_t *txbuff);
static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseCommandStatus rcs, uint8_t *txbuff);
/// @returns the most recently lexed request message
inline const RequestMsg GetRequestMsg() const { return requestMsg; }

37
src/modules/serial.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "serial.h"
#include "../hal/usart.h"
namespace modules {
namespace serial {
bool WriteToUSART(const uint8_t *src, uint8_t len) {
// How to properly enqueue the message? Especially in case of a full buffer.
// We neither can stay here in an endless loop until the buffer drains.
// Nor can we save the message elsewhere ... it must be just skipped and the protocol must handle it.
// Under normal circumstances, such a situation should not happen.
// The MMU cannot produce response messages on its own - it only responds to requests from the printer.
// That means there is only one message in the output buffer at once as long as the printer waits for the response before sending another request.
for (uint8_t i = 0; i < len; ++i) {
if (hu::usart1.CanWrite()) {
// should not block waiting for the TX buffer to drain as there was an empty spot for at least 1 byte
hu::usart1.Write(src[i]);
} else {
//buffer full - must skip the rest of the message - the communication will drop out anyway
return false;
}
}
return true; // not sure if we can actually leverage the knowledge of success while sending the message
}
bool Available() {
return !hu::usart1.ReadEmpty();
}
uint8_t ConsumeByte() {
return hu::usart1.Read();
}
} // namespace serial
} // namespace modules

17
src/modules/serial.h Normal file
View File

@ -0,0 +1,17 @@
/// @file
#pragma once
#include <stdint.h>
namespace modules {
namespace serial {
bool WriteToUSART(const uint8_t *src, uint8_t len);
bool Available();
uint8_t ConsumeByte();
} // namespace serial
} // namespace modules

View File

@ -3,8 +3,17 @@ add_executable(
cut_filament_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.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
@ -16,14 +25,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -2,9 +2,18 @@
add_executable(
eject_filament_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.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
@ -16,14 +25,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -2,9 +2,18 @@
add_executable(
failing_tmc_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.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
@ -16,14 +25,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -2,7 +2,20 @@
add_executable(
feed_to_bondtech_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.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
@ -12,14 +25,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -2,7 +2,20 @@
add_executable(
feed_to_finda_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.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
@ -12,14 +25,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -2,10 +2,18 @@
add_executable(
homing_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.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
@ -17,14 +25,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -2,10 +2,21 @@
add_executable(
load_filament_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.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
@ -15,14 +26,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -58,6 +58,9 @@ void Motion::SetPosition(Axis axis, pos_t x) {
void Motion::SetMode(Axis axis, hal::tmc2130::MotorMode mode) {
}
void Motion::SetMode(MotorMode mode) {
}
st_timer_t Motion::Step() {
for (uint8_t i = 0; i < 3; ++i) {
if (!axes[i].plannedMoves.empty()) {

View File

@ -2,10 +2,18 @@
add_executable(
tool_change_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/unload_to_finda.cpp
@ -18,14 +26,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -2,8 +2,18 @@
add_executable(
unload_filament_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.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
@ -15,14 +25,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -2,6 +2,19 @@
add_executable(
unload_to_finda_tests
${CMAKE_SOURCE_DIR}/src/logic/command_base.cpp
${CMAKE_SOURCE_DIR}/src/logic/cut_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/eject_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_finda.cpp
${CMAKE_SOURCE_DIR}/src/logic/feed_to_bondtech.cpp
${CMAKE_SOURCE_DIR}/src/logic/home.cpp
${CMAKE_SOURCE_DIR}/src/logic/idle_mode.cpp
${CMAKE_SOURCE_DIR}/src/logic/load_filament.cpp
${CMAKE_SOURCE_DIR}/src/logic/move_selector.cpp
${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/tool_change.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
@ -12,14 +25,17 @@ add_executable(
${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/protocol.cpp
${CMAKE_SOURCE_DIR}/src/modules/pulley.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_cpu.cpp
${MODULES_STUBS_DIR}/stub_eeprom.cpp
${MODULES_STUBS_DIR}/stub_gpio.cpp
${MODULES_STUBS_DIR}/stub_shr16.cpp
${MODULES_STUBS_DIR}/stub_serial.cpp
${MODULES_STUBS_DIR}/stub_timebase.cpp
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
${LOGIC_STUBS_DIR}/homing.cpp

View File

@ -230,7 +230,7 @@ TEST_CASE("protocol::EncodeResponseQueryOperation", "[protocol]") {
uint16_t encodedParamValue = responseStatus == mp::ResponseMsgParamCodes::Error ? (uint16_t)error : (uint16_t)value;
uint8_t msglen = mp::Protocol::EncodeResponseQueryOperation(requestMsg, responseStatus, encodedParamValue, txbuff.data());
uint8_t msglen = mp::Protocol::EncodeResponseQueryOperation(requestMsg, mp::ResponseCommandStatus(responseStatus, encodedParamValue), txbuff.data());
CHECK(msglen <= txbuff.size());
CHECK(txbuff[0] == (uint8_t)requestMsg.code);

View File

@ -0,0 +1,7 @@
namespace hal {
namespace cpu {
void Reset() {}
} // namespace cpu
} // namespace hal

View File

@ -0,0 +1,13 @@
#include "serial.h"
namespace modules {
namespace serial {
bool WriteToUSART(const uint8_t *src, uint8_t len) { return false; }
bool Available() { return false; }
uint8_t ConsumeByte() { return 0; }
} // namespace serial
} // namespace modules