diff --git a/Firmware/AutoDeplete.cpp b/Firmware/AutoDeplete.cpp index 9c4340f09..0a0274db5 100644 --- a/Firmware/AutoDeplete.cpp +++ b/Firmware/AutoDeplete.cpp @@ -1,79 +1,66 @@ -//! @file -//! @author: Marek Bel -//! @date Jan 3, 2019 - #include "AutoDeplete.h" -#include "assert.h" +#include "eeprom.h" +#include "Filament_sensor.h" -//! @brief bit field marking depleted filaments -//! -//! binary 1 marks filament as depleted -//! Zero initialized value means, that no filament is depleted. -static uint8_t depleted; -static const uint8_t filamentCount = 5; +namespace SpoolJoin { -//! @return binary 1 for all filaments -//! @par fCount number of filaments -static constexpr uint8_t allDepleted(uint8_t fCount) +SpoolJoin spooljoin; + +SpoolJoin::SpoolJoin() + : status(EEPROM::Unknown) + , currentMMUSlot(0) { - return fCount == 1 ? 1 : ((1 << (fCount - 1)) | allDepleted(fCount - 1)); } -//! @brief Is filament available for printing? -//! @par filament Filament number to be checked -//! @retval true Filament is available for printing. -//! @retval false Filament is not available for printing. -static bool loaded(uint8_t filament) +void SpoolJoin::updateSpoolJoinStatus(EEPROM newStatus) { - if (depleted & (1 << filament)) return false; - return true; + status = newStatus; + eeprom_write_byte((uint8_t*)EEPROM_AUTO_DEPLETE, (uint8_t)status); } -//! @brief Mark filament as not available for printing. -//! @par filament filament to be marked -void ad_markDepleted(uint8_t filament) +void SpoolJoin::initSpoolJoinStatus() { - assert(filament < filamentCount); - if (filament < filamentCount) + EEPROM currentStatus = (EEPROM)eeprom_read_byte((uint8_t*)EEPROM_AUTO_DEPLETE); + if( currentStatus == EEPROM::Empty) { - depleted |= 1 << filament; + // By default SpoolJoin is disabled + updateSpoolJoinStatus(EEPROM::Disabled); + } else { + updateSpoolJoinStatus(currentStatus); } } -//! @brief Mark filament as available for printing. -//! @par filament filament to be marked -void ad_markLoaded(uint8_t filament) +void SpoolJoin::toggleSpoolJoin() { - assert(filament < filamentCount); - if (filament < filamentCount) + if (eeprom_read_byte((uint8_t*)EEPROM_AUTO_DEPLETE) == (uint8_t)EEPROM::Disabled) { - depleted &= ~(1 << filament); + eeprom_write_byte((uint8_t*)EEPROM_AUTO_DEPLETE, (uint8_t)EEPROM::Enabled); + } else { + eeprom_write_byte((uint8_t*)EEPROM_AUTO_DEPLETE, (uint8_t)EEPROM::Disabled); } } -//! @brief Get alternative filament, which is not depleted -//! @par filament filament -//! @return Filament, if it is depleted, returns next available, -//! if all filaments are depleted, returns filament function parameter. -uint8_t ad_getAlternative(uint8_t filament) +uint8_t SpoolJoin::isSpoolJoinEnabled() { - assert(filament < filamentCount); - for (uint8_t i = 0; i +#include "eeprom.h" -void ad_markDepleted(uint8_t filament); -void ad_markLoaded(uint8_t filament); -uint8_t ad_getAlternative(uint8_t filament); -bool ad_allDepleted(); +// See documentation here: https://help.prusa3d.com/article/spooljoin-mmu2s_134252 -#endif /* AUTODEPLETE_H */ +namespace SpoolJoin { + +class SpoolJoin { +public: + SpoolJoin(); + + enum class EEPROM : uint8_t { + Unknown, ///< SpoolJoin is unknown while printer is booting up + Enabled, ///< SpoolJoin is enabled in EEPROM + Disabled, ///< SpoolJoin is disabled in EEPROM + NA, ///< SpoolJoin is 'Not Applicable' when Fsensor is faulty + Empty = 0xFF ///< EEPROM has not been set before and all bits are 1 (0xFF) - either a new printer or user erased the memory + }; + + /// @brief Called when EEPROM is ready to be read + void initSpoolJoinStatus(); + + /// @brief Enable SpoolJoin + inline void enableSpoolJoin() { updateSpoolJoinStatus(EEPROM::Enabled); }; + + /// @brief Disable SpoolJoin + inline void disableSpoolJoin() { updateSpoolJoinStatus(EEPROM::Disabled); }; + + /// @brief Toggle SpoolJoin + static void toggleSpoolJoin(); + + /// @brief Check if SpoolJoin is enabled + uint8_t isSpoolJoinEnabled(); + + /// @brief Fetch the next slot number should count from 0 to 4. + /// When filament slot 4 is depleted, the next slot should be 0. + /// @returns the next slot, ranges from 0 to 4 + uint8_t nextSlot(); + +private: + /// @brief Update EEPROM + /// @param newStatus Status to write into EEPROM + void updateSpoolJoinStatus(EEPROM newStatus); + + /// @brief SpoolJoin status + enum EEPROM status; + + /// @brief Currently used slot, ranges from 0 to 4 + uint8_t currentMMUSlot; +}; + +extern SpoolJoin spooljoin; + +} // namespace SpoolJoin diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 1768acbbe..a1f7671f2 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -1115,6 +1115,7 @@ void setup() if (eeprom_read_byte((uint8_t *)EEPROM_MMU_ENABLED)) { MMU2::mmu2.Start(); } + SpoolJoin::spooljoin.initSpoolJoinStatus(); //SERIAL_ECHOPAIR("Active sheet before:", static_cast(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))); @@ -3510,12 +3511,13 @@ static void mmu_M600_unload_filament() { /// @brief load filament for mmu v2 /// @par nozzle_temp nozzle temperature to load filament static void mmu_M600_load_filament(bool automatic, float nozzle_temp) { - // TODO: Only ask for the slot if automatic/ SpoolJoin is off - uint8_t slot = choose_menu_P(_T(MSG_SELECT_EXTRUDER), _T(MSG_EXTRUDER)); - // TODO SpoolJoin - /*if (automatic) { - tmp_extruder = ad_getAlternative(tmp_extruder); - }*/ + uint8_t slot; + if (automatic) { + slot = SpoolJoin::spooljoin.nextSlot(); + } else { + // Only ask for the slot if automatic/SpoolJoin is off + slot = choose_menu_P(_T(MSG_SELECT_EXTRUDER), _T(MSG_EXTRUDER)); + } setTargetHotend(nozzle_temp, active_extruder); diff --git a/Firmware/Tcodes.cpp b/Firmware/Tcodes.cpp index 7caed7a75..85a967063 100644 --- a/Firmware/Tcodes.cpp +++ b/Firmware/Tcodes.cpp @@ -57,14 +57,13 @@ void TCodes(char *const strchr_pointer, uint8_t codeValue) { } } else { SChooseFromMenu selectedSlot; -// if (strchr_pointer[index] == '?') -// selectedSlot = TCodeChooseFromMenu(); -// else { + if (strchr_pointer[index] == '?') { + selectedSlot = TCodeChooseFromMenu(); + } else if (MMU2::mmu2.Enabled() && SpoolJoin::spooljoin.isSpoolJoinEnabled()) { + selectedSlot.slot = SpoolJoin::spooljoin.nextSlot(); + } else { selectedSlot.slot = codeValue; -// if (MMU2::mmu2.Enabled() && lcd_autoDepleteEnabled()) { -// selectedSlot.slot = ad_getAlternative(selectedSlot.slot); -// } -// } + } st_synchronize(); if (MMU2::mmu2.Enabled()) { diff --git a/Firmware/mmu2.cpp b/Firmware/mmu2.cpp index 0a84c972d..51925bc9b 100644 --- a/Firmware/mmu2.cpp +++ b/Firmware/mmu2.cpp @@ -15,6 +15,7 @@ #include "temperature.h" #include "ultralcd.h" #include "cardreader.h" // for IS_SD_PRINTING +#include "AutoDeplete.h" // 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 @@ -211,6 +212,20 @@ void MMU2::mmu_loop() { ReportErrorHook((uint16_t)lastErrorCode, mmu2.MMUCurrentErrorCode() == ErrorCode::OK ? ErrorSourcePrinter : ErrorSourceMMU); } + // Check for FINDA filament runout + if (!FindaDetectsFilament() && CHECK_FSENSOR) { + stop_and_save_print_to_ram(0, 0); + restore_print_from_ram_and_continue(0); + if (SpoolJoin::spooljoin.isSpoolJoinEnabled() && get_current_tool() != (uint8_t)FILAMENT_UNKNOWN) // Can't auto if F=? + { + enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command + } + else + { + enquecommand_front_P(PSTR("M600")); //save print and run M600 command + } + } + avoidRecursion = false; } diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 0090d6245..64f01c14f 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -37,6 +37,7 @@ #include "sound.h" #include "mmu2.h" +#include "AutoDeplete.h" #include "static_assert.h" #include "first_lay_cal.h" @@ -76,9 +77,6 @@ bool isPrintPaused = false; static ShortTimer display_time; //just timer for showing pid finished message on lcd; static uint16_t pid_temp = DEFAULT_PID_TEMP; -static bool lcd_autoDeplete; - - static float manual_feedrate[] = MANUAL_FEEDRATE; /* LCD message status */ @@ -3958,15 +3956,6 @@ static void lcd_wizard_load() { //enquecommand_P(PSTR("M701")); } -bool lcd_autoDepleteEnabled() -{ - return (lcd_autoDeplete -#ifdef FILAMENT_SENSOR // @todo leptun: should be removed during mmu2 refactoring - needs checking - && fsensor.isReady() -#endif - ); -} - static void wizard_lay1cal_message(bool cold) { lcd_show_fullscreen_message_and_wait_P( @@ -4302,12 +4291,6 @@ static void lcd_fsensor_settings_menu() { #endif //FILAMENT_SENSOR -static void auto_deplete_switch() -{ - lcd_autoDeplete = !lcd_autoDeplete; - eeprom_update_byte((unsigned char *)EEPROM_AUTO_DEPLETE, lcd_autoDeplete); -} - static void settingsAutoDeplete() { if (MMU2::mmu2.Enabled()) @@ -4319,7 +4302,7 @@ static void settingsAutoDeplete() else #endif //FILAMENT_SENSOR { - MENU_ITEM_TOGGLE_P(_T(MSG_AUTO_DEPLETE), lcd_autoDeplete ? _T(MSG_ON) : _T(MSG_OFF), auto_deplete_switch); + MENU_ITEM_TOGGLE_P(_T(MSG_AUTO_DEPLETE), SpoolJoin::spooljoin.isSpoolJoinEnabled() ? _T(MSG_ON) : _T(MSG_OFF), SpoolJoin::spooljoin.toggleSpoolJoin); } } } @@ -7538,12 +7521,6 @@ void menu_action_sddirectory(const char* filename) void ultralcd_init() { - { - uint8_t autoDepleteRaw = eeprom_read_byte(reinterpret_cast(EEPROM_AUTO_DEPLETE)); - if (0xff == autoDepleteRaw) lcd_autoDeplete = false; - else lcd_autoDeplete = autoDepleteRaw; - - } backlight_init(); lcd_init(); lcd_refresh(); diff --git a/Firmware/ultralcd.h b/Firmware/ultralcd.h index fd48e7be1..d43b900c7 100755 --- a/Firmware/ultralcd.h +++ b/Firmware/ultralcd.h @@ -215,7 +215,6 @@ void lcd_language(); #endif void lcd_wizard(); -bool lcd_autoDepleteEnabled(); //! @brief Wizard state enum class WizState : uint8_t