Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MMU maintenance: Sync with 32-bit FW a little bit #4647

Merged
merged 6 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 68 additions & 43 deletions Firmware/mmu2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void waitForHotendTargetTemp(uint16_t delay, F f) {
}

void WaitForHotendTargetTempBeep() {
waitForHotendTargetTemp(3000, []{ });
waitForHotendTargetTemp(200, [] {});
MakeSound(Prompt);
}

Expand Down Expand Up @@ -73,14 +73,17 @@ void MMU2::Start() {
mmu2Serial.flush(); // make sure the UART buffer is clear before starting communication

SetCurrentTool(MMU2_NO_TOOL);
state = xState::Connecting;

// start the communication
logic.Start();
logic.ResetRetryAttempts();
logic.ResetCommunicationTimeoutAttempts();

state = xState::Connecting;
logic.Start();
}

MMU2::~MMU2() {}

void MMU2::Stop() {
StopKeepPowered();
PowerOff();
Expand Down Expand Up @@ -153,8 +156,9 @@ void MMU2::PowerOn() {
}

bool MMU2::ReadRegister(uint8_t address) {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}
do {
logic.ReadRegister(address); // we may signal the accepted/rejected status of the response as return value of this function
} while (!manage_response(false, false));
Expand All @@ -165,8 +169,9 @@ bool MMU2::ReadRegister(uint8_t address) {
}

bool __attribute__((noinline)) MMU2::WriteRegister(uint8_t address, uint16_t data) {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}

// special cases - intercept requests of registers which influence the printer's behaviour too + perform the change even on the printer's side
switch (address) {
Expand All @@ -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,
// so thread safety should be kept
static bool avoidRecursion = false;
if (avoidRecursion)
if (avoidRecursion) {
return;
}
avoidRecursion = true;

mmu_loop_inner(true);

avoidRecursion = false;
}

Expand All @@ -208,7 +212,7 @@ void __attribute__((noinline)) MMU2::mmu_loop_inner(bool reportErrors) {

void MMU2::CheckFINDARunout() {
// 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!");
marlin_stop_and_save_print_to_ram();
restore_print_from_ram_and_continue(0);
Expand Down Expand Up @@ -301,8 +305,12 @@ bool MMU2::VerifyFilamentEnteredPTFE() {
filament_inserted = filament_inserted && (WhereIsFilament() == FilamentState::AT_FSENSOR);
tlur.Progress(filament_inserted);
safe_delay_keep_alive(0);
if (planner_draining()) {
return false; // power panic or a similar issue happened, bail out fast
}
}
}

Disable_E0();
if (!filament_inserted) {
IncrementLoadFails();
Expand All @@ -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
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))
if (manage_response(true, true)) {
break;
}
// otherwise: failed to perform the command - unload first and then let it run again
IncrementMMUFails();

Expand All @@ -335,7 +344,7 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot) {
}
if (VerifyFilamentEnteredPTFE()) {
return true; // success
} else { // Prepare a retry attempt
} else { // Prepare a retry attempt
UnloadInner();
if (retries == 2 && cutter_enabled()) {
CutFilamentInner(slot); // try cutting filament tip at the last attempt
Expand All @@ -347,6 +356,9 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot) {

void MMU2::ToolChangeCommon(uint8_t slot) {
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
// @@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);
Expand All @@ -357,15 +369,16 @@ void MMU2::ToolChangeCommon(uint8_t slot) {
static_cast<void>(manage_response(true, true)); // yes, I'd like to silence [[nodiscard]] warning at this spot by casting to void
}

SetCurrentTool(slot); //filament change is finished
SetCurrentTool(slot); // filament change is finished
SpoolJoin::spooljoin.setSlot(slot);

++toolchange_counter;
}

bool MMU2::tool_change(uint8_t slot) {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}

if (slot != extruder) {
if (/*FindaDetectsFilament()*/
Expand All @@ -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.
///- 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) {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}

FSensorBlockRunout blockRunout;

Expand Down Expand Up @@ -435,8 +449,9 @@ void MMU2::SetCurrentTool(uint8_t ex){
}

bool MMU2::set_filament_type(uint8_t /*slot*/, uint8_t /*type*/) {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}

// @@TODO - this is not supported in the new MMU yet
// slot = slot; // @@TODO
Expand All @@ -461,8 +476,9 @@ void MMU2::UnloadInner() {
for (;;) {
Disable_E0();
logic.UnloadFilament();
if (manage_response(false, true))
if (manage_response(false, true)) {
break;
}
IncrementMMUFails();
}
MakeSound(Confirm);
Expand All @@ -473,15 +489,17 @@ void MMU2::UnloadInner() {
}

bool MMU2::unload() {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}

WaitForHotendTargetTempBeep();

{
ReportingRAII rep(CommandInProgress::UnloadFilament);
UnloadInner();
}

ScreenUpdateEnable();
return true;
}
Expand All @@ -490,15 +508,17 @@ void MMU2::CutFilamentInner(uint8_t slot) {
for (;;) {
Disable_E0();
logic.CutFilament(slot);
if (manage_response(false, true))
if (manage_response(false, true)) {
break;
}
IncrementMMUFails();
}
}

bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /*= true*/) {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}

if (enableFullScreenMsg) {
FullScreenMsgCut(slot);
Expand Down Expand Up @@ -528,17 +548,19 @@ bool MMU2::loading_test(uint8_t slot) {
}

bool MMU2::load_filament(uint8_t slot) {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}

FullScreenMsgLoad(slot);
{
ReportingRAII rep(CommandInProgress::LoadFilament);
for (;;) {
Disable_E0();
logic.LoadFilament(slot);
if (manage_response(false, false))
if (manage_response(false, false)) {
break;
}
IncrementMMUFails();
}
MakeSound(SoundType::Confirm);
Expand All @@ -548,8 +570,9 @@ bool MMU2::load_filament(uint8_t slot) {
}

bool MMU2::load_filament_to_nozzle(uint8_t slot) {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}

WaitForHotendTargetTempBeep();

Expand All @@ -574,8 +597,9 @@ bool MMU2::load_filament_to_nozzle(uint8_t slot) {
}

bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
if (!WaitForMMUReady())
if (!WaitForMMUReady()) {
return false;
}

if (enableFullScreenMsg) {
FullScreenMsgEject(slot);
Expand All @@ -589,8 +613,9 @@ bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
for (;;) {
Disable_E0();
logic.EjectFilament(slot);
if (manage_response(false, true))
if (manage_response(false, true)) {
break;
}
IncrementMMUFails();
}
SetCurrentTool(MMU2_NO_TOOL);
Expand All @@ -611,8 +636,9 @@ void MMU2::Home(uint8_t mode) {
}

void MMU2::SaveHotendTemp(bool turn_off_nozzle) {
if (mmu_print_saved & SavedState::Cooldown)
if (mmu_print_saved & SavedState::Cooldown) {
return;
}

if (turn_off_nozzle && !(mmu_print_saved & SavedState::CooldownPending)) {
Disable_E0();
Expand Down Expand Up @@ -701,8 +727,7 @@ void MMU2::CheckUserInput() {
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
// the error screen should always be dismissed.
ClearPrinterError();
Expand All @@ -720,7 +745,7 @@ void MMU2::CheckUserInput() {
SERIAL_ECHOLN((int)buttons_to_uint8t(btn));
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
Button(buttons_to_uint8t(btn));
}
Expand Down Expand Up @@ -782,6 +807,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
// - finished ok -> proceed with reading other commands
safe_delay_keep_alive(0); // calls LogicStep() and remembers its return status
// also disables stepper motor unlocking

if (mmu_print_saved & SavedState::CooldownPending) {
if (!nozzleTimeout.running()) {
Expand All @@ -803,9 +829,8 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
// command/operation completed, let Marlin continue its work
// the E may have some more moves to finish - wait for them
ResumeHotendTemp();
ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved.
if (!TuneMenuEntered())
{
ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved.
if (!TuneMenuEntered()) {
// If the error screen is sleeping (running 'Tune' menu)
// then don't reset retry attempts because we this will trigger
// an automatic retry attempt when 'Tune' button is selected. We want the
Expand Down Expand Up @@ -860,7 +885,7 @@ StepStatus MMU2::LogicStep(bool reportErrors) {
case Finished:
// At this point it is safe to trigger a runout and not interrupt the MMU protocol
CheckFINDARunout();
break;
[[fallthrough]]; // let Finished be reported the same way like Processing
gudnimg marked this conversation as resolved.
Show resolved Hide resolved

case Processing:
OnMMUProgressMsg(logic.Progress());
Expand Down Expand Up @@ -920,15 +945,19 @@ void MMU2::filament_ramming() {
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();

// Plan the moves
const E_Step *step = sequence;
for (uint8_t i = steps; i > 0; --i) {
for (uint8_t i = stepCount; i > 0; --i) {
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();
}
Expand Down Expand Up @@ -1031,7 +1060,7 @@ void MMU2::OnMMUProgressMsgChanged(ProgressCode pc) {
switch (pc) {
case ProgressCode::UnloadingToFinda:
if ((CommandInProgress)logic.CommandInProgress() == CommandInProgress::UnloadFilament
|| ((CommandInProgress)logic.CommandInProgress() == CommandInProgress::ToolChange)) {
|| ((CommandInProgress)logic.CommandInProgress() == CommandInProgress::ToolChange)) {
// If MK3S sent U0 command, ramming sequence takes care of releasing the filament.
// If Toolchange is done while printing, PrusaSlicer takes care of releasing the filament
// If printing is not in progress, ToolChange will issue a U0 command.
Expand Down Expand Up @@ -1079,14 +1108,10 @@ void MMU2::OnMMUProgressMsgSame(ProgressCode pc) {
case FilamentState::AT_FSENSOR:
// fsensor triggered, finish FeedingToExtruder state
loadFilamentStarted = false;

// Abort any excess E-move from the planner queue
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;
case FilamentState::NOT_PRESENT:
// fsensor not triggered, continue moving extruder
Expand Down
Loading
Loading