MMU: Sync code with 32-bit

The changes in this commit are mainly formatting

But there are some changes like adding a new function planner_draining()
This commit is contained in:
Guðni Már Gilbert 2024-03-28 23:15:35 +00:00 committed by gudnimg
parent e405e9140c
commit 592fc56bfc
11 changed files with 231 additions and 175 deletions

View File

@ -34,7 +34,7 @@ void waitForHotendTargetTemp(uint16_t delay, F f) {
} }
void WaitForHotendTargetTempBeep() { void WaitForHotendTargetTempBeep() {
waitForHotendTargetTemp(3000, []{ }); waitForHotendTargetTemp(200, [] {});
MakeSound(Prompt); MakeSound(Prompt);
} }
@ -73,14 +73,17 @@ void MMU2::Start() {
mmu2Serial.flush(); // make sure the UART buffer is clear before starting communication mmu2Serial.flush(); // make sure the UART buffer is clear before starting communication
SetCurrentTool(MMU2_NO_TOOL); SetCurrentTool(MMU2_NO_TOOL);
state = xState::Connecting;
// start the communication // start the communication
logic.Start();
logic.ResetRetryAttempts(); logic.ResetRetryAttempts();
logic.ResetCommunicationTimeoutAttempts(); logic.ResetCommunicationTimeoutAttempts();
state = xState::Connecting;
logic.Start();
} }
MMU2::~MMU2() {}
void MMU2::Stop() { void MMU2::Stop() {
StopKeepPowered(); StopKeepPowered();
PowerOff(); PowerOff();
@ -153,8 +156,9 @@ void MMU2::PowerOn() {
} }
bool MMU2::ReadRegister(uint8_t address) { bool MMU2::ReadRegister(uint8_t address) {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
do { do {
logic.ReadRegister(address); // we may signal the accepted/rejected status of the response as return value of this function logic.ReadRegister(address); // we may signal the accepted/rejected status of the response as return value of this function
} while (!manage_response(false, false)); } while (!manage_response(false, false));
@ -165,8 +169,9 @@ bool MMU2::ReadRegister(uint8_t address) {
} }
bool __attribute__((noinline)) MMU2::WriteRegister(uint8_t address, uint16_t data) { bool __attribute__((noinline)) MMU2::WriteRegister(uint8_t address, uint16_t data) {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
// special cases - intercept requests of registers which influence the printer's behaviour too + perform the change even on the printer's side // special cases - intercept requests of registers which influence the printer's behaviour too + perform the change even on the printer's side
switch (address) { switch (address) {
@ -192,12 +197,11 @@ void MMU2::mmu_loop() {
// Atomic compare_exchange would have been the most appropriate solution here, but this gets called only in Marlin's task, // Atomic compare_exchange would have been the most appropriate solution here, but this gets called only in Marlin's task,
// so thread safety should be kept // so thread safety should be kept
static bool avoidRecursion = false; static bool avoidRecursion = false;
if (avoidRecursion) if (avoidRecursion) {
return; return;
}
avoidRecursion = true; avoidRecursion = true;
mmu_loop_inner(true); mmu_loop_inner(true);
avoidRecursion = false; avoidRecursion = false;
} }
@ -208,7 +212,7 @@ void __attribute__((noinline)) MMU2::mmu_loop_inner(bool reportErrors) {
void MMU2::CheckFINDARunout() { void MMU2::CheckFINDARunout() {
// Check for FINDA filament runout // Check for FINDA filament runout
if (!FindaDetectsFilament() && check_fsensor()) { if (!FindaDetectsFilament() && check_fsensor()) { // Check if we have filament runout detected from sensors
SERIAL_ECHOLNPGM("FINDA filament runout!"); SERIAL_ECHOLNPGM("FINDA filament runout!");
marlin_stop_and_save_print_to_ram(); marlin_stop_and_save_print_to_ram();
restore_print_from_ram_and_continue(0); restore_print_from_ram_and_continue(0);
@ -301,8 +305,12 @@ bool MMU2::VerifyFilamentEnteredPTFE() {
filament_inserted = filament_inserted && (WhereIsFilament() == FilamentState::AT_FSENSOR); filament_inserted = filament_inserted && (WhereIsFilament() == FilamentState::AT_FSENSOR);
tlur.Progress(filament_inserted); tlur.Progress(filament_inserted);
safe_delay_keep_alive(0); safe_delay_keep_alive(0);
if (planner_draining()) {
return false; // power panic or a similar issue happened, bail out fast
} }
} }
}
Disable_E0(); Disable_E0();
if (!filament_inserted) { if (!filament_inserted) {
IncrementLoadFails(); IncrementLoadFails();
@ -318,8 +326,9 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot) {
Disable_E0(); // it may seem counterintuitive to disable the E-motor, but it gets enabled in the planner whenever the E-motor is to move Disable_E0(); // it may seem counterintuitive to disable the E-motor, but it gets enabled in the planner whenever the E-motor is to move
tool_change_extruder = slot; tool_change_extruder = slot;
logic.ToolChange(slot); // let the MMU pull the filament out and push a new one in logic.ToolChange(slot); // let the MMU pull the filament out and push a new one in
if (manage_response(true, true)) if (manage_response(true, true)) {
break; break;
}
// otherwise: failed to perform the command - unload first and then let it run again // otherwise: failed to perform the command - unload first and then let it run again
IncrementMMUFails(); IncrementMMUFails();
@ -347,6 +356,9 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot) {
void MMU2::ToolChangeCommon(uint8_t slot) { void MMU2::ToolChangeCommon(uint8_t slot) {
while (!ToolChangeCommonOnce(slot)) { // while not successfully fed into extruder's PTFE tube while (!ToolChangeCommonOnce(slot)) { // while not successfully fed into extruder's PTFE tube
if (planner_draining()) {
return; // power panic happening, pretend the G-code finished ok
}
// failed autoretry, report an error by forcing a "printer" error into the MMU infrastructure - it is a hack to leverage existing code // failed autoretry, report an error by forcing a "printer" error into the MMU infrastructure - it is a hack to leverage existing code
// @@TODO theoretically logic layer may not need to be spoiled with the printer error - may be just the manage_response needs it... // @@TODO theoretically logic layer may not need to be spoiled with the printer error - may be just the manage_response needs it...
logic.SetPrinterError(ErrorCode::LOAD_TO_EXTRUDER_FAILED); logic.SetPrinterError(ErrorCode::LOAD_TO_EXTRUDER_FAILED);
@ -364,8 +376,9 @@ void MMU2::ToolChangeCommon(uint8_t slot) {
} }
bool MMU2::tool_change(uint8_t slot) { bool MMU2::tool_change(uint8_t slot) {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
if (slot != extruder) { if (slot != extruder) {
if (/*FindaDetectsFilament()*/ if (/*FindaDetectsFilament()*/
@ -390,8 +403,9 @@ bool MMU2::tool_change(uint8_t slot) {
///- Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load. ///- Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load.
///- Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated. ///- Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated.
bool MMU2::tool_change(char code, uint8_t slot) { bool MMU2::tool_change(char code, uint8_t slot) {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
FSensorBlockRunout blockRunout; FSensorBlockRunout blockRunout;
@ -435,8 +449,9 @@ void MMU2::SetCurrentTool(uint8_t ex){
} }
bool MMU2::set_filament_type(uint8_t /*slot*/, uint8_t /*type*/) { bool MMU2::set_filament_type(uint8_t /*slot*/, uint8_t /*type*/) {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
// @@TODO - this is not supported in the new MMU yet // @@TODO - this is not supported in the new MMU yet
// slot = slot; // @@TODO // slot = slot; // @@TODO
@ -461,8 +476,9 @@ void MMU2::UnloadInner() {
for (;;) { for (;;) {
Disable_E0(); Disable_E0();
logic.UnloadFilament(); logic.UnloadFilament();
if (manage_response(false, true)) if (manage_response(false, true)) {
break; break;
}
IncrementMMUFails(); IncrementMMUFails();
} }
MakeSound(Confirm); MakeSound(Confirm);
@ -473,15 +489,16 @@ void MMU2::UnloadInner() {
} }
bool MMU2::unload() { bool MMU2::unload() {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
WaitForHotendTargetTempBeep();
{ {
ReportingRAII rep(CommandInProgress::UnloadFilament); ReportingRAII rep(CommandInProgress::UnloadFilament);
WaitForHotendTargetTempBeep();
UnloadInner(); UnloadInner();
} }
ScreenUpdateEnable(); ScreenUpdateEnable();
return true; return true;
} }
@ -490,15 +507,17 @@ void MMU2::CutFilamentInner(uint8_t slot) {
for (;;) { for (;;) {
Disable_E0(); Disable_E0();
logic.CutFilament(slot); logic.CutFilament(slot);
if (manage_response(false, true)) if (manage_response(false, true)) {
break; break;
}
IncrementMMUFails(); IncrementMMUFails();
} }
} }
bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /*= true*/) { bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /*= true*/) {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
if (enableFullScreenMsg) { if (enableFullScreenMsg) {
FullScreenMsgCut(slot); FullScreenMsgCut(slot);
@ -528,8 +547,9 @@ bool MMU2::loading_test(uint8_t slot) {
} }
bool MMU2::load_filament(uint8_t slot) { bool MMU2::load_filament(uint8_t slot) {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
FullScreenMsgLoad(slot); FullScreenMsgLoad(slot);
{ {
@ -537,8 +557,9 @@ bool MMU2::load_filament(uint8_t slot) {
for (;;) { for (;;) {
Disable_E0(); Disable_E0();
logic.LoadFilament(slot); logic.LoadFilament(slot);
if (manage_response(false, false)) if (manage_response(false, false)) {
break; break;
}
IncrementMMUFails(); IncrementMMUFails();
} }
MakeSound(SoundType::Confirm); MakeSound(SoundType::Confirm);
@ -548,10 +569,9 @@ bool MMU2::load_filament(uint8_t slot) {
} }
bool MMU2::load_filament_to_nozzle(uint8_t slot) { bool MMU2::load_filament_to_nozzle(uint8_t slot) {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
WaitForHotendTargetTempBeep();
FullScreenMsgLoad(slot); FullScreenMsgLoad(slot);
{ {
@ -559,6 +579,8 @@ bool MMU2::load_filament_to_nozzle(uint8_t slot) {
ReportingRAII rep(CommandInProgress::ToolChange); ReportingRAII rep(CommandInProgress::ToolChange);
FSensorBlockRunout blockRunout; FSensorBlockRunout blockRunout;
WaitForHotendTargetTempBeep();
if (extruder != MMU2_NO_TOOL) { // we already have some filament loaded - free it + shape its tip properly if (extruder != MMU2_NO_TOOL) { // we already have some filament loaded - free it + shape its tip properly
filament_ramming(); filament_ramming();
} }
@ -574,8 +596,9 @@ bool MMU2::load_filament_to_nozzle(uint8_t slot) {
} }
bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) { bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
if (!WaitForMMUReady()) if (!WaitForMMUReady()) {
return false; return false;
}
if (enableFullScreenMsg) { if (enableFullScreenMsg) {
FullScreenMsgEject(slot); FullScreenMsgEject(slot);
@ -589,8 +612,9 @@ bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
for (;;) { for (;;) {
Disable_E0(); Disable_E0();
logic.EjectFilament(slot); logic.EjectFilament(slot);
if (manage_response(false, true)) if (manage_response(false, true)) {
break; break;
}
IncrementMMUFails(); IncrementMMUFails();
} }
SetCurrentTool(MMU2_NO_TOOL); SetCurrentTool(MMU2_NO_TOOL);
@ -611,8 +635,9 @@ void MMU2::Home(uint8_t mode) {
} }
void MMU2::SaveHotendTemp(bool turn_off_nozzle) { void MMU2::SaveHotendTemp(bool turn_off_nozzle) {
if (mmu_print_saved & SavedState::Cooldown) if (mmu_print_saved & SavedState::Cooldown) {
return; return;
}
if (turn_off_nozzle && !(mmu_print_saved & SavedState::CooldownPending)) { if (turn_off_nozzle && !(mmu_print_saved & SavedState::CooldownPending)) {
Disable_E0(); Disable_E0();
@ -701,8 +726,7 @@ void MMU2::CheckUserInput() {
lastButton = Buttons::NoButton; // Clear it. lastButton = Buttons::NoButton; // Clear it.
} }
if (mmu2.MMULastErrorSource() == MMU2::ErrorSourcePrinter && btn != Buttons::NoButton) if (mmu2.MMULastErrorSource() == ErrorSourcePrinter && btn != Buttons::NoButton) {
{
// When the printer has raised an error screen, and a button was selected // When the printer has raised an error screen, and a button was selected
// the error screen should always be dismissed. // the error screen should always be dismissed.
ClearPrinterError(); ClearPrinterError();
@ -720,7 +744,7 @@ void MMU2::CheckUserInput() {
SERIAL_ECHOLN((int)buttons_to_uint8t(btn)); SERIAL_ECHOLN((int)buttons_to_uint8t(btn));
ResumeHotendTemp(); // Recover the hotend temp before we attempt to do anything else... ResumeHotendTemp(); // Recover the hotend temp before we attempt to do anything else...
if (mmu2.MMULastErrorSource() == MMU2::ErrorSourceMMU) { if (mmu2.MMULastErrorSource() == ErrorSourceMMU) {
// Do not send a button to the MMU unless the MMU is in error state // Do not send a button to the MMU unless the MMU is in error state
Button(buttons_to_uint8t(btn)); Button(buttons_to_uint8t(btn));
} }
@ -782,6 +806,7 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
// - failed -> then do the safety moves on the printer like before // - failed -> then do the safety moves on the printer like before
// - finished ok -> proceed with reading other commands // - finished ok -> proceed with reading other commands
safe_delay_keep_alive(0); // calls LogicStep() and remembers its return status safe_delay_keep_alive(0); // calls LogicStep() and remembers its return status
// also disables stepper motor unlocking
if (mmu_print_saved & SavedState::CooldownPending) { if (mmu_print_saved & SavedState::CooldownPending) {
if (!nozzleTimeout.running()) { if (!nozzleTimeout.running()) {
@ -804,8 +829,7 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
// the E may have some more moves to finish - wait for them // the E may have some more moves to finish - wait for them
ResumeHotendTemp(); ResumeHotendTemp();
ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved. ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved.
if (!TuneMenuEntered()) if (!TuneMenuEntered()) {
{
// If the error screen is sleeping (running 'Tune' menu) // If the error screen is sleeping (running 'Tune' menu)
// then don't reset retry attempts because we this will trigger // then don't reset retry attempts because we this will trigger
// an automatic retry attempt when 'Tune' button is selected. We want the // an automatic retry attempt when 'Tune' button is selected. We want the
@ -860,7 +884,7 @@ StepStatus MMU2::LogicStep(bool reportErrors) {
case Finished: case Finished:
// At this point it is safe to trigger a runout and not interrupt the MMU protocol // At this point it is safe to trigger a runout and not interrupt the MMU protocol
CheckFINDARunout(); CheckFINDARunout();
break; [[fallthrough]]; // let Finished be reported the same way like Processing
case Processing: case Processing:
OnMMUProgressMsg(logic.Progress()); OnMMUProgressMsg(logic.Progress());
@ -920,15 +944,17 @@ void MMU2::filament_ramming() {
execute_extruder_sequence(ramming_sequence, sizeof(ramming_sequence) / sizeof(E_Step)); execute_extruder_sequence(ramming_sequence, sizeof(ramming_sequence) / sizeof(E_Step));
} }
void MMU2::execute_extruder_sequence(const E_Step *sequence, uint8_t steps) { void MMU2::execute_extruder_sequence(const E_Step *sequence, uint8_t stepCount) {
planner_synchronize(); planner_synchronize();
const E_Step *step = sequence; // Plan the moves
for (uint8_t i = steps; i > 0; --i) { for (const E_Step *step = sequence, *end = sequence + stepCount; step != end; step++) {
extruder_move(pgm_read_float(&(step->extrude)), pgm_read_float(&(step->feedRate))); extruder_move(pgm_read_float(&(step->extrude)), pgm_read_float(&(step->feedRate)));
step++;
} }
planner_synchronize(); // it looks like it's better to sync the moves at the end - smoother move (if the sequence is not too long).
// Wait for the moves to finish
// it looks like it's better to sync the moves at the end - smoother move (if the sequence is not too long).
planner_synchronize();
Disable_E0(); Disable_E0();
} }
@ -1079,14 +1105,10 @@ void MMU2::OnMMUProgressMsgSame(ProgressCode pc) {
case FilamentState::AT_FSENSOR: case FilamentState::AT_FSENSOR:
// fsensor triggered, finish FeedingToExtruder state // fsensor triggered, finish FeedingToExtruder state
loadFilamentStarted = false; loadFilamentStarted = false;
// Abort any excess E-move from the planner queue
planner_abort_queued_moves(); planner_abort_queued_moves();
{
// After the MMU knows the FSENSOR is triggered it will:
// 1. Push the filament by additional 30mm (see fsensorToNozzle)
// 2. Disengage the idler and push another 2mm.
extruder_move(logic.ExtraLoadDistance() + 2, logic.PulleySlowFeedRate()); extruder_move(logic.ExtraLoadDistance() + 2, logic.PulleySlowFeedRate());
}
break; break;
case FilamentState::NOT_PRESENT: case FilamentState::NOT_PRESENT:
// fsensor not triggered, continue moving extruder // fsensor not triggered, continue moving extruder

View File

@ -11,6 +11,7 @@ typedef float feedRate_t;
#else #else
#include "protocol_logic.h" #include "protocol_logic.h"
#include <atomic> #include <atomic>
#include <memory>
#endif #endif
struct E_Step; struct E_Step;
@ -32,6 +33,7 @@ struct Version {
class MMU2 { class MMU2 {
public: public:
MMU2(); MMU2();
~MMU2();
/// Powers ON the MMU, then initializes the UART and protocol logic /// Powers ON the MMU, then initializes the UART and protocol logic
void Start(); void Start();
@ -273,7 +275,9 @@ private:
StepStatus LogicStep(bool reportErrors); StepStatus LogicStep(bool reportErrors);
void filament_ramming(); void filament_ramming();
void execute_extruder_sequence(const E_Step *sequence, uint8_t steps);
void execute_extruder_sequence(const E_Step *sequence, uint8_t stepCount);
void execute_load_to_nozzle_sequence(); void execute_load_to_nozzle_sequence();
/// Reports an error into attached ExtUIs /// Reports an error into attached ExtUIs
@ -343,6 +347,7 @@ private:
void SetCurrentTool(uint8_t ex); void SetCurrentTool(uint8_t ex);
ProtocolLogic logic; ///< implementation of the protocol logic layer ProtocolLogic logic; ///< implementation of the protocol logic layer
uint8_t extruder; ///< currently active slot in the MMU ... somewhat... not sure where to get it from yet uint8_t extruder; ///< currently active slot in the MMU ... somewhat... not sure where to get it from yet
uint8_t tool_change_extruder; ///< only used for UI purposes uint8_t tool_change_extruder; ///< only used for UI purposes

View File

@ -29,7 +29,7 @@ static constexpr uint8_t FindErrorIndex(uint16_t pec) {
return (i != errorCodesEnd) ? (i-errorCodes) : (errorCodesSize - 1); return (i != errorCodesEnd) ? (i-errorCodes) : (errorCodesSize - 1);
} }
// check that the searching algoritm works // check that the searching algorithm works
static_assert(FindErrorIndex(ERR_MECHANICAL_FINDA_DIDNT_TRIGGER) == 0); static_assert(FindErrorIndex(ERR_MECHANICAL_FINDA_DIDNT_TRIGGER) == 0);
static_assert(FindErrorIndex(ERR_MECHANICAL_FINDA_FILAMENT_STUCK) == 1); static_assert(FindErrorIndex(ERR_MECHANICAL_FINDA_FILAMENT_STUCK) == 1);
static_assert(FindErrorIndex(ERR_MECHANICAL_FSENSOR_DIDNT_TRIGGER) == 2); static_assert(FindErrorIndex(ERR_MECHANICAL_FSENSOR_DIDNT_TRIGGER) == 2);
@ -96,68 +96,90 @@ uint8_t PrusaErrorCodeIndex(ErrorCode ec) {
return FindErrorIndex(ERR_SYSTEM_UNLOAD_MANUALLY); return FindErrorIndex(ERR_SYSTEM_UNLOAD_MANUALLY);
case ErrorCode::MCU_UNDERVOLTAGE_VCC: case ErrorCode::MCU_UNDERVOLTAGE_VCC:
return FindErrorIndex(ERR_ELECTRICAL_MMU_MCU_ERROR); return FindErrorIndex(ERR_ELECTRICAL_MMU_MCU_ERROR);
default: break; default:
break;
} }
// Electrical issues which can be detected somehow. // Electrical issues which can be detected somehow.
// Need to be placed before TMC-related errors in order to process couples of error bits between single ones // Need to be placed before TMC-related errors in order to process couples of error bits between single ones
// and to keep the code size down. // and to keep the code size down.
if (ContainsBit(ec, ErrorCode::TMC_PULLEY_BIT)) { if (ContainsBit(ec, ErrorCode::TMC_PULLEY_BIT)) {
if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) {
return FindErrorIndex(ERR_ELECTRICAL_MMU_PULLEY_SELFTEST_FAILED); return FindErrorIndex(ERR_ELECTRICAL_MMU_PULLEY_SELFTEST_FAILED);
}
} else if (ContainsBit(ec, ErrorCode::TMC_SELECTOR_BIT)) { } else if (ContainsBit(ec, ErrorCode::TMC_SELECTOR_BIT)) {
if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) {
return FindErrorIndex(ERR_ELECTRICAL_MMU_SELECTOR_SELFTEST_FAILED); return FindErrorIndex(ERR_ELECTRICAL_MMU_SELECTOR_SELFTEST_FAILED);
}
} else if (ContainsBit(ec, ErrorCode::TMC_IDLER_BIT)) { } else if (ContainsBit(ec, ErrorCode::TMC_IDLER_BIT)) {
if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) if ((ec & ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) == ErrorCode::MMU_SOLDERING_NEEDS_ATTENTION) {
return FindErrorIndex(ERR_ELECTRICAL_MMU_IDLER_SELFTEST_FAILED); return FindErrorIndex(ERR_ELECTRICAL_MMU_IDLER_SELFTEST_FAILED);
} }
}
// TMC-related errors - multiple of these can occur at once // TMC-related errors - multiple of these can occur at once
// - in such a case we report the first which gets found/converted into Prusa-Error-Codes (usually the fact, that one TMC has an issue is serious enough) // - in such a case we report the first which gets found/converted into Prusa-Error-Codes (usually the fact, that one TMC has an issue is serious enough)
// By carefully ordering the checks here we can prioritize the errors being reported to the user. // By carefully ordering the checks here we can prioritize the errors being reported to the user.
if (ContainsBit(ec, ErrorCode::TMC_PULLEY_BIT)) { if (ContainsBit(ec, ErrorCode::TMC_PULLEY_BIT)) {
if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH)) if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_DRIVER_ERROR); return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_DRIVER_ERROR);
if (ContainsBit(ec, ErrorCode::TMC_RESET)) }
if (ContainsBit(ec, ErrorCode::TMC_RESET)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_DRIVER_RESET); return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_DRIVER_RESET);
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP)) }
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_UNDERVOLTAGE_ERROR); return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_UNDERVOLTAGE_ERROR);
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND)) }
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_DRIVER_SHORTED); return FindErrorIndex(ERR_ELECTRICAL_TMC_PULLEY_DRIVER_SHORTED);
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN)) }
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN)) {
return FindErrorIndex(ERR_TEMPERATURE_WARNING_TMC_PULLEY_TOO_HOT); return FindErrorIndex(ERR_TEMPERATURE_WARNING_TMC_PULLEY_TOO_HOT);
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR)) }
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR)) {
return FindErrorIndex(ERR_TEMPERATURE_TMC_PULLEY_OVERHEAT_ERROR); return FindErrorIndex(ERR_TEMPERATURE_TMC_PULLEY_OVERHEAT_ERROR);
}
} else if (ContainsBit(ec, ErrorCode::TMC_SELECTOR_BIT)) { } else if (ContainsBit(ec, ErrorCode::TMC_SELECTOR_BIT)) {
if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH)) if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_DRIVER_ERROR); return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_DRIVER_ERROR);
if (ContainsBit(ec, ErrorCode::TMC_RESET)) }
if (ContainsBit(ec, ErrorCode::TMC_RESET)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_DRIVER_RESET); return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_DRIVER_RESET);
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP)) }
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_UNDERVOLTAGE_ERROR); return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_UNDERVOLTAGE_ERROR);
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND)) }
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_DRIVER_SHORTED); return FindErrorIndex(ERR_ELECTRICAL_TMC_SELECTOR_DRIVER_SHORTED);
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN)) }
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN)) {
return FindErrorIndex(ERR_TEMPERATURE_WARNING_TMC_SELECTOR_TOO_HOT); return FindErrorIndex(ERR_TEMPERATURE_WARNING_TMC_SELECTOR_TOO_HOT);
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR)) }
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR)) {
return FindErrorIndex(ERR_TEMPERATURE_TMC_SELECTOR_OVERHEAT_ERROR); return FindErrorIndex(ERR_TEMPERATURE_TMC_SELECTOR_OVERHEAT_ERROR);
}
} else if (ContainsBit(ec, ErrorCode::TMC_IDLER_BIT)) { } else if (ContainsBit(ec, ErrorCode::TMC_IDLER_BIT)) {
if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH)) if (ContainsBit(ec, ErrorCode::TMC_IOIN_MISMATCH)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_DRIVER_ERROR); return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_DRIVER_ERROR);
if (ContainsBit(ec, ErrorCode::TMC_RESET)) }
if (ContainsBit(ec, ErrorCode::TMC_RESET)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_DRIVER_RESET); return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_DRIVER_RESET);
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP)) }
if (ContainsBit(ec, ErrorCode::TMC_UNDERVOLTAGE_ON_CHARGE_PUMP)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_UNDERVOLTAGE_ERROR); return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_UNDERVOLTAGE_ERROR);
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND)) }
if (ContainsBit(ec, ErrorCode::TMC_SHORT_TO_GROUND)) {
return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_DRIVER_SHORTED); return FindErrorIndex(ERR_ELECTRICAL_TMC_IDLER_DRIVER_SHORTED);
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN)) }
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_WARN)) {
return FindErrorIndex(ERR_TEMPERATURE_WARNING_TMC_IDLER_TOO_HOT); return FindErrorIndex(ERR_TEMPERATURE_WARNING_TMC_IDLER_TOO_HOT);
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR)) }
if (ContainsBit(ec, ErrorCode::TMC_OVER_TEMPERATURE_ERROR)) {
return FindErrorIndex(ERR_TEMPERATURE_TMC_IDLER_OVERHEAT_ERROR); return FindErrorIndex(ERR_TEMPERATURE_TMC_IDLER_OVERHEAT_ERROR);
} }
}
// if nothing got caught, return a generic runtime error // if nothing got caught, return a generic error
return FindErrorIndex(ERR_OTHER_UNKNOWN_ERROR); return FindErrorIndex(ERR_OTHER_UNKNOWN_ERROR);
} }
@ -193,7 +215,6 @@ Buttons ButtonPressed(ErrorCode ec) {
const auto result = ButtonAvailable(ec); const auto result = ButtonAvailable(ec);
buttonSelectedOperation = ButtonOperations::NoOperation; // Reset operation buttonSelectedOperation = ButtonOperations::NoOperation; // Reset operation
return result; return result;
} }

View File

@ -28,6 +28,7 @@ void extruder_schedule_turning(float feed_rate);
float move_raise_z(float delta); float move_raise_z(float delta);
void planner_abort_queued_moves(); void planner_abort_queued_moves();
bool planner_draining();
void planner_synchronize(); void planner_synchronize();
bool planner_any_moves(); bool planner_any_moves();
float stepper_get_machine_position_E_mm(); float stepper_get_machine_position_E_mm();

View File

@ -38,6 +38,10 @@ void planner_abort_queued_moves() {
planner_aborted = false; planner_aborted = false;
} }
bool planner_draining() {
return planner_aborted;
}
void planner_synchronize() { void planner_synchronize() {
st_synchronize(); st_synchronize();
} }
@ -84,7 +88,6 @@ void nozzle_park() {
} }
bool marlin_printingIsActive() { bool marlin_printingIsActive() {
// return IS_SD_PRINTING || usb_timer_running();
return printer_active(); return printer_active();
} }
@ -92,13 +95,13 @@ void marlin_manage_heater(){
manage_heater(); manage_heater();
} }
void marlin_manage_inactivity(bool b){ void marlin_manage_inactivity(bool ignore_stepper_queue) {
manage_inactivity(b); manage_inactivity(ignore_stepper_queue);
} }
void marlin_idle(bool b){ void marlin_idle(bool ignore_stepper_queue) {
manage_heater(); manage_heater();
manage_inactivity(b); manage_inactivity(ignore_stepper_queue);
} }
void marlin_refresh_print_state_in_ram() { void marlin_refresh_print_state_in_ram() {
@ -133,8 +136,13 @@ void safe_delay_keep_alive(uint16_t t) {
delay_keep_alive(t); delay_keep_alive(t);
} }
void Enable_E0(){ enable_e0(); } void Enable_E0() {
void Disable_E0(){ disable_e0(); } enable_e0();
}
void Disable_E0() {
disable_e0();
}
bool all_axes_homed() { bool all_axes_homed() {
return axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]; return axis_known_position[X_AXIS] && axis_known_position[Y_AXIS];

View File

@ -1,4 +1,4 @@
/// @file /// @file mmu2_protocol.cpp
#include "mmu2_protocol.h" #include "mmu2_protocol.h"
// protocol definition // protocol definition
@ -112,11 +112,8 @@ DecodeStatus Protocol::DecodeRequest(uint8_t c) {
rqState = RequestStates::Code; rqState = RequestStates::Code;
return DecodeStatus::MessageCompleted; return DecodeStatus::MessageCompleted;
} }
} else {
requestMsg.code = RequestMsgCodes::unknown;
rqState = RequestStates::Error;
return DecodeStatus::Error;
} }
[[fallthrough]];
default: //case error: default: //case error:
if (IsNewLine(c)) { if (IsNewLine(c)) {
rqState = RequestStates::Code; rqState = RequestStates::Code;
@ -331,7 +328,7 @@ uint8_t Protocol::UInt8ToHex(uint8_t value, uint8_t *dst) {
return charsOut; return charsOut;
} }
uint8_t Protocol::UInt16ToHex(uint16_t value, uint8_t *dst) { uint8_t __attribute__((noinline)) Protocol::UInt16ToHex(uint16_t value, uint8_t *dst) {
constexpr uint16_t topNibbleMask = 0xf000; constexpr uint16_t topNibbleMask = 0xf000;
if (value == 0) { if (value == 0) {
*dst = '0'; *dst = '0';

View File

@ -1,4 +1,4 @@
/// @file protocol.h /// @file mmu2_protocol.h
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "mmu2_crc.h" #include "mmu2_crc.h"
@ -8,6 +8,7 @@ namespace modules {
/// @brief The MMU communication protocol implementation and related stuff. /// @brief The MMU communication protocol implementation and related stuff.
/// ///
/// See description of the new protocol in the MMU 2021 doc /// See description of the new protocol in the MMU 2021 doc
namespace protocol { namespace protocol {
/// Definition of request message codes /// Definition of request message codes
@ -179,17 +180,9 @@ public:
/// @returns number of bytes written into txbuff /// @returns number of bytes written into txbuff
static uint8_t EncodeResponseReadFINDA(const RequestMsg &msg, uint8_t findaValue, uint8_t *txbuff); static uint8_t EncodeResponseReadFINDA(const RequestMsg &msg, uint8_t findaValue, uint8_t *txbuff);
/// Encode response to Query operation status /// Encode response to Query operation status
/// @param msg source request message for this response /// @param msg source request message for this response
/// @param code status of operation (Processing, Error, Finished) /// @param rcs status of operation (Processing, Error, Finished)
/// @param value related to status of operation(e.g. error code or progress)
/// @param txbuff where to format the message /// @param txbuff where to format the message
/// @returns number of bytes written into txbuff /// @returns number of bytes written into txbuff
static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseCommandStatus rcs, uint8_t *txbuff); static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseCommandStatus rcs, uint8_t *txbuff);

View File

@ -267,6 +267,8 @@ StepStatus ProtocolLogic::ScopeStep() {
if (!ExpectsResponse()) { if (!ExpectsResponse()) {
// we are waiting for something // we are waiting for something
switch (currentScope) { switch (currentScope) {
case Scope::StartSeq:
return Processing;
case Scope::DelayedRestart: case Scope::DelayedRestart:
return DelayedRestartWait(); return DelayedRestartWait();
case Scope::Idle: case Scope::Idle:
@ -280,8 +282,9 @@ StepStatus ProtocolLogic::ScopeStep() {
} }
} else { } else {
// we are expecting a message // we are expecting a message
if (auto expmsg = ExpectingMessage(); expmsg != MessageReady) // this whole statement takes 12B if (auto expmsg = ExpectingMessage(); expmsg != MessageReady) { // this whole statement takes 12B
return expmsg; return expmsg;
}
// process message // process message
switch (currentScope) { switch (currentScope) {
@ -723,8 +726,9 @@ void ProtocolLogic::FormatLastResponseMsgAndClearLRB(char *dst) {
for (uint8_t i = 0; i < lrb; ++i) { for (uint8_t i = 0; i < lrb; ++i) {
uint8_t b = lastReceivedBytes[i]; uint8_t b = lastReceivedBytes[i];
// Check for printable character, including space // Check for printable character, including space
if (b < 32 || b > 127) if (b < 32 || b > 127) {
b = '.'; b = '.';
}
*dst++ = b; *dst++ = b;
} }
*dst = 0; // terminate properly *dst = 0; // terminate properly
@ -738,8 +742,9 @@ void ProtocolLogic::LogRequestMsg(const uint8_t *txbuff, uint8_t size) {
for (uint8_t i = 0; i < size; ++i) { for (uint8_t i = 0; i < size; ++i) {
uint8_t b = txbuff[i]; uint8_t b = txbuff[i];
// Check for printable character, including space // Check for printable character, including space
if (b < 32 || b > 127) if (b < 32 || b > 127) {
b = '.'; b = '.';
}
tmp[i + 1] = b; tmp[i + 1] = b;
} }
tmp[size + 1] = 0; tmp[size + 1] = 0;
@ -845,8 +850,9 @@ StepStatus ProtocolLogic::Step() {
} }
uint8_t ProtocolLogic::CommandInProgress() const { uint8_t ProtocolLogic::CommandInProgress() const {
if (currentScope != Scope::Command) if (currentScope != Scope::Command) {
return 0; return 0;
}
return (uint8_t)ReqMsg().code; return (uint8_t)ReqMsg().code;
} }
@ -862,7 +868,7 @@ void ProtocolLogic::ResetRetryAttempts() {
retryAttempts = MAX_RETRIES; retryAttempts = MAX_RETRIES;
} }
void __attribute__((noinline)) ProtocolLogic::ResetCommunicationTimeoutAttempts() { void ProtocolLogic::ResetCommunicationTimeoutAttempts() {
SERIAL_ECHOLNPGM("RSTCommTimeout"); SERIAL_ECHOLNPGM("RSTCommTimeout");
dataTO.Reset(); dataTO.Reset();
} }

View File

@ -13,9 +13,12 @@ namespace MMU2 {
/// When the printer's FW starts, the MMU mode is either Stopped or NotResponding (based on user's preference). /// When the printer's FW starts, the MMU mode is either Stopped or NotResponding (based on user's preference).
/// When the MMU successfully establishes communication, the state changes to Active. /// When the MMU successfully establishes communication, the state changes to Active.
enum class xState : uint_fast8_t { enum class xState : uint_fast8_t {
/// The user doesn't want the printer to work with the MMU. The MMU itself is not powered and does not work at all.
/// !!! Must be 0 !!! marlin_vars.mmu2_state is set to 0 if not active
Stopped,
Active, ///< MMU has been detected, connected, communicates and is ready to be worked with. Active, ///< MMU has been detected, connected, communicates and is ready to be worked with.
Connecting, ///< MMU is connected but it doesn't communicate (yet). The user wants the MMU, but it is not ready to be worked with. Connecting, ///< MMU is connected but it doesn't communicate (yet). The user wants the MMU, but it is not ready to be worked with.
Stopped ///< The user doesn't want the printer to work with the MMU. The MMU itself is not powered and does not work at all.
}; };
} // namespace MMU2 } // namespace MMU2