diff --git a/Firmware/mmu2.cpp b/Firmware/mmu2.cpp index 3c837d100..41071cdb2 100644 --- a/Firmware/mmu2.cpp +++ b/Firmware/mmu2.cpp @@ -275,29 +275,49 @@ bool MMU2::VerifyFilamentEnteredPTFE() void MMU2::ToolChangeCommon(uint8_t slot){ for(;;) { // while not successfully fed into extruder's PTFE tube - for(;;) { - tool_change_extruder = slot; - logic.ToolChange(slot); // let the MMU pull the filament out and push a new one in - if( manage_response(true, true) ) + uint8_t retries = 3; + for(/*nothing*/; retries; --retries){ + for(;;) { + tool_change_extruder = slot; + logic.ToolChange(slot); // let the MMU pull the filament out and push a new one in + if( manage_response(true, true) ) + break; + // otherwise: failed to perform the command - unload first and then let it run again + IncrementMMUFails(); + + // just in case we stood in an error screen for too long and the hotend got cold + ResumeHotendTemp(); + // if the extruder has been parked, it will get unparked once the ToolChange command finishes OK + // - so no ResumeUnpark() at this spot + + unload(); + // if we run out of retries, we must do something ... may be raise an error screen and allow the user to do something + // but honestly - if the MMU restarts during every toolchange, + // something else is seriously broken and stopping a print is probably our best option. + } + // reset current position to whatever the planner thinks it is + plan_set_e_position(current_position[E_AXIS]); + if (VerifyFilamentEnteredPTFE()){ break; - // otherwise: failed to perform the command - unload first and then let it run again - IncrementMMUFails(); - - // just in case we stood in an error screen for too long and the hotend got cold - ResumeHotendTemp(); - // if the extruder has been parked, it will get unparked once the ToolChange command finishes OK - // - so no ResumeUnpark() at this spot - - unload(); - // if we run out of retries, we must do something ... may be raise an error screen and allow the user to do something - // but honestly - if the MMU restarts during every toolchange, - // something else is seriously broken and stopping a print is probably our best option. + } else { // Prepare a retry attempt + unload(); // @@TODO cut filament + // cut_filament(slot); + } } - // reset current position to whatever the planner thinks it is - plan_set_e_position(current_position[E_AXIS]); - if (VerifyFilamentEnteredPTFE()) break; - else { // Prepare a retry attempt - unload(); // TODO cut filament + if( retries ){ + // we were successful in pushing the filament into the nozzle + break; + } else { + // failed autoretry, report an error by forcing a "printer" error into the MMU infrastructure - it is a hack to leverage existing code + logic.SetPrinterError(ErrorCode::TRY_LOAD_UNLOAD_FAILED); + SaveAndPark(true); + SaveHotendTemp(true); + // We only have to wait for the user to fix the issue and press "Retry". + // @@TODO Do we need to process the return value of manage_response? + manage_response(true, true); + logic.ClearPrinterError(); + ResumeHotendTemp(); + ResumeUnpark(); } } @@ -747,6 +767,7 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { // now what :D ... big bad ... ramming, unload, retry the whole command originally issued return false; case VersionMismatch: // this basically means the MMU will be disabled until reconnected + case PrinterError: CheckUserInput(); return true; case CommandError: @@ -810,6 +831,9 @@ StepStatus MMU2::LogicStep(bool reportErrors) { StopKeepPowered(); ReportError(ErrorCode::VERSION_MISMATCH, ErrorSourcePrinter); break; + case PrinterError: + ReportError(logic.PrinterError(), ErrorSourcePrinter); + break; default: break; } diff --git a/Firmware/mmu2/error_codes.h b/Firmware/mmu2/error_codes.h index 7f1478f9a..902a8ae17 100644 --- a/Firmware/mmu2/error_codes.h +++ b/Firmware/mmu2/error_codes.h @@ -56,6 +56,7 @@ enum class ErrorCode : uint_fast16_t { QUEUE_FULL = 0x802b, ///< E32811 internal logic error - attempt to move with a full queue + TRY_LOAD_UNLOAD_FAILED = 0x802b, ///< E32811 internal error of the printer - try-load-unload sequence detected missing filament -> failed load into the nozzle VERSION_MISMATCH = 0x802c, ///< E32812 internal error of the printer - incompatible version of the MMU FW PROTOCOL_ERROR = 0x802d, ///< E32813 internal error of the printer - communication with the MMU got garbled - protocol decoder couldn't decode the incoming messages MMU_NOT_RESPONDING = 0x802e, ///< E32814 internal error of the printer - communication with the MMU is not working diff --git a/Firmware/mmu2_protocol_logic.cpp b/Firmware/mmu2_protocol_logic.cpp index ba898fdd3..67f59d317 100644 --- a/Firmware/mmu2_protocol_logic.cpp +++ b/Firmware/mmu2_protocol_logic.cpp @@ -800,7 +800,8 @@ StepStatus ProtocolLogic::Step() { default: break; } - return currentStatus; + // special handling of explicit printer errors + return IsPrinterError() ? StepStatus::PrinterError : currentStatus; } uint8_t ProtocolLogic::CommandInProgress() const { diff --git a/Firmware/mmu2_protocol_logic.h b/Firmware/mmu2_protocol_logic.h index 184f6f866..7a10125d0 100644 --- a/Firmware/mmu2_protocol_logic.h +++ b/Firmware/mmu2_protocol_logic.h @@ -40,6 +40,7 @@ enum StepStatus : uint_fast8_t { CommandRejected, ///< the MMU rejected the command due to some other command in progress, may be the user is operating the MMU locally (button commands) CommandError, ///< the command in progress stopped due to unrecoverable error, user interaction required VersionMismatch, ///< the MMU reports its firmware version incompatible with our implementation + PrinterError, ///< printer's explicit error - MMU is fine, but the printer was unable to complete the requested operation CommunicationRecovered, ButtonPushed, ///< The MMU reported the user pushed one of its three buttons. }; @@ -141,6 +142,19 @@ public: inline uint8_t MmuFwVersionRevision() const { return mmuFwVersion[2]; } + + inline void SetPrinterError(ErrorCode ec){ + explicitPrinterError = ec; + } + inline void ClearPrinterError(){ + explicitPrinterError = ErrorCode::OK; + } + inline bool IsPrinterError()const { + return explicitPrinterError != ErrorCode::OK; + } + inline ErrorCode PrinterError() const { + return explicitPrinterError; + } #ifndef UNITTEST private: #endif @@ -162,6 +176,8 @@ private: StepStatus SwitchFromIdleToCommand(); void SwitchFromStartToIdle(); + ErrorCode explicitPrinterError; + enum class State : uint_fast8_t { Stopped, ///< stopped for whatever reason InitSequence, ///< initial sequence running