clang-format

This commit is contained in:
D.R.racer 2023-01-25 10:03:25 +01:00 committed by DRracer
parent 0555376502
commit 528abcb8d8
7 changed files with 231 additions and 216 deletions

View File

@ -15,22 +15,22 @@
#ifdef __AVR__ #ifdef __AVR__
// As of FW 3.12 we only support building the FW with only one extruder, all the multi-extruder infrastructure will be removed. // 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 // Saves at least 800B of code size
static_assert(EXTRUDERS==1); static_assert(EXTRUDERS == 1);
constexpr float MMM_TO_MMS(float MM_M){ return MM_M / 60.0f; } constexpr float MMM_TO_MMS(float MM_M) { return MM_M / 60.0f; }
#endif #endif
namespace MMU2 { namespace MMU2 {
template<typename F> template <typename F>
void waitForHotendTargetTemp(uint16_t delay, F f){ void waitForHotendTargetTemp(uint16_t delay, F f) {
while (((thermal_degTargetHotend() - thermal_degHotend()) > 5)) { while (((thermal_degTargetHotend() - thermal_degHotend()) > 5)) {
f(); f();
safe_delay_keep_alive(delay); safe_delay_keep_alive(delay);
} }
} }
void WaitForHotendTargetTempBeep(){ void WaitForHotendTargetTempBeep() {
waitForHotendTargetTemp(3000, []{ }); waitForHotendTargetTemp(3000, []{ });
MakeSound(Prompt); MakeSound(Prompt);
} }
@ -51,14 +51,13 @@ MMU2::MMU2()
, unloadFilamentStarted(false) , unloadFilamentStarted(false)
, loadingToNozzle(false) , loadingToNozzle(false)
, toolchange_counter(0) , toolchange_counter(0)
, tmcFailures(0) , tmcFailures(0) {
{
} }
void MMU2::Start() { void MMU2::Start() {
mmu2Serial.begin(MMU_BAUD); mmu2Serial.begin(MMU_BAUD);
PowerOn(); // I repurposed this to serve as our EEPROM disable toggle. PowerOn(); // I repurposed this to serve as our EEPROM disable toggle.
mmu2Serial.flush(); // make sure the UART buffer is clear before starting communication mmu2Serial.flush(); // make sure the UART buffer is clear before starting communication
extruder = MMU2_NO_TOOL; extruder = MMU2_NO_TOOL;
@ -75,13 +74,13 @@ void MMU2::Stop() {
PowerOff(); // This also disables the MMU in the EEPROM. PowerOff(); // This also disables the MMU in the EEPROM.
} }
void MMU2::StopKeepPowered(){ void MMU2::StopKeepPowered() {
state = xState::Stopped; state = xState::Stopped;
logic.Stop(); logic.Stop();
mmu2Serial.close(); mmu2Serial.close();
} }
void MMU2::Reset(ResetForm level){ void MMU2::Reset(ResetForm level) {
switch (level) { switch (level) {
case Software: case Software:
ResetX0(); ResetX0();
@ -101,13 +100,13 @@ void MMU2::ResetX0() {
logic.ResetMMU(); // Send soft reset logic.ResetMMU(); // Send soft reset
} }
void MMU2::TriggerResetPin(){ void MMU2::TriggerResetPin() {
reset(); reset();
} }
void MMU2::PowerCycle(){ void MMU2::PowerCycle() {
// cut the power to the MMU and after a while restore it // cut the power to the MMU and after a while restore it
// Sadly, MK3/S/+ cannot do this // Sadly, MK3/S/+ cannot do this
// NOTE: the below will toggle the EEPROM var. Should we // NOTE: the below will toggle the EEPROM var. Should we
// assert this function is never called in the MK3 FW? Do we even care? // assert this function is never called in the MK3 FW? Do we even care?
PowerOff(); PowerOff();
@ -115,36 +114,36 @@ void MMU2::PowerCycle(){
PowerOn(); PowerOn();
} }
void MMU2::PowerOff(){ void MMU2::PowerOff() {
power_off(); power_off();
} }
void MMU2::PowerOn(){ void MMU2::PowerOn() {
power_on(); power_on();
} }
bool MMU2::ReadRegister(uint8_t address){ bool MMU2::ReadRegister(uint8_t address) {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
do { do {
logic.ReadRegister(address); // we may signal the accepted/rejected status of the response as return value of this function logic.ReadRegister(address); // we may signal the accepted/rejected status of the response as return value of this function
} while( ! manage_response(false, false) ); } while (!manage_response(false, false));
return true; return true;
} }
bool MMU2::WriteRegister(uint8_t address, uint16_t data){ bool MMU2::WriteRegister(uint8_t address, uint16_t data) {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
// special case - intercept requests of extra loading distance and perform the change even on the printer's side // special case - intercept requests of extra loading distance and perform the change even on the printer's side
if( address == 0x0b ){ if (address == 0x0b) {
logic.PlanExtraLoadDistance(data); logic.PlanExtraLoadDistance(data);
} }
do { do {
logic.WriteRegister(address, data); // we may signal the accepted/rejected status of the response as return value of this function logic.WriteRegister(address, data); // we may signal the accepted/rejected status of the response as return value of this function
} while( ! manage_response(false, false) ); } while (!manage_response(false, false));
return true; return true;
} }
@ -193,13 +192,13 @@ struct ReportingRAII {
: cip(cip) { : cip(cip) {
BeginReport(cip, (uint16_t)ProgressCode::EngagingIdler); BeginReport(cip, (uint16_t)ProgressCode::EngagingIdler);
} }
inline ~ReportingRAII(){ inline ~ReportingRAII() {
EndReport(cip, (uint16_t)ProgressCode::OK); EndReport(cip, (uint16_t)ProgressCode::OK);
} }
}; };
bool MMU2::WaitForMMUReady(){ bool MMU2::WaitForMMUReady() {
switch(State()){ switch (State()) {
case xState::Stopped: case xState::Stopped:
return false; return false;
case xState::Connecting: case xState::Connecting:
@ -210,11 +209,11 @@ bool MMU2::WaitForMMUReady(){
} }
} }
bool MMU2::RetryIfPossible(uint16_t ec){ bool MMU2::RetryIfPossible(uint16_t ec) {
if (logic.RetryAttempts()) { if (logic.RetryAttempts()) {
SetButtonResponse(ButtonOperations::Retry); SetButtonResponse(ButtonOperations::Retry);
// check, that Retry is actually allowed on that operation // check, that Retry is actually allowed on that operation
if( ButtonAvailable(ec) != NoButton ){ if (ButtonAvailable(ec) != NoButton) {
logic.SetInAutoRetry(true); logic.SetInAutoRetry(true);
SERIAL_ECHOLNPGM("RetryButtonPressed"); SERIAL_ECHOLNPGM("RetryButtonPressed");
// We don't decrement until the button is acknowledged by the MMU. // We don't decrement until the button is acknowledged by the MMU.
@ -226,20 +225,19 @@ bool MMU2::RetryIfPossible(uint16_t ec){
return false; return false;
} }
bool MMU2::VerifyFilamentEnteredPTFE() bool MMU2::VerifyFilamentEnteredPTFE() {
{
planner_synchronize(); planner_synchronize();
if (WhereIsFilament() == FilamentState::NOT_PRESENT) return false; if (WhereIsFilament() == FilamentState::NOT_PRESENT)
return false;
uint8_t fsensorState = 0; uint8_t fsensorState = 0;
// MMU has finished its load, push the filament further by some defined constant length // MMU has finished its load, push the filament further by some defined constant length
// If the filament sensor reads 0 at any moment, then report FAILURE // If the filament sensor reads 0 at any moment, then report FAILURE
MoveE(MMU2_EXTRUDER_PTFE_LENGTH + MMU2_EXTRUDER_HEATBREAK_LENGTH - (logic.ExtraLoadDistance() - MMU2_FILAMENT_SENSOR_POSITION), MMU2_VERIFY_LOAD_TO_NOZZLE_FEED_RATE); MoveE(MMU2_EXTRUDER_PTFE_LENGTH + MMU2_EXTRUDER_HEATBREAK_LENGTH - (logic.ExtraLoadDistance() - MMU2_FILAMENT_SENSOR_POSITION), MMU2_VERIFY_LOAD_TO_NOZZLE_FEED_RATE);
MoveE( - (MMU2_EXTRUDER_PTFE_LENGTH + MMU2_EXTRUDER_HEATBREAK_LENGTH - (logic.ExtraLoadDistance() - MMU2_FILAMENT_SENSOR_POSITION)), MMU2_VERIFY_LOAD_TO_NOZZLE_FEED_RATE); MoveE(-(MMU2_EXTRUDER_PTFE_LENGTH + MMU2_EXTRUDER_HEATBREAK_LENGTH - (logic.ExtraLoadDistance() - MMU2_FILAMENT_SENSOR_POSITION)), MMU2_VERIFY_LOAD_TO_NOZZLE_FEED_RATE);
while(planner_any_moves()) while (planner_any_moves()) {
{
// Wait for move to finish and monitor the fsensor the entire time // Wait for move to finish and monitor the fsensor the entire time
// A single 0 reading will set the bit. // A single 0 reading will set the bit.
fsensorState |= (WhereIsFilament() == FilamentState::NOT_PRESENT); fsensorState |= (WhereIsFilament() == FilamentState::NOT_PRESENT);
@ -247,8 +245,7 @@ bool MMU2::VerifyFilamentEnteredPTFE()
marlin_manage_inactivity(true); marlin_manage_inactivity(true);
} }
if (fsensorState) if (fsensorState) {
{
IncrementLoadFails(); IncrementLoadFails();
return false; return false;
} else { } else {
@ -257,14 +254,14 @@ bool MMU2::VerifyFilamentEnteredPTFE()
} }
} }
bool MMU2::ToolChangeCommonOnce(uint8_t slot){ bool MMU2::ToolChangeCommonOnce(uint8_t slot) {
static_assert(MAX_RETRIES > 1); // need >1 retries to do the cut in the last attempt static_assert(MAX_RETRIES > 1); // need >1 retries to do the cut in the last attempt
for(uint8_t retries = MAX_RETRIES; retries; --retries){ for (uint8_t retries = MAX_RETRIES; retries; --retries) {
for(;;) { for (;;) {
Disable_E0(); // it may seem counterintuitive to disable the E-motor, but it gets enabled in the planner whenever the E-motor is to move Disable_E0(); // it may seem counterintuitive to disable the E-motor, but it gets enabled in the planner whenever the E-motor is to move
tool_change_extruder = slot; tool_change_extruder = slot;
logic.ToolChange(slot); // let the MMU pull the filament out and push a new one in logic.ToolChange(slot); // let the MMU pull the filament out and push a new one in
if( manage_response(true, true) ) if (manage_response(true, true))
break; break;
// otherwise: failed to perform the command - unload first and then let it run again // otherwise: failed to perform the command - unload first and then let it run again
IncrementMMUFails(); IncrementMMUFails();
@ -280,12 +277,12 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot){
// something else is seriously broken and stopping a print is probably our best option. // something else is seriously broken and stopping a print is probably our best option.
} }
// reset current position to whatever the planner thinks it is // reset current position to whatever the planner thinks it is
planner_set_current_position_E( planner_get_current_position_E() ); planner_set_current_position_E(planner_get_current_position_E());
if (VerifyFilamentEnteredPTFE()){ if (VerifyFilamentEnteredPTFE()) {
return true; // success return true; // success
} else { // Prepare a retry attempt } else { // Prepare a retry attempt
unload(); unload();
if( retries == 2 && cutter_enabled()){ if (retries == 2 && cutter_enabled()) {
cut_filament(slot, false); // try cutting filament tip at the last attempt cut_filament(slot, false); // try cutting filament tip at the last attempt
} }
} }
@ -293,8 +290,8 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot){
return false; // couldn't accomplish the task return false; // couldn't accomplish the task
} }
void MMU2::ToolChangeCommon(uint8_t slot){ void MMU2::ToolChangeCommon(uint8_t slot) {
while( ! ToolChangeCommonOnce(slot) ){ // while not successfully fed into extruder's PTFE tube while (!ToolChangeCommonOnce(slot)) { // while not successfully fed into extruder's PTFE tube
// failed autoretry, report an error by forcing a "printer" error into the MMU infrastructure - it is a hack to leverage existing code // failed autoretry, report an error by forcing a "printer" error into the MMU infrastructure - it is a hack to leverage existing code
// @@TODO theoretically logic layer may not need to be spoiled with the printer error - may be just the manage_response needs it... // @@TODO theoretically logic layer may not need to be spoiled with the printer error - may be just the manage_response needs it...
logic.SetPrinterError(ErrorCode::LOAD_TO_EXTRUDER_FAILED); logic.SetPrinterError(ErrorCode::LOAD_TO_EXTRUDER_FAILED);
@ -312,7 +309,7 @@ void MMU2::ToolChangeCommon(uint8_t slot){
} }
bool MMU2::tool_change(uint8_t slot) { bool MMU2::tool_change(uint8_t slot) {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
if (slot != extruder) { if (slot != extruder) {
@ -338,14 +335,14 @@ bool MMU2::tool_change(uint8_t slot) {
///- Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load. ///- Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load.
///- Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated. ///- Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated.
bool MMU2::tool_change(char code, uint8_t slot) { bool MMU2::tool_change(char code, uint8_t slot) {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
FSensorBlockRunout blockRunout; FSensorBlockRunout blockRunout;
switch (code) { switch (code) {
case '?': { case '?': {
waitForHotendTargetTemp(100, []{}); waitForHotendTargetTemp(100, [] {});
load_filament_to_nozzle(slot); load_filament_to_nozzle(slot);
} break; } break;
@ -357,7 +354,7 @@ bool MMU2::tool_change(char code, uint8_t slot) {
} break; } break;
case 'c': { case 'c': {
waitForHotendTargetTemp(100, []{}); waitForHotendTargetTemp(100, [] {});
execute_load_to_nozzle_sequence(); execute_load_to_nozzle_sequence();
} break; } break;
} }
@ -378,25 +375,25 @@ uint8_t MMU2::get_tool_change_tool() const {
} }
bool MMU2::set_filament_type(uint8_t /*slot*/, uint8_t /*type*/) { bool MMU2::set_filament_type(uint8_t /*slot*/, uint8_t /*type*/) {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
// @@TODO - this is not supported in the new MMU yet // @@TODO - this is not supported in the new MMU yet
// slot = slot; // @@TODO // slot = slot; // @@TODO
// type = type; // @@TODO // type = type; // @@TODO
// cmd_arg = filamentType; // cmd_arg = filamentType;
// command(MMU_CMD_F0 + index); // command(MMU_CMD_F0 + index);
if( ! manage_response(false, false) ){ if (!manage_response(false, false)) {
// @@TODO failed to perform the command - retry // @@TODO failed to perform the command - retry
; ;
} // true, true); -- Comment: how is it possible for a filament type set to fail? } // true, true); -- Comment: how is it possible for a filament type set to fail?
return true; return true;
} }
bool MMU2::unload() { bool MMU2::unload() {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
WaitForHotendTargetTempBeep(); WaitForHotendTargetTempBeep();
@ -408,10 +405,10 @@ bool MMU2::unload() {
// we assume the printer managed to relieve filament tip from the gears, // we assume the printer managed to relieve filament tip from the gears,
// so repeating that part in case of an MMU restart is not necessary // so repeating that part in case of an MMU restart is not necessary
for(;;) { for (;;) {
Disable_E0(); Disable_E0();
logic.UnloadFilament(); logic.UnloadFilament();
if( manage_response(false, true) ) if (manage_response(false, true))
break; break;
IncrementMMUFails(); IncrementMMUFails();
} }
@ -424,23 +421,23 @@ bool MMU2::unload() {
return true; return true;
} }
bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /* = true */){ bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /*= true*/) {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
if( enableFullScreenMsg ){ if (enableFullScreenMsg) {
FullScreenMsgCut(slot); FullScreenMsgCut(slot);
} }
{ {
if( FindaDetectsFilament() ){ if (FindaDetectsFilament()) {
unload(); unload();
} }
ReportingRAII rep(CommandInProgress::CutFilament); ReportingRAII rep(CommandInProgress::CutFilament);
for(;;){ for (;;) {
Disable_E0(); Disable_E0();
logic.CutFilament(slot); logic.CutFilament(slot);
if( manage_response(false, true) ) if (manage_response(false, true))
break; break;
IncrementMMUFails(); IncrementMMUFails();
} }
@ -451,7 +448,7 @@ bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /* = true */){
return true; return true;
} }
bool MMU2::loading_test(uint8_t slot){ bool MMU2::loading_test(uint8_t slot) {
FullScreenMsgTest(slot); FullScreenMsgTest(slot);
tool_change(slot); tool_change(slot);
planner_synchronize(); planner_synchronize();
@ -461,16 +458,16 @@ bool MMU2::loading_test(uint8_t slot){
} }
bool MMU2::load_filament(uint8_t slot) { bool MMU2::load_filament(uint8_t slot) {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
FullScreenMsgLoad(slot); FullScreenMsgLoad(slot);
ReportingRAII rep(CommandInProgress::LoadFilament); ReportingRAII rep(CommandInProgress::LoadFilament);
for(;;) { for (;;) {
Disable_E0(); Disable_E0();
logic.LoadFilament(slot); logic.LoadFilament(slot);
if( manage_response(false, false) ) if (manage_response(false, false))
break; break;
IncrementMMUFails(); IncrementMMUFails();
} }
@ -484,16 +481,17 @@ bool MMU2::load_filament(uint8_t slot) {
struct LoadingToNozzleRAII { struct LoadingToNozzleRAII {
MMU2 &mmu2; MMU2 &mmu2;
explicit inline LoadingToNozzleRAII(MMU2 &mmu2):mmu2(mmu2){ explicit inline LoadingToNozzleRAII(MMU2 &mmu2)
: mmu2(mmu2) {
mmu2.loadingToNozzle = true; mmu2.loadingToNozzle = true;
} }
inline ~LoadingToNozzleRAII(){ inline ~LoadingToNozzleRAII() {
mmu2.loadingToNozzle = false; mmu2.loadingToNozzle = false;
} }
}; };
bool MMU2::load_filament_to_nozzle(uint8_t slot) { bool MMU2::load_filament_to_nozzle(uint8_t slot) {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
LoadingToNozzleRAII ln(*this); LoadingToNozzleRAII ln(*this);
@ -506,7 +504,7 @@ bool MMU2::load_filament_to_nozzle(uint8_t slot) {
ReportingRAII rep(CommandInProgress::ToolChange); ReportingRAII rep(CommandInProgress::ToolChange);
FSensorBlockRunout blockRunout; FSensorBlockRunout blockRunout;
if( extruder != MMU2_NO_TOOL ){ // we already have some filament loaded - free it + shape its tip properly if (extruder != MMU2_NO_TOOL) { // we already have some filament loaded - free it + shape its tip properly
filament_ramming(); filament_ramming();
} }
@ -521,22 +519,22 @@ bool MMU2::load_filament_to_nozzle(uint8_t slot) {
} }
bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) { bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
if( ! WaitForMMUReady()) if (!WaitForMMUReady())
return false; return false;
if( enableFullScreenMsg ){ if (enableFullScreenMsg) {
FullScreenMsgEject(slot); FullScreenMsgEject(slot);
} }
{ {
if( FindaDetectsFilament() ){ if (FindaDetectsFilament()) {
unload(); unload();
} }
ReportingRAII rep(CommandInProgress::EjectFilament); ReportingRAII rep(CommandInProgress::EjectFilament);
for(;;) { for (;;) {
Disable_E0(); Disable_E0();
logic.EjectFilament(slot); logic.EjectFilament(slot);
if( manage_response(false, true) ) if (manage_response(false, true))
break; break;
IncrementMMUFails(); IncrementMMUFails();
} }
@ -547,19 +545,20 @@ bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
return true; return true;
} }
void MMU2::Button(uint8_t index){ void MMU2::Button(uint8_t index) {
LogEchoEvent_P(PSTR("Button")); LogEchoEvent_P(PSTR("Button"));
logic.Button(index); logic.Button(index);
} }
void MMU2::Home(uint8_t mode){ void MMU2::Home(uint8_t mode) {
logic.Home(mode); logic.Home(mode);
} }
void MMU2::SaveHotendTemp(bool turn_off_nozzle) { void MMU2::SaveHotendTemp(bool turn_off_nozzle) {
if (mmu_print_saved & SavedState::Cooldown) return; if (mmu_print_saved & SavedState::Cooldown)
return;
if (turn_off_nozzle && !(mmu_print_saved & SavedState::CooldownPending)){ if (turn_off_nozzle && !(mmu_print_saved & SavedState::CooldownPending)) {
Disable_E0(); Disable_E0();
resume_hotend_temp = thermal_degTargetHotend(); resume_hotend_temp = thermal_degTargetHotend();
mmu_print_saved |= SavedState::CooldownPending; mmu_print_saved |= SavedState::CooldownPending;
@ -573,7 +572,7 @@ void MMU2::SaveAndPark(bool move_axes) {
Disable_E0(); Disable_E0();
planner_synchronize(); planner_synchronize();
if (move_axes){ if (move_axes) {
mmu_print_saved |= SavedState::ParkExtruder; mmu_print_saved |= SavedState::ParkExtruder;
resume_position = planner_current_position(); // save current pos resume_position = planner_current_position(); // save current pos
@ -599,14 +598,14 @@ void MMU2::ResumeHotendTemp() {
} }
if ((mmu_print_saved & SavedState::Cooldown) && resume_hotend_temp) { if ((mmu_print_saved & SavedState::Cooldown) && resume_hotend_temp) {
LogEchoEvent_P(PSTR("Resuming Temp")); LogEchoEvent_P(PSTR("Resuming Temp"));
// @@TODO MMU2_ECHO_MSGRPGM(PSTR("Restoring hotend temperature ")); // @@TODO MMU2_ECHO_MSGRPGM(PSTR("Restoring hotend temperature "));
SERIAL_ECHOLN(resume_hotend_temp); SERIAL_ECHOLN(resume_hotend_temp);
mmu_print_saved &= ~(SavedState::Cooldown); mmu_print_saved &= ~(SavedState::Cooldown);
thermal_setTargetHotend(resume_hotend_temp); thermal_setTargetHotend(resume_hotend_temp);
FullScreenMsgRestoringTemperature(); FullScreenMsgRestoringTemperature();
//@todo better report the event and let the GUI do its work somewhere else //@todo better report the event and let the GUI do its work somewhere else
ReportErrorHookSensorLineRender(); ReportErrorHookSensorLineRender();
waitForHotendTargetTemp(100, []{ waitForHotendTargetTemp(100, [] {
marlin_manage_inactivity(true); marlin_manage_inactivity(true);
mmu2.mmu_loop_inner(false); mmu2.mmu_loop_inner(false);
ReportErrorHookDynamicRender(); ReportErrorHookDynamicRender();
@ -617,13 +616,13 @@ void MMU2::ResumeHotendTemp() {
} }
} }
void MMU2::ResumeUnpark(){ void MMU2::ResumeUnpark() {
if (mmu_print_saved & SavedState::ParkExtruder) { if (mmu_print_saved & SavedState::ParkExtruder) {
LogEchoEvent_P(PSTR("Resuming XYZ")); LogEchoEvent_P(PSTR("Resuming XYZ"));
// Move XY to starting position, then Z // Move XY to starting position, then Z
motion_do_blocking_move_to_xy(resume_position.xyz[0], resume_position.xyz[1], feedRate_t(NOZZLE_PARK_XY_FEEDRATE)); motion_do_blocking_move_to_xy(resume_position.xyz[0], resume_position.xyz[1], feedRate_t(NOZZLE_PARK_XY_FEEDRATE));
// Move Z_AXIS to saved position // Move Z_AXIS to saved position
motion_do_blocking_move_to_z(resume_position.xyz[2], feedRate_t(NOZZLE_PARK_Z_FEEDRATE)); motion_do_blocking_move_to_z(resume_position.xyz[2], feedRate_t(NOZZLE_PARK_Z_FEEDRATE));
@ -631,13 +630,13 @@ void MMU2::ResumeUnpark(){
} }
} }
void MMU2::CheckUserInput(){ void MMU2::CheckUserInput() {
auto btn = ButtonPressed((uint16_t)lastErrorCode); auto btn = ButtonPressed((uint16_t)lastErrorCode);
// Was a button pressed on the MMU itself instead of the LCD? // 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; btn = lastButton;
lastButton = Buttons::NoButton; // Clear it. lastButton = Buttons::NoButton; // Clear it.
} }
switch (btn) { switch (btn) {
@ -648,7 +647,7 @@ void MMU2::CheckUserInput(){
SERIAL_ECHOLN(btn); SERIAL_ECHOLN(btn);
// clear the explicit printer error as soon as possible so that the MMU error screens + reporting doesn't get too confused // clear the explicit printer error as soon as possible so that the MMU error screens + reporting doesn't get too confused
if( lastErrorCode == ErrorCode::LOAD_TO_EXTRUDER_FAILED ){ if (lastErrorCode == ErrorCode::LOAD_TO_EXTRUDER_FAILED) {
// A horrible hack - clear the explicit printer error allowing manage_response to recover on MMU's Finished state // A horrible hack - clear the explicit printer error allowing manage_response to recover on MMU's Finished state
// Moreover - if the MMU is currently doing something (like the LoadFilament - see comment above) // Moreover - if the MMU is currently doing something (like the LoadFilament - see comment above)
// we'll actually wait for it automagically in manage_response and after it finishes correctly, // we'll actually wait for it automagically in manage_response and after it finishes correctly,
@ -668,7 +667,7 @@ void MMU2::CheckUserInput(){
// A quick hack: for specific error codes move the E-motor every time. // A quick hack: for specific error codes move the E-motor every time.
// Not sure if we can rely on the fsensor. // Not sure if we can rely on the fsensor.
// Just plan the move, let the MMU take over when it is ready // Just plan the move, let the MMU take over when it is ready
switch(lastErrorCode){ switch (lastErrorCode) {
case ErrorCode::FSENSOR_DIDNT_SWITCH_OFF: case ErrorCode::FSENSOR_DIDNT_SWITCH_OFF:
case ErrorCode::FSENSOR_TOO_EARLY: case ErrorCode::FSENSOR_TOO_EARLY:
HelpUnloadToFinda(); HelpUnloadToFinda();
@ -714,11 +713,11 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
// - finished ok -> proceed with reading other commands // - finished ok -> proceed with reading other commands
safe_delay_keep_alive(0); // calls LogicStep() and remembers its return status safe_delay_keep_alive(0); // calls LogicStep() and remembers its return status
if (mmu_print_saved & SavedState::CooldownPending){ if (mmu_print_saved & SavedState::CooldownPending) {
if (!nozzleTimeout.running()){ if (!nozzleTimeout.running()) {
nozzleTimeout.start(); nozzleTimeout.start();
LogEchoEvent_P(PSTR("Cooling Timeout started")); LogEchoEvent_P(PSTR("Cooling Timeout started"));
} else if (nozzleTimeout.expired(DEFAULT_SAFETYTIMER_TIME_MINS*60*1000ul)){ // mins->msec. } else if (nozzleTimeout.expired(DEFAULT_SAFETYTIMER_TIME_MINS * 60 * 1000ul)) { // mins->msec.
mmu_print_saved &= ~(SavedState::CooldownPending); mmu_print_saved &= ~(SavedState::CooldownPending);
mmu_print_saved |= SavedState::Cooldown; mmu_print_saved |= SavedState::Cooldown;
thermal_setTargetHotend(0); thermal_setTargetHotend(0);
@ -730,13 +729,13 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
} }
switch (logicStepLastStatus) { switch (logicStepLastStatus) {
case Finished: case Finished:
// command/operation completed, let Marlin continue its work // command/operation completed, let Marlin continue its work
// the E may have some more moves to finish - wait for them // the E may have some more moves to finish - wait for them
ResumeHotendTemp(); ResumeHotendTemp();
ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved. ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved.
logic.ResetRetryAttempts(); // Reset the retry counter. logic.ResetRetryAttempts(); // Reset the retry counter.
planner_synchronize(); planner_synchronize();
return true; return true;
case Interrupted: case Interrupted:
// now what :D ... big bad ... ramming, unload, retry the whole command originally issued // now what :D ... big bad ... ramming, unload, retry the whole command originally issued
@ -755,7 +754,7 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
case CommunicationTimeout: case CommunicationTimeout:
case ProtocolError: case ProtocolError:
case ButtonPushed: case ButtonPushed:
if (! logic.InAutoRetry()){ if (!logic.InAutoRetry()) {
// Don't proceed to the park/save if we are doing an autoretry. // Don't proceed to the park/save if we are doing an autoretry.
SaveAndPark(move_axes); SaveAndPark(move_axes);
SaveHotendTemp(turn_off_nozzle); SaveHotendTemp(turn_off_nozzle);
@ -794,9 +793,8 @@ StepStatus MMU2::LogicStep(bool reportErrors) {
// can be silently handed over to a higher layer, no processing necessary at this spot // can be silently handed over to a higher layer, no processing necessary at this spot
break; break;
default: default:
if(reportErrors) { if (reportErrors) {
switch (ss) switch (ss) {
{
case CommandError: case CommandError:
ReportError(logic.Error(), ErrorSourceMMU); ReportError(logic.Error(), ErrorSourceMMU);
break; break;
@ -821,7 +819,7 @@ StepStatus MMU2::LogicStep(bool reportErrors) {
} }
} }
if( logic.Running() ){ if (logic.Running()) {
state = xState::Active; state = xState::Active;
} }
return ss; return ss;
@ -852,17 +850,17 @@ void MMU2::execute_extruder_sequence(const E_Step *sequence, uint8_t steps) {
void MMU2::execute_load_to_nozzle_sequence() { void MMU2::execute_load_to_nozzle_sequence() {
planner_synchronize(); planner_synchronize();
// Compensate for configurable Extra Loading Distance // Compensate for configurable Extra Loading Distance
planner_set_current_position_E( planner_get_current_position_E() - (logic.ExtraLoadDistance() - MMU2_FILAMENT_SENSOR_POSITION) ); planner_set_current_position_E(planner_get_current_position_E() - (logic.ExtraLoadDistance() - MMU2_FILAMENT_SENSOR_POSITION));
execute_extruder_sequence(load_to_nozzle_sequence, sizeof(load_to_nozzle_sequence) / sizeof (load_to_nozzle_sequence[0])); execute_extruder_sequence(load_to_nozzle_sequence, sizeof(load_to_nozzle_sequence) / sizeof(load_to_nozzle_sequence[0]));
} }
void MMU2::ReportError(ErrorCode ec, ErrorSource res) { void MMU2::ReportError(ErrorCode ec, ErrorSource res) {
// Due to a potential lossy error reporting layers linked to this hook // Due to a potential lossy error reporting layers linked to this hook
// we'd better report everything to make sure especially the error states // we'd better report everything to make sure especially the error states
// do not get lost. // do not get lost.
// - The good news here is the fact, that the MMU reports the errors repeatedly until resolved. // - The good news here is the fact, that the MMU reports the errors repeatedly until resolved.
// - The bad news is, that MMU not responding may repeatedly occur on printers not having the MMU at all. // - The bad news is, that MMU not responding may repeatedly occur on printers not having the MMU at all.
// //
// Not sure how to properly handle this situation, options: // Not sure how to properly handle this situation, options:
// - skip reporting "MMU not responding" (at least for now) // - skip reporting "MMU not responding" (at least for now)
// - report only changes of states (we can miss an error message) // - report only changes of states (we can miss an error message)
@ -870,7 +868,7 @@ void MMU2::ReportError(ErrorCode ec, ErrorSource res) {
// Right now the filtering of MMU_NOT_RESPONDING is done in ReportErrorHook() as it is not a problem if mmu2.cpp // 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 // 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: case ProgressCode::UnloadingToFinda:
unloadFilamentStarted = false; unloadFilamentStarted = false;
break; break;
@ -882,12 +880,12 @@ void MMU2::ReportError(ErrorCode ec, ErrorSource res) {
break; break;
} }
if( ec != lastErrorCode ){ // deduplicate: only report changes in error codes into the log if (ec != lastErrorCode) { // deduplicate: only report changes in error codes into the log
lastErrorCode = ec; lastErrorCode = ec;
lastErrorSource = res; lastErrorSource = res;
LogErrorEvent_P( _O(PrusaErrorTitle(PrusaErrorCodeIndex((uint16_t)ec))) ); LogErrorEvent_P(_O(PrusaErrorTitle(PrusaErrorCodeIndex((uint16_t)ec))));
if( ec != ErrorCode::OK ){ if (ec != ErrorCode::OK) {
IncrementMMUFails(); IncrementMMUFails();
// check if it is a "power" failure - we consider TMC-related errors as power failures // check if it is a "power" failure - we consider TMC-related errors as power failures
@ -908,29 +906,28 @@ void MMU2::ReportError(ErrorCode ec, ErrorSource res) {
} }
} }
if( !mmu2.RetryIfPossible((uint16_t)ec) ) { if (!mmu2.RetryIfPossible((uint16_t)ec)) {
// If retry attempts are all used up // If retry attempts are all used up
// or if 'Retry' operation is not available // or if 'Retry' operation is not available
// raise the MMU error sceen and wait for user input // raise the MMU error sceen and wait for user input
ReportErrorHook((CommandInProgress)logic.CommandInProgress(), (uint16_t)ec, uint8_t(lastErrorSource)); ReportErrorHook((CommandInProgress)logic.CommandInProgress(), (uint16_t)ec, uint8_t(lastErrorSource));
} }
static_assert(mmu2Magic[0] == 'M' static_assert(mmu2Magic[0] == 'M'
&& mmu2Magic[1] == 'M' && mmu2Magic[1] == 'M'
&& mmu2Magic[2] == 'U' && mmu2Magic[2] == 'U'
&& mmu2Magic[3] == '2' && mmu2Magic[3] == '2'
&& mmu2Magic[4] == ':' && mmu2Magic[4] == ':'
&& strlen_constexpr(mmu2Magic) == 5, && strlen_constexpr(mmu2Magic) == 5,
"MMU2 logging prefix mismatch, must be updated at various spots" "MMU2 logging prefix mismatch, must be updated at various spots");
);
} }
void MMU2::ReportProgress(ProgressCode pc) { void MMU2::ReportProgress(ProgressCode pc) {
ReportProgressHook((CommandInProgress)logic.CommandInProgress(), (uint16_t)pc); ReportProgressHook((CommandInProgress)logic.CommandInProgress(), (uint16_t)pc);
LogEchoEvent_P( _O(ProgressCodeToText((uint16_t)pc)) ); LogEchoEvent_P(_O(ProgressCodeToText((uint16_t)pc)));
} }
void MMU2::OnMMUProgressMsg(ProgressCode pc){ void MMU2::OnMMUProgressMsg(ProgressCode pc) {
if (pc != lastProgressCode) { if (pc != lastProgressCode) {
OnMMUProgressMsgChanged(pc); OnMMUProgressMsgChanged(pc);
} else { } else {
@ -938,7 +935,7 @@ void MMU2::OnMMUProgressMsg(ProgressCode pc){
} }
} }
void MMU2::OnMMUProgressMsgChanged(ProgressCode pc){ void MMU2::OnMMUProgressMsgChanged(ProgressCode pc) {
ReportProgress(pc); ReportProgress(pc);
lastProgressCode = pc; lastProgressCode = pc;
switch (pc) { switch (pc) {
@ -967,11 +964,11 @@ void MMU2::OnMMUProgressMsgChanged(ProgressCode pc){
} }
} }
void __attribute__((noinline)) MMU2::HelpUnloadToFinda(){ void __attribute__((noinline)) MMU2::HelpUnloadToFinda() {
MoveE(- MMU2_RETRY_UNLOAD_TO_FINDA_LENGTH, MMU2_RETRY_UNLOAD_TO_FINDA_FEED_RATE); MoveE(-MMU2_RETRY_UNLOAD_TO_FINDA_LENGTH, MMU2_RETRY_UNLOAD_TO_FINDA_FEED_RATE);
} }
void MMU2::OnMMUProgressMsgSame(ProgressCode pc){ void MMU2::OnMMUProgressMsgSame(ProgressCode pc) {
switch (pc) { switch (pc) {
case ProgressCode::UnloadingToFinda: case ProgressCode::UnloadingToFinda:
if (unloadFilamentStarted && !planner_any_moves()) { // Only plan a move if there is no move ongoing if (unloadFilamentStarted && !planner_any_moves()) { // Only plan a move if there is no move ongoing

View File

@ -7,12 +7,13 @@
#ifdef __AVR__ #ifdef __AVR__
#include "mmu2_protocol_logic.h" #include "mmu2_protocol_logic.h"
typedef float feedRate_t; typedef float feedRate_t;
#else #else
#include "protocol_logic.h" #include "protocol_logic.h"
#include "../../Marlin/src/core/macros.h" #include "../../Marlin/src/core/macros.h"
#include "../../Marlin/src/core/types.h" #include "../../Marlin/src/core/types.h"
#include <atomic> #include <atomic>
#endif #endif
struct E_Step; struct E_Step;
@ -34,34 +35,34 @@ struct Version {
class MMU2 { class MMU2 {
public: public:
MMU2(); MMU2();
/// Powers ON the MMU, then initializes the UART and protocol logic /// Powers ON the MMU, then initializes the UART and protocol logic
void Start(); void Start();
/// Stops the protocol logic, closes the UART, powers OFF the MMU /// Stops the protocol logic, closes the UART, powers OFF the MMU
void Stop(); void Stop();
inline xState State() const { return state; } inline xState State() const { return state; }
inline bool Enabled()const { return State() == xState::Active; } inline bool Enabled() const { return State() == xState::Active; }
/// Different levels of resetting the MMU /// Different levels of resetting the MMU
enum ResetForm : uint8_t { enum ResetForm : uint8_t {
Software = 0, ///< sends a X0 command into the MMU, the MMU will watchdog-reset itself Software = 0, ///< sends a X0 command into the MMU, the MMU will watchdog-reset itself
ResetPin = 1, ///< trigger the reset pin of the MMU ResetPin = 1, ///< trigger the reset pin of the MMU
CutThePower = 2 ///< power off and power on (that includes +5V and +24V power lines) CutThePower = 2 ///< power off and power on (that includes +5V and +24V power lines)
}; };
/// Saved print state on error. /// Saved print state on error.
enum SavedState: uint8_t { enum SavedState : uint8_t {
None = 0, // No state saved. None = 0, // No state saved.
ParkExtruder = 1, // The extruder was parked. ParkExtruder = 1, // The extruder was parked.
Cooldown = 2, // The extruder was allowed to cool. Cooldown = 2, // The extruder was allowed to cool.
CooldownPending = 4, CooldownPending = 4,
}; };
/// Source of operation error /// Source of operation error
enum ErrorSource: uint8_t { enum ErrorSource : uint8_t {
ErrorSourcePrinter = 0, ErrorSourcePrinter = 0,
ErrorSourceMMU = 1, ErrorSourceMMU = 1,
ErrorSourceNone = 0xFF, ErrorSourceNone = 0xFF,
@ -70,10 +71,10 @@ public:
/// Perform a reset of the MMU /// Perform a reset of the MMU
/// @param level physical form of the reset /// @param level physical form of the reset
void Reset(ResetForm level); void Reset(ResetForm level);
/// Power off the MMU (cut the power) /// Power off the MMU (cut the power)
void PowerOff(); void PowerOff();
/// Power on the MMU /// Power on the MMU
void PowerOn(); void PowerOn();
@ -97,7 +98,7 @@ public:
/// @param slot of the slot to be selected /// @param slot of the slot to be selected
/// @returns false if the operation cannot be performed (Stopped) /// @returns false if the operation cannot be performed (Stopped)
bool tool_change(uint8_t slot); bool tool_change(uint8_t slot);
/// Handling of special Tx, Tc, T? commands /// Handling of special Tx, Tc, T? commands
bool tool_change(char code, uint8_t slot); bool tool_change(char code, uint8_t slot);
@ -109,7 +110,7 @@ public:
/// Load (insert) filament just into the MMU (not into printer's nozzle) /// Load (insert) filament just into the MMU (not into printer's nozzle)
/// @returns false if the operation cannot be performed (Stopped) /// @returns false if the operation cannot be performed (Stopped)
bool load_filament(uint8_t slot); bool load_filament(uint8_t slot);
/// Load (push) filament from the MMU into the printer's nozzle /// Load (push) filament from the MMU into the printer's nozzle
/// @returns false if the operation cannot be performed (Stopped or cold extruder) /// @returns false if the operation cannot be performed (Stopped or cold extruder)
bool load_filament_to_nozzle(uint8_t slot); bool load_filament_to_nozzle(uint8_t slot);
@ -137,7 +138,7 @@ public:
/// @returns the active filament slot index (0-4) or 0xff in case of no active tool /// @returns the active filament slot index (0-4) or 0xff in case of no active tool
uint8_t get_current_tool() const; uint8_t get_current_tool() const;
/// @returns The filament slot index (0 to 4) that will be loaded next, 0xff in case of no active tool change /// @returns The filament slot index (0 to 4) that will be loaded next, 0xff in case of no active tool change
uint8_t get_tool_change_tool() const; uint8_t get_tool_change_tool() const;
bool set_filament_type(uint8_t slot, uint8_t type); bool set_filament_type(uint8_t slot, uint8_t type);
@ -145,14 +146,14 @@ public:
/// Issue a "button" click into the MMU - to be used from Error screens of the MMU /// Issue a "button" click into the MMU - to be used from Error screens of the MMU
/// to select one of the 3 possible options to resolve the issue /// to select one of the 3 possible options to resolve the issue
void Button(uint8_t index); void Button(uint8_t index);
/// Issue an explicit "homing" command into the MMU /// Issue an explicit "homing" command into the MMU
void Home(uint8_t mode); void Home(uint8_t mode);
/// @returns current state of FINDA (true=filament present, false=filament not present) /// @returns current state of FINDA (true=filament present, false=filament not present)
inline bool FindaDetectsFilament()const { return logic.FindaPressed(); } inline bool FindaDetectsFilament() const { return logic.FindaPressed(); }
inline uint16_t TotalFailStatistics()const { return logic.FailStatistics(); } inline uint16_t TotalFailStatistics() const { return logic.FailStatistics(); }
/// @returns Current error code /// @returns Current error code
inline ErrorCode MMUCurrentErrorCode() const { return logic.Error(); } inline ErrorCode MMUCurrentErrorCode() const { return logic.Error(); }
@ -162,11 +163,11 @@ public:
/// @returns the version of the connected MMU FW. /// @returns the version of the connected MMU FW.
/// In the future we'll return the trully detected FW version /// In the future we'll return the trully detected FW version
Version GetMMUFWVersion()const { Version GetMMUFWVersion() const {
if( State() == xState::Active ){ if (State() == xState::Active) {
return { logic.MmuFwVersionMajor(), logic.MmuFwVersionMinor(), logic.MmuFwVersionRevision() }; return { logic.MmuFwVersionMajor(), logic.MmuFwVersionMinor(), logic.MmuFwVersionRevision() };
} else { } else {
return { 0, 0, 0}; return { 0, 0, 0 };
} }
} }
@ -187,21 +188,21 @@ public:
/// Set toolchange counter to zero /// Set toolchange counter to zero
inline void ClearToolChangeCounter() { toolchange_counter = 0; }; inline void ClearToolChangeCounter() { toolchange_counter = 0; };
inline uint16_t TMCFailures()const { return tmcFailures; } inline uint16_t TMCFailures() const { return tmcFailures; }
inline void IncrementTMCFailures() { ++tmcFailures; } inline void IncrementTMCFailures() { ++tmcFailures; }
inline void ClearTMCFailures() { tmcFailures = 0; } inline void ClearTMCFailures() { tmcFailures = 0; }
private: private:
/// Perform software self-reset of the MMU (sends an X0 command) /// Perform software self-reset of the MMU (sends an X0 command)
void ResetX0(); void ResetX0();
/// Trigger reset pin of the MMU /// Trigger reset pin of the MMU
void TriggerResetPin(); void TriggerResetPin();
/// Perform power cycle of the MMU (cold boot) /// Perform power cycle of the MMU (cold boot)
/// Please note this is a blocking operation (sleeps for some time inside while doing the power cycle) /// Please note this is a blocking operation (sleeps for some time inside while doing the power cycle)
void PowerCycle(); void PowerCycle();
/// Stop the communication, but keep the MMU powered on (for scenarios with incorrect FW version) /// Stop the communication, but keep the MMU powered on (for scenarios with incorrect FW version)
void StopKeepPowered(); void StopKeepPowered();
@ -220,7 +221,7 @@ private:
/// Updates the global state of MMU (Active/Connecting/Stopped) at runtime, see @ref State /// Updates the global state of MMU (Active/Connecting/Stopped) at runtime, see @ref State
/// @param reportErrors true if Errors should raise MMU Error screen, false otherwise /// @param reportErrors true if Errors should raise MMU Error screen, false otherwise
StepStatus LogicStep(bool reportErrors); StepStatus LogicStep(bool reportErrors);
void filament_ramming(); void filament_ramming();
void execute_extruder_sequence(const E_Step *sequence, uint8_t steps); void execute_extruder_sequence(const E_Step *sequence, uint8_t steps);
void execute_load_to_nozzle_sequence(); void execute_load_to_nozzle_sequence();
@ -233,7 +234,7 @@ private:
/// Reports progress of operations into attached ExtUIs /// Reports progress of operations into attached ExtUIs
/// @param pc progress code, see ProgressCode /// @param pc progress code, see ProgressCode
void ReportProgress(ProgressCode pc); void ReportProgress(ProgressCode pc);
/// Responds to a change of MMU's progress /// Responds to a change of MMU's progress
/// - plans additional steps, e.g. starts the E-motor after fsensor trigger /// - plans additional steps, e.g. starts the E-motor after fsensor trigger
void OnMMUProgressMsg(ProgressCode pc); void OnMMUProgressMsg(ProgressCode pc);
@ -296,26 +297,26 @@ private:
void HelpUnloadToFinda(); void HelpUnloadToFinda();
ProtocolLogic logic; ///< implementation of the protocol logic layer ProtocolLogic logic; ///< implementation of the protocol logic layer
uint8_t extruder; ///< currently active slot in the MMU ... somewhat... not sure where to get it from yet uint8_t extruder; ///< currently active slot in the MMU ... somewhat... not sure where to get it from yet
uint8_t tool_change_extruder; ///< only used for UI purposes uint8_t tool_change_extruder; ///< only used for UI purposes
pos3d resume_position; pos3d resume_position;
int16_t resume_hotend_temp; int16_t resume_hotend_temp;
ProgressCode lastProgressCode = ProgressCode::OK; ProgressCode lastProgressCode = ProgressCode::OK;
ErrorCode lastErrorCode = ErrorCode::MMU_NOT_RESPONDING; ErrorCode lastErrorCode = ErrorCode::MMU_NOT_RESPONDING;
ErrorSource lastErrorSource = ErrorSource::ErrorSourceNone; ErrorSource lastErrorSource = ErrorSource::ErrorSourceNone;
Buttons lastButton = Buttons::NoButton; Buttons lastButton = Buttons::NoButton;
StepStatus logicStepLastStatus; StepStatus logicStepLastStatus;
enum xState state; enum xState state;
uint8_t mmu_print_saved; uint8_t mmu_print_saved;
bool loadFilamentStarted; bool loadFilamentStarted;
bool unloadFilamentStarted; bool unloadFilamentStarted;
friend struct LoadingToNozzleRAII; friend struct LoadingToNozzleRAII;
/// true in case we are doing the LoadToNozzle operation - that means the filament shall be loaded all the way down to the nozzle /// true in case we are doing the LoadToNozzle operation - that means the filament shall be loaded all the way down to the nozzle
/// unlike the mid-print ToolChange commands, which only load the first ~30mm and then the G-code takes over. /// unlike the mid-print ToolChange commands, which only load the first ~30mm and then the G-code takes over.

View File

@ -11,11 +11,11 @@ uint8_t PrusaErrorCodeIndex(uint16_t ec);
/// @returns pointer to a PROGMEM string representing the Title of the Prusa-Error-Codes error /// @returns pointer to a PROGMEM string representing the Title of the Prusa-Error-Codes error
/// @param i index of the error - obtained by calling ErrorCodeIndex /// @param i index of the error - obtained by calling ErrorCodeIndex
const char * PrusaErrorTitle(uint8_t i); const char *PrusaErrorTitle(uint8_t i);
/// @returns pointer to a PROGMEM string representing the multi-page Description of the Prusa-Error-Codes error /// @returns pointer to a PROGMEM string representing the multi-page Description of the Prusa-Error-Codes error
/// @param i index of the error - obtained by calling ErrorCodeIndex /// @param i index of the error - obtained by calling ErrorCodeIndex
const char * PrusaErrorDesc(uint8_t i); const char *PrusaErrorDesc(uint8_t i);
/// @returns the actual numerical value of the Prusa-Error-Codes error /// @returns the actual numerical value of the Prusa-Error-Codes error
/// @param i index of the error - obtained by calling ErrorCodeIndex /// @param i index of the error - obtained by calling ErrorCodeIndex
@ -27,10 +27,10 @@ uint8_t PrusaErrorButtons(uint8_t i);
/// @returns pointer to a PROGMEM string representing the Title of a button /// @returns pointer to a PROGMEM string representing the Title of a button
/// @param i index of the error - obtained by calling PrusaErrorButtons + extracting low or high nibble from the Btns pair /// @param i index of the error - obtained by calling PrusaErrorButtons + extracting low or high nibble from the Btns pair
const char * PrusaErrorButtonTitle(uint8_t bi); const char *PrusaErrorButtonTitle(uint8_t bi);
/// @returns pointer to a PROGMEM string representing the "More" button /// @returns pointer to a PROGMEM string representing the "More" button
const char * PrusaErrorButtonMore(); const char *PrusaErrorButtonMore();
/// Sets the selected button for later pick-up by the MMU state machine. /// Sets the selected button for later pick-up by the MMU state machine.
/// Used to save the GUI selection/decoupling /// Used to save the GUI selection/decoupling

View File

@ -8,8 +8,8 @@ namespace MMU2 {
/// Beware, the numeric codes are important and sent into the MMU /// Beware, the numeric codes are important and sent into the MMU
enum class FilamentState : uint_fast8_t { enum class FilamentState : uint_fast8_t {
NOT_PRESENT = 0, ///< filament sensor doesn't see the filament NOT_PRESENT = 0, ///< filament sensor doesn't see the filament
AT_FSENSOR = 1, ///< filament detected by the filament sensor, but the nozzle has not detected the filament yet AT_FSENSOR = 1, ///< filament detected by the filament sensor, but the nozzle has not detected the filament yet
IN_NOZZLE = 2, ///< filament detected by the filament sensor and also loaded in the nozzle IN_NOZZLE = 2, ///< filament detected by the filament sensor and also loaded in the nozzle
UNAVAILABLE = 3 ///< sensor not available (likely not connected due broken cable) UNAVAILABLE = 3 ///< sensor not available (likely not connected due broken cable)
}; };

View File

@ -20,18 +20,36 @@ void LogEchoEvent_P(const char *msg);
} // namespace } // namespace
#define SERIAL_MMU2() { serialprintPGM(mmu2Magic); } #define SERIAL_MMU2() \
{ serialprintPGM(mmu2Magic); }
#define MMU2_ECHO_MSGLN(S) do{ SERIAL_ECHO_START; SERIAL_MMU2(); SERIAL_ECHOLN(S); }while(0) #define MMU2_ECHO_MSGLN(S) \
#define MMU2_ERROR_MSGLN(S) MMU2_ECHO_MSGLN(S) //!@todo Decide MMU2 errors on serial line do { \
#define MMU2_ECHO_MSGRPGM(S) do{ SERIAL_ECHO_START; SERIAL_MMU2(); SERIAL_ECHORPGM(S); }while(0) SERIAL_ECHO_START(); \
#define MMU2_ERROR_MSGRPGM(S) MMU2_ECHO_MSGRPGM(S) //!@todo Decide MMU2 errors on serial line SERIAL_MMU2(); \
SERIAL_ECHOLN(S); \
} while (0)
#define MMU2_ERROR_MSGLN(S) MMU2_ECHO_MSGLN(S) //!@todo Decide MMU2 errors on serial line
#define MMU2_ECHO_MSGRPGM(S) \
do { \
SERIAL_ECHO_START(); \
SERIAL_MMU2(); \
SERIAL_ECHO(S); \
} while (0)
#define MMU2_ERROR_MSGRPGM(S) MMU2_ECHO_MSGRPGM(S) //!@todo Decide MMU2 errors on serial line
#define MMU2_ECHO_MSG(S) \
do { \
SERIAL_ECHO_START(); \
SERIAL_MMU2(); \
SERIAL_ECHO(S); \
} while (0)
#define MMU2_ERROR_MSG(S) MMU2_ECHO_MSG(S) //!@todo Decide MMU2 errors on serial line
#else // #ifndef UNITTEST #else // #ifndef UNITTEST
#define MMU2_ECHO_MSGLN(S) /* */ #define MMU2_ECHO_MSGLN(S) /* */
#define MMU2_ERROR_MSGLN(S) /* */ #define MMU2_ERROR_MSGLN(S) /* */
#define MMU2_ECHO_MSGRPGM(S) /* */ #define MMU2_ECHO_MSGRPGM(S) /* */
#define MMU2_ERROR_MSGRPGM(S) /* */ #define MMU2_ERROR_MSGRPGM(S) /* */
#endif // #ifndef UNITTEST #endif // #ifndef UNITTEST

View File

@ -3,12 +3,12 @@
#include "mmu2_fsensor.h" #include "mmu2_fsensor.h"
#ifdef __AVR__ #ifdef __AVR__
// on MK3/S/+ we shuffle the timers a bit, thus "_millis" may not equal "millis" // on MK3/S/+ we shuffle the timers a bit, thus "_millis" may not equal "millis"
#include "system_timer.h" #include "system_timer.h"
#else #else
// irrelevant on Buddy FW, just keep "_millis" as "millis" // irrelevant on Buddy FW, just keep "_millis" as "millis"
#include <wiring_time.h> #include <wiring_time.h>
#define _millis millis #define _millis millis
#endif #endif
#include <string.h> #include <string.h>
@ -18,13 +18,13 @@ namespace MMU2 {
static const uint8_t supportedMmuFWVersion[3] PROGMEM = { 2, 1, 6 }; static const uint8_t supportedMmuFWVersion[3] PROGMEM = { 2, 1, 6 };
const uint8_t ProtocolLogic::regs8Addrs[ProtocolLogic::regs8Count] PROGMEM = { const uint8_t ProtocolLogic::regs8Addrs[ProtocolLogic::regs8Count] PROGMEM = {
8, // FINDA state 8, // FINDA state
0x1b, // Selector slot 0x1b, // Selector slot
0x1c, // Idler slot 0x1c, // Idler slot
}; };
const uint8_t ProtocolLogic::regs16Addrs[ProtocolLogic::regs16Count] PROGMEM = { const uint8_t ProtocolLogic::regs16Addrs[ProtocolLogic::regs16Count] PROGMEM = {
4, // MMU errors - aka statistics 4, // MMU errors - aka statistics
0x1a, // Pulley position [mm] 0x1a, // Pulley position [mm]
}; };
@ -52,10 +52,10 @@ void ProtocolLogic::StartReading8bitRegisters() {
SendReadRegister(pgm_read_byte(regs8Addrs + regIndex), ScopeState::Reading8bitRegisters); SendReadRegister(pgm_read_byte(regs8Addrs + regIndex), ScopeState::Reading8bitRegisters);
} }
void ProtocolLogic::ProcessRead8bitRegister(){ void ProtocolLogic::ProcessRead8bitRegister() {
regs8[regIndex] = rsp.paramValue; regs8[regIndex] = rsp.paramValue;
++regIndex; ++regIndex;
if(regIndex >= regs8Count){ if (regIndex >= regs8Count) {
// proceed with reading 16bit registers // proceed with reading 16bit registers
StartReading16bitRegisters(); StartReading16bitRegisters();
} else { } else {
@ -68,10 +68,10 @@ void ProtocolLogic::StartReading16bitRegisters() {
SendReadRegister(pgm_read_byte(regs16Addrs + regIndex), ScopeState::Reading16bitRegisters); SendReadRegister(pgm_read_byte(regs16Addrs + regIndex), ScopeState::Reading16bitRegisters);
} }
ProtocolLogic::ScopeState __attribute__((noinline)) ProtocolLogic::ProcessRead16bitRegister(ProtocolLogic::ScopeState stateAtEnd){ ProtocolLogic::ScopeState __attribute__((noinline)) ProtocolLogic::ProcessRead16bitRegister(ProtocolLogic::ScopeState stateAtEnd) {
regs16[regIndex] = rsp.paramValue; regs16[regIndex] = rsp.paramValue;
++regIndex; ++regIndex;
if(regIndex >= regs16Count){ if (regIndex >= regs16Count) {
return stateAtEnd; return stateAtEnd;
} else { } else {
SendReadRegister(pgm_read_byte(regs16Addrs + regIndex), ScopeState::Reading16bitRegisters); SendReadRegister(pgm_read_byte(regs16Addrs + regIndex), ScopeState::Reading16bitRegisters);
@ -84,9 +84,9 @@ void ProtocolLogic::StartWritingInitRegisters() {
SendWriteRegister(pgm_read_byte(initRegs8Addrs + regIndex), initRegs8[regIndex], ScopeState::WritingInitRegisters); SendWriteRegister(pgm_read_byte(initRegs8Addrs + regIndex), initRegs8[regIndex], ScopeState::WritingInitRegisters);
} }
bool __attribute__((noinline)) ProtocolLogic::ProcessWritingInitRegister(){ bool __attribute__((noinline)) ProtocolLogic::ProcessWritingInitRegister() {
++regIndex; ++regIndex;
if(regIndex >= initRegs8Count){ if (regIndex >= initRegs8Count) {
return true; return true;
} else { } else {
SendWriteRegister(pgm_read_byte(initRegs8Addrs + regIndex), initRegs8[regIndex], ScopeState::WritingInitRegisters); SendWriteRegister(pgm_read_byte(initRegs8Addrs + regIndex), initRegs8[regIndex], ScopeState::WritingInitRegisters);
@ -114,7 +114,7 @@ void ProtocolLogic::SendReadRegister(uint8_t index, ScopeState nextState) {
scopeState = nextState; scopeState = nextState;
} }
void ProtocolLogic::SendWriteRegister(uint8_t index, uint16_t value, ScopeState nextState){ void ProtocolLogic::SendWriteRegister(uint8_t index, uint16_t value, ScopeState nextState) {
SendWriteMsg(RequestMsg(RequestMsgCodes::Write, index, value)); SendWriteMsg(RequestMsg(RequestMsgCodes::Write, index, value));
scopeState = nextState; scopeState = nextState;
} }
@ -124,18 +124,18 @@ struct OldMMUFWDetector {
uint8_t ok; uint8_t ok;
inline constexpr OldMMUFWDetector() inline constexpr OldMMUFWDetector()
: ok(0) {} : ok(0) {}
enum class State : uint8_t { MatchingPart, enum class State : uint8_t { MatchingPart,
SomethingElse, SomethingElse,
Matched }; Matched };
/// @returns true when "ok\n" gets detected /// @returns true when "ok\n" gets detected
State Detect(uint8_t c){ State Detect(uint8_t c) {
// consume old MMU FW's data if any -> avoid confusion of protocol decoder // consume old MMU FW's data if any -> avoid confusion of protocol decoder
if(ok == 0 && c == 'o'){ if (ok == 0 && c == 'o') {
++ok; ++ok;
return State::MatchingPart; return State::MatchingPart;
} else if(ok == 1 && c == 'k'){ } else if (ok == 1 && c == 'k') {
++ok; ++ok;
return State::Matched; return State::Matched;
} }
@ -146,9 +146,9 @@ struct OldMMUFWDetector {
StepStatus ProtocolLogic::ExpectingMessage() { StepStatus ProtocolLogic::ExpectingMessage() {
int bytesConsumed = 0; int bytesConsumed = 0;
int c = -1; int c = -1;
OldMMUFWDetector oldMMUh4x0r; // old MMU FW hacker ;) OldMMUFWDetector oldMMUh4x0r; // old MMU FW hacker ;)
// try to consume as many rx bytes as possible (until a message has been completed) // try to consume as many rx bytes as possible (until a message has been completed)
while ((c = uart->read()) >= 0) { while ((c = uart->read()) >= 0) {
++bytesConsumed; ++bytesConsumed;
@ -162,16 +162,16 @@ StepStatus ProtocolLogic::ExpectingMessage() {
return MessageReady; return MessageReady;
case DecodeStatus::NeedMoreData: case DecodeStatus::NeedMoreData:
break; break;
case DecodeStatus::Error:{ case DecodeStatus::Error: {
// consume old MMU FW's data if any -> avoid confusion of protocol decoder // consume old MMU FW's data if any -> avoid confusion of protocol decoder
auto old = oldMMUh4x0r.Detect(c); auto old = oldMMUh4x0r.Detect(c);
if( old == OldMMUFWDetector::State::Matched ){ if (old == OldMMUFWDetector::State::Matched) {
// Old MMU FW 1.0.6 detected. Firmwares are incompatible. // Old MMU FW 1.0.6 detected. Firmwares are incompatible.
return VersionMismatch; return VersionMismatch;
} else if( old == OldMMUFWDetector::State::MatchingPart ){ } else if (old == OldMMUFWDetector::State::MatchingPart) {
break; break;
} }
} }
[[fallthrough]]; // otherwise [[fallthrough]]; // otherwise
default: default:
RecordUARTActivity(); // something has happened on the UART, update the timeout record RecordUARTActivity(); // something has happened on the UART, update the timeout record
@ -195,7 +195,7 @@ void ProtocolLogic::SendMsg(RequestMsg rq) {
RecordUARTActivity(); RecordUARTActivity();
} }
void ProtocolLogic::SendWriteMsg(RequestMsg rq){ void ProtocolLogic::SendWriteMsg(RequestMsg rq) {
uint8_t txbuff[Protocol::MaxRequestSize()]; uint8_t txbuff[Protocol::MaxRequestSize()];
uint8_t len = Protocol::EncodeWriteRequest(rq.value, rq.value2, txbuff); uint8_t len = Protocol::EncodeWriteRequest(rq.value, rq.value2, txbuff);
uart->write(txbuff, len); uart->write(txbuff, len);
@ -242,7 +242,7 @@ StepStatus ProtocolLogic::ProcessVersionResponse(uint8_t stage) {
} }
StepStatus ProtocolLogic::ScopeStep() { StepStatus ProtocolLogic::ScopeStep() {
if ( ! ExpectsResponse() ) { if (!ExpectsResponse()) {
// we are waiting for something // we are waiting for something
switch (currentScope) { switch (currentScope) {
case Scope::DelayedRestart: case Scope::DelayedRestart:
@ -296,7 +296,7 @@ StepStatus ProtocolLogic::StartSeqStep() {
} }
return Processing; return Processing;
case ScopeState::WritingInitRegisters: case ScopeState::WritingInitRegisters:
if( ProcessWritingInitRegister() ){ if (ProcessWritingInitRegister()) {
SendAndUpdateFilamentSensor(); SendAndUpdateFilamentSensor();
} }
return Processing; return Processing;
@ -354,7 +354,7 @@ StepStatus ProtocolLogic::ProcessCommandQueryResponse() {
case ResponseMsgParamCodes::Finished: case ResponseMsgParamCodes::Finished:
// We must check whether the "finished" is actually related to the command issued into the MMU // We must check whether the "finished" is actually related to the command issued into the MMU
// It can also be an X0 F which means MMU just successfully restarted. // It can also be an X0 F which means MMU just successfully restarted.
if( ReqMsg().code == rsp.request.code && ReqMsg().value == rsp.request.value ){ if (ReqMsg().code == rsp.request.code && ReqMsg().value == rsp.request.value) {
progressCode = ProgressCode::OK; progressCode = ProgressCode::OK;
scopeState = ScopeState::Ready; scopeState = ScopeState::Ready;
rq = RequestMsg(RequestMsgCodes::unknown, 0); // clear the successfully finished request rq = RequestMsg(RequestMsgCodes::unknown, 0); // clear the successfully finished request
@ -449,7 +449,7 @@ StepStatus ProtocolLogic::IdleStep() {
StartReading8bitRegisters(); StartReading8bitRegisters();
return ButtonPushed; return ButtonPushed;
case ResponseMsgParamCodes::Finished: case ResponseMsgParamCodes::Finished:
if( ReqMsg().code != RequestMsgCodes::unknown ){ if (ReqMsg().code != RequestMsgCodes::unknown) {
// got reset while doing some other command - the originally issued command was interrupted! // got reset while doing some other command - the originally issued command was interrupted!
// this must be solved by the upper layer, protocol logic doesn't have all the context (like unload before trying again) // this must be solved by the upper layer, protocol logic doesn't have all the context (like unload before trying again)
IdleRestart(); IdleRestart();
@ -526,8 +526,7 @@ ProtocolLogic::ProtocolLogic(MMU2Serial *uart, uint8_t extraLoadDistance, uint8_
, lastFSensor((uint8_t)WhereIsFilament()) , lastFSensor((uint8_t)WhereIsFilament())
, regIndex(0) , regIndex(0)
, retryAttempts(MAX_RETRIES) , retryAttempts(MAX_RETRIES)
, inAutoRetry(false) , inAutoRetry(false) {
{
// @@TODO currently, I don't see a way of writing the initialization better :( // @@TODO currently, I don't see a way of writing the initialization better :(
// I'd like to write something like: initRegs8 { extraLoadDistance, pulleySlowFeedrate } // I'd like to write something like: initRegs8 { extraLoadDistance, pulleySlowFeedrate }
// avr-gcc seems to like such a syntax, ARM gcc doesn't // avr-gcc seems to like such a syntax, ARM gcc doesn't
@ -583,11 +582,11 @@ void ProtocolLogic::Home(uint8_t mode) {
PlanGenericRequest(RequestMsg(RequestMsgCodes::Home, mode)); PlanGenericRequest(RequestMsg(RequestMsgCodes::Home, mode));
} }
void ProtocolLogic::ReadRegister(uint8_t address){ void ProtocolLogic::ReadRegister(uint8_t address) {
PlanGenericRequest(RequestMsg(RequestMsgCodes::Read, address)); PlanGenericRequest(RequestMsg(RequestMsgCodes::Read, address));
} }
void ProtocolLogic::WriteRegister(uint8_t address, uint16_t data){ void ProtocolLogic::WriteRegister(uint8_t address, uint16_t data) {
PlanGenericRequest(RequestMsg(RequestMsgCodes::Write, address, data)); PlanGenericRequest(RequestMsg(RequestMsgCodes::Write, address, data));
} }
@ -599,23 +598,23 @@ void ProtocolLogic::PlanGenericRequest(RequestMsg rq) {
} }
bool ProtocolLogic::ActivatePlannedRequest() { bool ProtocolLogic::ActivatePlannedRequest() {
switch(plannedRq.code){ switch (plannedRq.code) {
case RequestMsgCodes::Button: case RequestMsgCodes::Button:
// only issue the button to the MMU and do not restart the state machines // only issue the button to the MMU and do not restart the state machines
SendButton(plannedRq.value); SendButton(plannedRq.value);
plannedRq = RequestMsg(RequestMsgCodes::unknown, 0); plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);
return true; return true;
case RequestMsgCodes::Read: case RequestMsgCodes::Read:
SendReadRegister(plannedRq.value, ScopeState::ReadRegisterSent ); SendReadRegister(plannedRq.value, ScopeState::ReadRegisterSent);
plannedRq = RequestMsg(RequestMsgCodes::unknown, 0); plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);
return true; return true;
case RequestMsgCodes::Write: case RequestMsgCodes::Write:
SendWriteRegister(plannedRq.value, plannedRq.value2, ScopeState::WriteRegisterSent ); SendWriteRegister(plannedRq.value, plannedRq.value2, ScopeState::WriteRegisterSent);
plannedRq = RequestMsg(RequestMsgCodes::unknown, 0); plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);
return true; return true;
case RequestMsgCodes::unknown: case RequestMsgCodes::unknown:
return false; return false;
default:// commands default: // commands
currentScope = Scope::Command; currentScope = Scope::Command;
SetRequestMsg(plannedRq); SetRequestMsg(plannedRq);
plannedRq = RequestMsg(RequestMsgCodes::unknown, 0); plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
constexpr inline int strlen_constexpr(const char* str){ constexpr inline int strlen_constexpr(const char *str) {
return *str ? 1 + strlen_constexpr(str + 1) : 0; return *str ? 1 + strlen_constexpr(str + 1) : 0;
} }