浏览代码

Merge pull request #1442 from mkbel/auto_deplete_2

Auto deplete 2
PavelSindler 5 年之前
父节点
当前提交
2f4e859da9
共有 7 个文件被更改,包括 274 次插入7 次删除
  1. 2 0
      CMakeLists.txt
  2. 79 0
      Firmware/AutoDeplete.cpp
  3. 17 0
      Firmware/AutoDeplete.h
  4. 5 0
      Firmware/Marlin_main.cpp
  5. 24 6
      Firmware/mmu.cpp
  6. 1 1
      Firmware/mmu.h
  7. 146 0
      Tests/AutoDeplete_test.cpp

+ 2 - 0
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)

+ 79 - 0
Firmware/AutoDeplete.cpp

@@ -0,0 +1,79 @@
+//! @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;
+
+//! @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));
+}
+
+//! @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);
+    for (uint8_t i = 0; i<filamentCount; ++i)
+    {
+        uint8_t nextFilament = (filament + i) % filamentCount;
+        if (loaded(nextFilament)) return nextFilament;
+    }
+    return filament;
+}
+
+//! @brief Are all filaments depleted?
+//! @retval true All filaments are depleted.
+//! @retval false All filaments are not depleted.
+bool ad_allDepleted()
+{
+    if (allDepleted(filamentCount) == depleted)
+    {
+        return true;
+    }
+    return false;
+}

+ 17 - 0
Firmware/AutoDeplete.h

@@ -0,0 +1,17 @@
+//! @file
+//! @author: Marek Bel
+//! @brief Filament auto deplete engine for multi-material prints with MMUv2 (Now marketed as SpoolJoin)
+//!
+//! Interface for marking MMUv2 filaments as depleted and getting alternative filament for printing.
+
+#ifndef AUTODEPLETE_H
+#define AUTODEPLETE_H
+
+#include <stdint.h>
+
+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 */

+ 5 - 0
Firmware/Marlin_main.cpp

@@ -78,6 +78,7 @@
 #include <avr/pgmspace.h>
 
 #include "Dcodes.h"
+#include "AutoDeplete.h"
 
 
 #ifdef SWSPI
@@ -6944,6 +6945,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

+ 24 - 6
Firmware/mmu.cpp

@@ -1,4 +1,4 @@
-//mmu.cpp
+//! @file
 
 #include "mmu.h"
 #include "planner.h"
@@ -14,6 +14,7 @@
 #include "printers.h"
 #include <avr/pgmspace.h>
 #include "io_atmega2560.h"
+#include "AutoDeplete.h"
 
 #ifdef TMC2130
 #include "tmc2130.h"
@@ -320,8 +321,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)
@@ -417,16 +425,26 @@ 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)
 {
-#ifdef TMC2130
 	if ((cmd >= MMU_CMD_T0) && (cmd <= MMU_CMD_T4))
 	{
 		//disable extruder motor
+#ifdef TMC2130
 		tmc2130_set_pwr(E_AXIS, 0);
+#endif //TMC2130
 		//printf_P(PSTR("E-axis disabled\n"));
+		ad_markLoaded(cmd - MMU_CMD_T0);
 	}
-#endif //TMC2130
+    if ((cmd >= MMU_CMD_L0) && (cmd <= MMU_CMD_L4))
+    {
+        ad_markLoaded(cmd - MMU_CMD_L0);
+    }
 
 	mmu_cmd = cmd;
 	mmu_ready = false;
@@ -748,7 +766,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();

+ 1 - 1
Firmware/mmu.h

@@ -1,4 +1,4 @@
-//mmu.h
+//! @file
 
 #include <inttypes.h>
 

+ 146 - 0
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);
+
+}