commit
2f4e859da9
@ -14,7 +14,9 @@ set(TEST_SOURCES
|
|||||||
Tests/tests.cpp
|
Tests/tests.cpp
|
||||||
Tests/Example_test.cpp
|
Tests/Example_test.cpp
|
||||||
Tests/Timer_test.cpp
|
Tests/Timer_test.cpp
|
||||||
|
Tests/AutoDeplete_test.cpp
|
||||||
Firmware/Timer.cpp
|
Firmware/Timer.cpp
|
||||||
|
Firmware/AutoDeplete.cpp
|
||||||
)
|
)
|
||||||
add_executable(tests ${TEST_SOURCES})
|
add_executable(tests ${TEST_SOURCES})
|
||||||
target_include_directories(tests PRIVATE Tests)
|
target_include_directories(tests PRIVATE Tests)
|
||||||
|
79
Firmware/AutoDeplete.cpp
Normal file
79
Firmware/AutoDeplete.cpp
Normal file
@ -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
Firmware/AutoDeplete.h
Normal file
17
Firmware/AutoDeplete.h
Normal file
@ -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 */
|
@ -78,6 +78,7 @@
|
|||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
#include "Dcodes.h"
|
#include "Dcodes.h"
|
||||||
|
#include "AutoDeplete.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef SWSPI
|
#ifdef SWSPI
|
||||||
@ -6944,6 +6945,10 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tmp_extruder = code_value();
|
tmp_extruder = code_value();
|
||||||
|
if (mmu_enabled && lcd_autoDepleteEnabled())
|
||||||
|
{
|
||||||
|
tmp_extruder = ad_getAlternative(tmp_extruder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
st_synchronize();
|
st_synchronize();
|
||||||
snmm_filaments_used |= (1 << tmp_extruder); //for stop print
|
snmm_filaments_used |= (1 << tmp_extruder); //for stop print
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//mmu.cpp
|
//! @file
|
||||||
|
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
#include "planner.h"
|
#include "planner.h"
|
||||||
@ -14,6 +14,7 @@
|
|||||||
#include "printers.h"
|
#include "printers.h"
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "io_atmega2560.h"
|
#include "io_atmega2560.h"
|
||||||
|
#include "AutoDeplete.h"
|
||||||
|
|
||||||
#ifdef TMC2130
|
#ifdef TMC2130
|
||||||
#include "tmc2130.h"
|
#include "tmc2130.h"
|
||||||
@ -320,8 +321,15 @@ void mmu_loop(void)
|
|||||||
if (!mmu_finda && CHECK_FINDA && fsensor_enabled) {
|
if (!mmu_finda && CHECK_FINDA && fsensor_enabled) {
|
||||||
fsensor_stop_and_save_print();
|
fsensor_stop_and_save_print();
|
||||||
enquecommand_front_P(PSTR("FSENSOR_RECOVER")); //then recover
|
enquecommand_front_P(PSTR("FSENSOR_RECOVER")); //then recover
|
||||||
if (lcd_autoDepleteEnabled()) enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command
|
ad_markDepleted(mmu_extruder);
|
||||||
else enquecommand_front_P(PSTR("M600")); //save print and run M600 command
|
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;
|
mmu_state = 1;
|
||||||
if (mmu_cmd == 0)
|
if (mmu_cmd == 0)
|
||||||
@ -417,16 +425,26 @@ int8_t mmu_set_filament_type(uint8_t extruder, uint8_t filament)
|
|||||||
return timeout?1:0;
|
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)
|
void mmu_command(uint8_t cmd)
|
||||||
{
|
{
|
||||||
#ifdef TMC2130
|
|
||||||
if ((cmd >= MMU_CMD_T0) && (cmd <= MMU_CMD_T4))
|
if ((cmd >= MMU_CMD_T0) && (cmd <= MMU_CMD_T4))
|
||||||
{
|
{
|
||||||
//disable extruder motor
|
//disable extruder motor
|
||||||
|
#ifdef TMC2130
|
||||||
tmc2130_set_pwr(E_AXIS, 0);
|
tmc2130_set_pwr(E_AXIS, 0);
|
||||||
//printf_P(PSTR("E-axis disabled\n"));
|
|
||||||
}
|
|
||||||
#endif //TMC2130
|
#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_cmd = cmd;
|
||||||
mmu_ready = false;
|
mmu_ready = false;
|
||||||
@ -748,7 +766,7 @@ void mmu_M600_load_filament(bool automatic)
|
|||||||
#endif //MMU_M600_SWITCH_EXTRUDER
|
#endif //MMU_M600_SWITCH_EXTRUDER
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tmp_extruder = (tmp_extruder+1)%5;
|
tmp_extruder = ad_getAlternative(tmp_extruder);
|
||||||
}
|
}
|
||||||
lcd_update_enable(false);
|
lcd_update_enable(false);
|
||||||
lcd_clear();
|
lcd_clear();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//mmu.h
|
//! @file
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
146
Tests/AutoDeplete_test.cpp
Normal file
146
Tests/AutoDeplete_test.cpp
Normal file
@ -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);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user