diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h index 348b4d7f7..810203ea8 100755 --- a/Firmware/Marlin.h +++ b/Firmware/Marlin.h @@ -316,8 +316,9 @@ extern bool fan_state[2]; extern int fan_edge_counter[2]; extern int fan_speed[2]; -// Handling multiple extruders pins -extern uint8_t active_extruder; +// Active extruder becomes a #define to make the whole firmware compilable. +// We may even remove the references to it wherever possible in the future +#define active_extruder 0 //Long pause extern unsigned long pause_time; diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 923595f84..91e97c474 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -244,7 +244,6 @@ float extruder_offset[NUM_EXTRUDER_OFFSETS][EXTRUDERS] = { }; #endif -uint8_t active_extruder = 0; int fanSpeed=0; uint8_t newFanSpeed = 0; @@ -362,9 +361,7 @@ uint8_t saved_printing_type = PRINTING_TYPE_SD; static float saved_pos[4] = { X_COORD_INVALID, 0, 0, 0 }; static uint16_t saved_feedrate2 = 0; //!< Default feedrate (truncated from float) static int saved_feedmultiply2 = 0; -static uint8_t saved_active_extruder = 0; -float saved_extruder_temperature = 0.0; //!< Active extruder temperature -float saved_bed_temperature = 0.0; //!< Bed temperature +static float saved_extruder_temperature = 0.0; //!< Active extruder temperature static bool saved_extruder_relative_mode = false; int saved_fan_speed = 0; //!< Print fan speed //! @} @@ -11122,7 +11119,6 @@ void stop_and_save_print_to_ram(float z_move, float e_move) if (pos_invalid) saved_pos[X_AXIS] = X_COORD_INVALID; saved_feedmultiply2 = feedmultiply; //save feedmultiply - saved_active_extruder = active_extruder; //save active_extruder saved_extruder_temperature = degTargetHotend(active_extruder); saved_bed_temperature = degTargetBed(); saved_extruder_relative_mode = axis_relative_modes & E_AXIS_MASK; @@ -11171,11 +11167,11 @@ void stop_and_save_print_to_ram(float z_move, float e_move) } void restore_extruder_temperature_from_ram() { - if (degTargetHotend(saved_active_extruder) != saved_extruder_temperature) + if (degTargetHotend(active_extruder) != saved_extruder_temperature) { - setTargetHotendSafe(saved_extruder_temperature, saved_active_extruder); + setTargetHotendSafe(saved_extruder_temperature, active_extruder); heating_status = HeatingStatus::EXTRUDER_HEATING; - wait_for_heater(_millis(), saved_active_extruder); + wait_for_heater(_millis(), active_extruder); heating_status = HeatingStatus::EXTRUDER_HEATING_COMPLETE; } } @@ -11202,11 +11198,8 @@ void restore_print_from_ram_and_continue(float e_move) // restore bed temperature (bed can be disabled during a thermal warning) if (degBed() != saved_bed_temperature) setTargetBed(saved_bed_temperature); - - // restore active_extruder - active_extruder = saved_active_extruder; fanSpeed = saved_fan_speed; - restore_extruder_temperture_from_ram(); + restore_extruder_temperature_from_ram(); axis_relative_modes ^= (-saved_extruder_relative_mode ^ axis_relative_modes) & E_AXIS_MASK; float e = saved_pos[E_AXIS] - e_move; plan_set_e_position(e); diff --git a/Firmware/mmu2.cpp b/Firmware/mmu2.cpp index 34255892b..393982011 100644 --- a/Firmware/mmu2.cpp +++ b/Firmware/mmu2.cpp @@ -16,6 +16,10 @@ #include "ultralcd.h" #include "cardreader.h" // for IS_SD_PRINTING +// As of FW 3.12 we only support building the FW with only one extruder, all the multi-extruder infrastructure will be removed. +// Saves at least 800B of code size +static_assert(EXTRUDERS==1); + // Settings for filament load / unload from the LCD menu. // This is for Prusa MK3-style extruders. Customize for your hardware. #define MMU2_FILAMENTCHANGE_EJECT_FEED 80.0 @@ -281,7 +285,6 @@ bool MMU2::tool_change(uint8_t index) { extruder = index; //filament change is finished previous_extruder = extruder; - SetActiveExtruder(0); // @@TODO really report onto the serial? May be for the Octoprint? Not important now // SERIAL_ECHO_START(); @@ -315,7 +318,6 @@ bool MMU2::tool_change(char code, uint8_t slot) { manage_response(false, false); extruder = slot; previous_extruder = extruder; - SetActiveExtruder(0); set_extrude_min_temp(EXTRUDE_MINTEMP); } break; @@ -467,7 +469,6 @@ bool MMU2::load_filament_to_nozzle(uint8_t index) { extruder = index; previous_extruder = extruder; - SetActiveExtruder(0); Sound_MakeSound(e_SOUND_TYPE_StandardConfirm); } @@ -515,7 +516,7 @@ bool MMU2::eject_filament(uint8_t index, bool recover) { } void MMU2::Button(uint8_t index){ - SERIAL_ECHOLNPGM("Button"); + LogEchoEvent_P(PSTR("Button")); logic.Button(index); } @@ -525,7 +526,7 @@ void MMU2::Home(uint8_t mode){ void MMU2::SaveAndPark(bool move_axes, bool turn_off_nozzle) { if (mmu_print_saved == SavedState::None) { // First occurrence. Save current position, park print head, disable nozzle heater. - LogEchoEvent("Saving and parking"); + LogEchoEvent_P(PSTR("Saving and parking")); st_synchronize(); resume_hotend_temp = degTargetHotend(active_extruder); @@ -553,7 +554,7 @@ void MMU2::SaveAndPark(bool move_axes, bool turn_off_nozzle) { if (turn_off_nozzle){ mmu_print_saved |= SavedState::CooldownPending; - LogEchoEvent("Heater cooldown pending"); + LogEchoEvent_P(PSTR("Heater cooldown pending")); // This just sets the flag that we should timeout and shut off the nozzle in 30 minutes... //setAllTargetHotends(0); } @@ -568,10 +569,10 @@ void MMU2::ResumeHotendTemp() { { // Clear the "pending" flag if we haven't cooled yet. mmu_print_saved &= ~(SavedState::CooldownPending); - LogEchoEvent("Cooldown flag cleared"); + LogEchoEvent_P(PSTR("Cooldown flag cleared")); } if ((mmu_print_saved & SavedState::Cooldown) && resume_hotend_temp) { - LogEchoEvent("Resuming Temp"); + LogEchoEvent_P(PSTR("Resuming Temp")); MMU2_ECHO_MSG("Restoring hotend temperature "); SERIAL_ECHOLN(resume_hotend_temp); mmu_print_saved &= ~(SavedState::Cooldown); @@ -583,15 +584,14 @@ void MMU2::ResumeHotendTemp() { manage_inactivity(true); }); lcd_update_enable(true); // temporary hack to stop this locking the printer... - LogEchoEvent("Hotend temperature reached"); + LogEchoEvent_P(PSTR("Hotend temperature reached")); lcd_clear(); } } -void MMU2::ResumeUnpark() -{ +void MMU2::ResumeUnpark(){ if (mmu_print_saved & SavedState::ParkExtruder) { - LogEchoEvent("Resuming XYZ"); + LogEchoEvent_P(PSTR("Resuming XYZ")); current_position[X_AXIS] = resume_position.xyz[X_AXIS]; current_position[Y_AXIS] = resume_position.xyz[Y_AXIS]; @@ -609,11 +609,11 @@ void MMU2::CheckUserInput(){ auto btn = ButtonPressed((uint16_t)lastErrorCode); // Was a button pressed on the MMU itself instead of the LCD? - if (btn == Buttons::NoButton && lastButton != Buttons::NoButton) - { + if (btn == Buttons::NoButton && lastButton != Buttons::NoButton){ btn = lastButton; lastButton = Buttons::NoButton; // Clear it. } + switch (btn) { case Left: case Middle: @@ -662,25 +662,19 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { manage_inactivity(true); // calls LogicStep() and remembers its return status lcd_update(0); - if (mmu_print_saved & SavedState::CooldownPending) - { - if (!nozzleTimeout.running()) - { + if (mmu_print_saved & SavedState::CooldownPending){ + if (!nozzleTimeout.running()){ nozzleTimeout.start(); - LogEchoEvent("Cooling Timeout started"); - } - else if (nozzleTimeout.expired(DEFAULT_SAFETYTIMER_TIME_MINS*60*1000ul)) // mins->msec. TODO: do we use the global or have our own independent timeout - { + LogEchoEvent_P(PSTR("Cooling Timeout started")); + } else if (nozzleTimeout.expired(DEFAULT_SAFETYTIMER_TIME_MINS*60*1000ul)){ // mins->msec. TODO: do we use the global or have our own independent timeout mmu_print_saved &= ~(SavedState::CooldownPending); mmu_print_saved |= SavedState::Cooldown; setAllTargetHotends(0); - LogEchoEvent("Heater cooldown"); + LogEchoEvent_P(PSTR("Heater cooldown")); } - } - else if (nozzleTimeout.running()) - { + } else if (nozzleTimeout.running()) { nozzleTimeout.stop(); - LogEchoEvent("Cooling timer stopped"); + LogEchoEvent_P(PSTR("Cooling timer stopped")); } switch (logicStepLastStatus) { @@ -696,11 +690,10 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { return; case CommandError: // Don't proceed to the park/save if we are doing an autoretry. - if (inAutoRetry) - { + if (inAutoRetry){ continue; } - /* FALLTHRU */ + [[fallthrough]]; case CommunicationTimeout: case ProtocolError: SaveAndPark(move_axes, turn_off_nozzle); // and wait for the user to resolve the problem @@ -743,7 +736,7 @@ StepStatus MMU2::LogicStep() { break; case ButtonPushed: lastButton = logic.Button(); - LogEchoEvent("MMU Button pushed"); + LogEchoEvent_P(PSTR("MMU Button pushed")); CheckUserInput(); // Process the button immediately break; default: @@ -767,16 +760,10 @@ void MMU2::execute_extruder_sequence(const E_Step *sequence, uint8_t steps) { current_position[E_AXIS] += pgm_read_float(&(step->extrude)); plan_buffer_line_curposXYZE(pgm_read_float(&(step->feedRate))); st_synchronize(); -// SERIAL_ECHOPGM("EES:"); -// SERIAL_ECHOLN(position[E_AXIS]); step++; } } -void MMU2::SetActiveExtruder(uint8_t ex){ - active_extruder = ex; -} - void MMU2::ReportError(ErrorCode ec, uint8_t res) { // Due to a potential lossy error reporting layers linked to this hook // we'd better report everything to make sure especially the error states @@ -791,8 +778,7 @@ void MMU2::ReportError(ErrorCode ec, uint8_t res) { // Right now the filtering of MMU_NOT_RESPONDING is done in ReportErrorHook() as it is not a problem if mmu2.cpp // Depending on the Progress code, we may want to do some action when an error occurs - switch (logic.Progress()) - { + switch (logic.Progress()){ case ProgressCode::UnloadingToFinda: unloadFilamentStarted = false; break; @@ -808,8 +794,7 @@ void MMU2::ReportError(ErrorCode ec, uint8_t res) { if( ec != lastErrorCode ){ // deduplicate: only report changes in error codes into the log lastErrorCode = ec; - SERIAL_ECHO_START; - SERIAL_ECHOLNRPGM( _T(PrusaErrorTitle(PrusaErrorCodeIndex((uint16_t)ec))) ); + LogErrorEvent_P( _T(PrusaErrorTitle(PrusaErrorCodeIndex((uint16_t)ec))) ); } static_assert(mmu2Magic[0] == 'M' @@ -824,103 +809,89 @@ void MMU2::ReportError(ErrorCode ec, uint8_t res) { void MMU2::ReportProgress(ProgressCode pc) { ReportProgressHook((CommandInProgress)logic.CommandInProgress(), (uint16_t)pc); - - SERIAL_ECHO_START; - SERIAL_ECHOLNRPGM( _T(ProgressCodeToText((uint16_t)pc)) ); + LogEchoEvent_P( _T(ProgressCodeToText((uint16_t)pc)) ); } void MMU2::OnMMUProgressMsg(ProgressCode pc){ if (pc != lastProgressCode) { - ReportProgress(pc); - lastProgressCode = pc; - - // Act accordingly - one-time handling - switch (pc) { - case ProgressCode::UnloadingToFinda: - if ((CommandInProgress)logic.CommandInProgress() == CommandInProgress::UnloadFilament - || ((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. - break; - } - else - { - // We're likely recovering from an MMU error - st_synchronize(); - unloadFilamentStarted = true; - current_position[E_AXIS] -= MMU2_RETRY_UNLOAD_TO_FINDA_LENGTH; - plan_buffer_line_curposXYZE(MMU2_RETRY_UNLOAD_TO_FINDA_FEED_RATE); - } - break; - case ProgressCode::FeedingToFSensor: - // prepare for the movement of the E-motor - st_synchronize(); - loadFilamentStarted = true; - break; - default: - // do nothing yet - break; - } + OnMMUProgressMsgChanged(pc); } else { - // Act accordingly - every status change (even the same state) - switch (pc) { - case ProgressCode::UnloadingToFinda: - if (unloadFilamentStarted && !blocks_queued()) { // Only plan a move if there is no move ongoing - if (fsensor.getFilamentPresent() == 1) - { - current_position[E_AXIS] -= MMU2_RETRY_UNLOAD_TO_FINDA_LENGTH; - plan_buffer_line_curposXYZE(MMU2_RETRY_UNLOAD_TO_FINDA_FEED_RATE); - } else { - unloadFilamentStarted = false; - } - } - break; - case ProgressCode::FeedingToFSensor: - if (loadFilamentStarted) { - switch (WhereIsFilament()) { - case FilamentState::AT_FSENSOR: - // fsensor triggered, finish FeedingToBondtech state - loadFilamentStarted = false; - // 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 5mm. -// SERIAL_ECHOPGM("ATF1="); -// SERIAL_ECHO(current_position[E_AXIS]); - current_position[E_AXIS] += 30.0f + 2.0f; - plan_buffer_line_curposXYZE(MMU2_LOAD_TO_NOZZLE_FEED_RATE); -// SERIAL_ECHOPGM("ATF2="); -// SERIAL_ECHOLN(current_position[E_AXIS]); - break; - case FilamentState::NOT_PRESENT: - // fsensor not triggered, continue moving extruder - if (!blocks_queued()) { // Only plan a move if there is no move ongoing - current_position[E_AXIS] += 2.0f; - plan_buffer_line_curposXYZE(MMU2_LOAD_TO_NOZZLE_FEED_RATE); - } - break; - default: - // Abort here? - break; - } - } - break; - default: - // do nothing yet - break; - } + OnMMUProgressMsgSame(pc); } } -void MMU2::LogErrorEvent(const char *msg){ - MMU2_ERROR_MSG(msg); - SERIAL_ECHOLN(); +void MMU2::OnMMUProgressMsgChanged(ProgressCode pc){ + ReportProgress(pc); + lastProgressCode = pc; + switch (pc) { + case ProgressCode::UnloadingToFinda: + if ((CommandInProgress)logic.CommandInProgress() == CommandInProgress::UnloadFilament + || ((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. + break; + } else { + // We're likely recovering from an MMU error + st_synchronize(); + unloadFilamentStarted = true; + current_position[E_AXIS] -= MMU2_RETRY_UNLOAD_TO_FINDA_LENGTH; + plan_buffer_line_curposXYZE(MMU2_RETRY_UNLOAD_TO_FINDA_FEED_RATE); + } + break; + case ProgressCode::FeedingToFSensor: + // prepare for the movement of the E-motor + st_synchronize(); + loadFilamentStarted = true; + break; + default: + // do nothing yet + break; + } } -void MMU2::LogEchoEvent(const char *msg){ - MMU2_ECHO_MSG(msg); - SERIAL_ECHOLN(); +void MMU2::OnMMUProgressMsgSame(ProgressCode pc){ + switch (pc) { + case ProgressCode::UnloadingToFinda: + if (unloadFilamentStarted && !blocks_queued()) { // Only plan a move if there is no move ongoing + if (fsensor.getFilamentPresent()) { + current_position[E_AXIS] -= MMU2_RETRY_UNLOAD_TO_FINDA_LENGTH; + plan_buffer_line_curposXYZE(MMU2_RETRY_UNLOAD_TO_FINDA_FEED_RATE); + } else { + unloadFilamentStarted = false; + } + } + break; + case ProgressCode::FeedingToFSensor: + if (loadFilamentStarted) { + switch (WhereIsFilament()) { + case FilamentState::AT_FSENSOR: + // fsensor triggered, finish FeedingToBondtech state + loadFilamentStarted = false; + // 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 5mm. + current_position[E_AXIS] += 30.0f + 2.0f; + plan_buffer_line_curposXYZE(MMU2_LOAD_TO_NOZZLE_FEED_RATE); + break; + case FilamentState::NOT_PRESENT: + // fsensor not triggered, continue moving extruder + if (!blocks_queued()) { // Only plan a move if there is no move ongoing + current_position[E_AXIS] += 2.0f; + plan_buffer_line_curposXYZE(MMU2_LOAD_TO_NOZZLE_FEED_RATE); + } + break; + default: + // Abort here? + break; + } + } + break; + default: + // do nothing yet + break; + } } } // namespace MMU2 diff --git a/Firmware/mmu2.h b/Firmware/mmu2.h index 33800b946..0167fa1d8 100644 --- a/Firmware/mmu2.h +++ b/Firmware/mmu2.h @@ -201,7 +201,6 @@ private: void filament_ramming(); void execute_extruder_sequence(const E_Step *sequence, uint8_t steps); - void SetActiveExtruder(uint8_t ex); /// Reports an error into attached ExtUIs /// @param ec error code, see ErrorCode @@ -215,13 +214,11 @@ private: /// Responds to a change of MMU's progress /// - plans additional steps, e.g. starts the E-motor after fsensor trigger void OnMMUProgressMsg(ProgressCode pc); + /// Progress code changed - act accordingly + void OnMMUProgressMsgChanged(ProgressCode pc); + /// Repeated calls when progress code remains the same + void OnMMUProgressMsgSame(ProgressCode pc); - /// Report the msg into the general logging subsystem (through Marlin's SERIAL_ECHO stuff) - void LogErrorEvent(const char *msg); - - /// Report the msg into the general logging subsystem (through Marlin's SERIAL_ECHO stuff) - void LogEchoEvent(const char *msg); - /// Save print and park the print head void SaveAndPark(bool move_axes, bool turn_off_nozzle); diff --git a/Firmware/mmu2_log.cpp b/Firmware/mmu2_log.cpp new file mode 100644 index 000000000..288317b02 --- /dev/null +++ b/Firmware/mmu2_log.cpp @@ -0,0 +1,17 @@ +#include "mmu2_log.h" + +namespace MMU2 { + +void LogErrorEvent_P(const char *msg){ + SERIAL_ERROR_START; + SERIAL_MMU2(); + SERIAL_ECHOLNRPGM(msg); +} + +void LogEchoEvent_P(const char *msg){ + SERIAL_ECHO_START; + SERIAL_MMU2(); + SERIAL_ECHOLNRPGM(msg); +} + +} // namespace MMU2 diff --git a/Firmware/mmu2_log.h b/Firmware/mmu2_log.h index 0194534d9..a70182489 100644 --- a/Firmware/mmu2_log.h +++ b/Firmware/mmu2_log.h @@ -8,6 +8,18 @@ // and MMU2::ReportError + MMU2::ReportProgress static constexpr char mmu2Magic[] PROGMEM = "MMU2:"; +namespace MMU2 { + +/// Report the msg into the general logging subsystem (through Marlin's SERIAL_ECHO stuff) +/// @param msg pointer to a string in PROGMEM +void LogErrorEvent_P(const char *msg); + +/// Report the msg into the general logging subsystem (through Marlin's SERIAL_ECHO stuff) +/// @param msg pointer to a string in PROGMEM +void LogEchoEvent_P(const char *msg); + +} // namespace + #define SERIAL_MMU2() { serialprintPGM(mmu2Magic); } #define MMU2_ECHO_MSG(S) do{ SERIAL_ECHO_START; SERIAL_MMU2(); SERIAL_ECHO(S); }while(0) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index a556918a6..6206af7bf 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -911,8 +911,6 @@ block->steps_y.wide = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-p block->direction_bits |= (1<active_extruder = extruder; - //enable active axes #ifdef COREXY if((block->steps_x.wide != 0) || (block->steps_y.wide != 0)) diff --git a/Firmware/planner.h b/Firmware/planner.h index ed46cc82c..09cb6152c 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -75,7 +75,6 @@ typedef struct { dda_usteps_t step_event_count; // The number of step events required to complete this block uint32_t acceleration_rate; // The acceleration rate used for acceleration calculation unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) - unsigned char active_extruder; // Selects the active extruder // accelerate_until and decelerate_after are set by calculate_trapezoid_for_block() and they need to be synchronized with the stepper interrupt controller. uint32_t accelerate_until; // The index of the step event on which to stop acceleration uint32_t decelerate_after; // The index of the step event on which to start decelerating