From a309ec1b0b7d46c3d7c483d2aecab039c2eae88f Mon Sep 17 00:00:00 2001 From: Marek Bel Date: Thu, 3 Jan 2019 22:58:25 +0100 Subject: [PATCH 1/7] Add filament auto deplete engine for multi-material prints with MMUv2. --- Firmware/AutoDeplete.cpp | 78 ++++++++++++++++++++++++++++++++++++++++ Firmware/AutoDeplete.h | 17 +++++++++ 2 files changed, 95 insertions(+) create mode 100644 Firmware/AutoDeplete.cpp create mode 100644 Firmware/AutoDeplete.h diff --git a/Firmware/AutoDeplete.cpp b/Firmware/AutoDeplete.cpp new file mode 100644 index 000000000..bfc090129 --- /dev/null +++ b/Firmware/AutoDeplete.cpp @@ -0,0 +1,78 @@ +//! @file +//! @author: Marek Bel +//! @date Jan 3, 2019 + +#include "AutoDeplete.h" +#include "assert.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; + +static constexpr uint8_t allDepleted(uint8_t fCount) +{ + return fCount == 1 ? 1 : ((1 << (fCount - 1)) | allDepleted(fCount - 2)); +} + +//! @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) +{ + if (depleted & (1 << filament)) return false; + return true; +} + +//! @brief Mark filament as not available for printing. +//! @par filament filament to be marked +void ad_markDepleted(uint8_t filament) +{ + assert(filament < filamentCount); + if (filament < filamentCount) + { + depleted |= 1 << filament; + } +} + +//! @brief Mark filament as available for printing. +//! @par filament filament to be marked +void ad_markLoaded(uint8_t filament) +{ + assert(filament < filamentCount); + if (filament < filamentCount) + { + depleted &= ~(1 << filament); + } +} + +//! @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) +{ + assert(filament < filamentCount); + if (ad_allDepleted()) return filament; + for (uint8_t i = 0; i + +void ad_markDepleted(uint8_t filament); +void ad_markLoaded(uint8_t filament); +uint8_t ad_getAlternative(uint8_t filament); +bool ad_allDepleted(); + +#endif /* AUTODEPLETE_H */ From 360a977520c7c0a7ed3a9f7d492c5a3e28c698a8 Mon Sep 17 00:00:00 2001 From: Marek Bel Date: Fri, 4 Jan 2019 19:34:42 +0100 Subject: [PATCH 2/7] Fix allDepleted(). Add tests. --- CMakeLists.txt | 2 + Firmware/AutoDeplete.cpp | 2 +- Tests/AutoDeplete_test.cpp | 146 +++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 Tests/AutoDeplete_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b0798404..c0c2aacd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,9 @@ set(TEST_SOURCES Tests/tests.cpp Tests/Example_test.cpp Tests/Timer_test.cpp + Tests/AutoDeplete_test.cpp Firmware/Timer.cpp + Firmware/AutoDeplete.cpp ) add_executable(tests ${TEST_SOURCES}) target_include_directories(tests PRIVATE Tests) diff --git a/Firmware/AutoDeplete.cpp b/Firmware/AutoDeplete.cpp index bfc090129..e6323dd96 100644 --- a/Firmware/AutoDeplete.cpp +++ b/Firmware/AutoDeplete.cpp @@ -14,7 +14,7 @@ static const uint8_t filamentCount = 5; static constexpr uint8_t allDepleted(uint8_t fCount) { - return fCount == 1 ? 1 : ((1 << (fCount - 1)) | allDepleted(fCount - 2)); + return fCount == 1 ? 1 : ((1 << (fCount - 1)) | allDepleted(fCount - 1)); } //! @brief Is filament available for printing? diff --git a/Tests/AutoDeplete_test.cpp b/Tests/AutoDeplete_test.cpp new file mode 100644 index 000000000..fb2964bc0 --- /dev/null +++ b/Tests/AutoDeplete_test.cpp @@ -0,0 +1,146 @@ +/** + * @file + * @author Marek Bel + */ + +#include "catch.hpp" + +#include "../Firmware/AutoDeplete.h" + +TEST_CASE( "AutoDeplete test.", "[AutoDeplete]" ) +{ + CHECK(ad_allDepleted() == false); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + + ad_markDepleted(1); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(3); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 4); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(4); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 0); + CHECK(ad_getAlternative(4) == 0); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(4); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 0); + CHECK(ad_getAlternative(4) == 0); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(0); + + CHECK(ad_getAlternative(0) == 2); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 2); + CHECK(ad_getAlternative(4) == 2); + CHECK(ad_allDepleted() == false); + + ad_markDepleted(2); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == true); + + ad_markDepleted(2); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == true); + + ad_markLoaded(4); + + CHECK(ad_getAlternative(0) == 4); + CHECK(ad_getAlternative(1) == 4); + CHECK(ad_getAlternative(2) == 4); + CHECK(ad_getAlternative(3) == 4); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(0); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 4); + CHECK(ad_getAlternative(2) == 4); + CHECK(ad_getAlternative(3) == 4); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(3); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 3); + CHECK(ad_getAlternative(2) == 3); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(3); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 3); + CHECK(ad_getAlternative(2) == 3); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(2); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 2); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(1); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + + ad_markLoaded(1); + + CHECK(ad_getAlternative(0) == 0); + CHECK(ad_getAlternative(1) == 1); + CHECK(ad_getAlternative(2) == 2); + CHECK(ad_getAlternative(3) == 3); + CHECK(ad_getAlternative(4) == 4); + CHECK(ad_allDepleted() == false); + +} From 92ff284f82c2955404800a607f454cf0c298c937 Mon Sep 17 00:00:00 2001 From: Marek Bel Date: Fri, 4 Jan 2019 19:35:33 +0100 Subject: [PATCH 3/7] Remove redundant code. --- Firmware/AutoDeplete.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Firmware/AutoDeplete.cpp b/Firmware/AutoDeplete.cpp index e6323dd96..9593a1fec 100644 --- a/Firmware/AutoDeplete.cpp +++ b/Firmware/AutoDeplete.cpp @@ -56,7 +56,6 @@ void ad_markLoaded(uint8_t filament) uint8_t ad_getAlternative(uint8_t filament) { assert(filament < filamentCount); - if (ad_allDepleted()) return filament; for (uint8_t i = 0; i Date: Fri, 4 Jan 2019 19:56:15 +0100 Subject: [PATCH 4/7] Comment. --- Firmware/AutoDeplete.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Firmware/AutoDeplete.cpp b/Firmware/AutoDeplete.cpp index 9593a1fec..9c4340f09 100644 --- a/Firmware/AutoDeplete.cpp +++ b/Firmware/AutoDeplete.cpp @@ -12,6 +12,8 @@ static uint8_t depleted; static const uint8_t filamentCount = 5; +//! @return binary 1 for all filaments +//! @par fCount number of filaments static constexpr uint8_t allDepleted(uint8_t fCount) { return fCount == 1 ? 1 : ((1 << (fCount - 1)) | allDepleted(fCount - 1)); From 1a219b2372a4e4f3cf697575bbf56aa07bdd209f Mon Sep 17 00:00:00 2001 From: Marek Bel Date: Fri, 4 Jan 2019 21:11:42 +0100 Subject: [PATCH 5/7] Mark filament as depleted when detected by MMUv2 FINDA. Do not try to load filament if it is marked depleted, load next filament instead. Force user action when all filaments are marked as depleted. --- Firmware/mmu.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Firmware/mmu.cpp b/Firmware/mmu.cpp index d8e324581..e904742cb 100644 --- a/Firmware/mmu.cpp +++ b/Firmware/mmu.cpp @@ -13,6 +13,7 @@ #include "sound.h" #include "printers.h" #include +#include "AutoDeplete.h" #ifdef TMC2130 #include "tmc2130.h" @@ -276,8 +277,15 @@ void mmu_loop(void) if (!mmu_finda && CHECK_FINDA && fsensor_enabled) { fsensor_stop_and_save_print(); enquecommand_front_P(PSTR("FSENSOR_RECOVER")); //then recover - if (lcd_autoDepleteEnabled()) enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command - else enquecommand_front_P(PSTR("M600")); //save print and run M600 command + ad_markDepleted(mmu_extruder); + if (lcd_autoDepleteEnabled() && !ad_allDepleted()) + { + enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command + } + else + { + enquecommand_front_P(PSTR("M600")); //save print and run M600 command + } } mmu_state = 1; if (mmu_cmd == 0) @@ -337,14 +345,19 @@ int8_t mmu_set_filament_type(uint8_t extruder, uint8_t filament) void mmu_command(uint8_t cmd) { -#ifdef TMC2130 if ((cmd >= MMU_CMD_T0) && (cmd <= MMU_CMD_T4)) { //disable extruder motor +#ifdef TMC2130 tmc2130_set_pwr(E_AXIS, 0); - //printf_P(PSTR("E-axis disabled\n")); - } #endif //TMC2130 + //printf_P(PSTR("E-axis disabled\n")); + ad_markLoaded(cmd - MMU_CMD_T0); + } + if ((cmd >= MMU_CMD_L0) && (cmd <= MMU_CMD_L4)) + { + ad_markLoaded(cmd - MMU_CMD_L0); + } mmu_cmd = cmd; mmu_ready = false; @@ -586,7 +599,7 @@ void mmu_M600_load_filament(bool automatic) #endif //MMU_M600_SWITCH_EXTRUDER } else { - tmp_extruder = (tmp_extruder+1)%5; + tmp_extruder = ad_getAlternative(tmp_extruder); } lcd_update_enable(false); lcd_clear(); From d89c03a0f14b23ca392198c6143c09d35d811cc8 Mon Sep 17 00:00:00 2001 From: Marek Bel Date: Fri, 4 Jan 2019 21:26:13 +0100 Subject: [PATCH 6/7] Documentation. --- Firmware/mmu.cpp | 7 ++++++- Firmware/mmu.h | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Firmware/mmu.cpp b/Firmware/mmu.cpp index e904742cb..13c7169e3 100644 --- a/Firmware/mmu.cpp +++ b/Firmware/mmu.cpp @@ -1,4 +1,4 @@ -//mmu.cpp +//! @file #include "mmu.h" #include "planner.h" @@ -343,6 +343,11 @@ int8_t mmu_set_filament_type(uint8_t extruder, uint8_t filament) return timeout?1:0; } +//! @brief Enqueue MMUv2 command +//! +//! Call manage_response() after enqueuing to process command. +//! If T command is enqueued, it disables current for extruder motor if TMC2130 driver present. +//! If T or L command is enqueued, it marks filament loaded in AutoDeplete module. void mmu_command(uint8_t cmd) { if ((cmd >= MMU_CMD_T0) && (cmd <= MMU_CMD_T4)) diff --git a/Firmware/mmu.h b/Firmware/mmu.h index 2071891ea..b8d609ee3 100644 --- a/Firmware/mmu.h +++ b/Firmware/mmu.h @@ -1,4 +1,4 @@ -//mmu.h +//! @file #include From c080b899c3c45b0858d9d9505da88cc21b9c317a Mon Sep 17 00:00:00 2001 From: Marek Bel Date: Fri, 4 Jan 2019 22:32:48 +0100 Subject: [PATCH 7/7] Change filament number in T command to alternative if depleted and lcd_autoDepleteEnabled(). --- Firmware/Marlin_main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index dc96673c6..d08c1154a 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -78,6 +78,7 @@ #include #include "Dcodes.h" +#include "AutoDeplete.h" #ifdef SWSPI @@ -6920,6 +6921,10 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) } else { tmp_extruder = code_value(); + if (mmu_enabled && lcd_autoDepleteEnabled()) + { + tmp_extruder = ad_getAlternative(tmp_extruder); + } } st_synchronize(); snmm_filaments_used |= (1 << tmp_extruder); //for stop print