clang-format
This commit is contained in:
parent
0555376502
commit
528abcb8d8
|
|
@ -15,22 +15,22 @@
|
|||
#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.
|
||||
// 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
|
||||
|
||||
namespace MMU2 {
|
||||
|
||||
template<typename F>
|
||||
void waitForHotendTargetTemp(uint16_t delay, F f){
|
||||
template <typename F>
|
||||
void waitForHotendTargetTemp(uint16_t delay, F f) {
|
||||
while (((thermal_degTargetHotend() - thermal_degHotend()) > 5)) {
|
||||
f();
|
||||
safe_delay_keep_alive(delay);
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForHotendTargetTempBeep(){
|
||||
void WaitForHotendTargetTempBeep() {
|
||||
waitForHotendTargetTemp(3000, []{ });
|
||||
MakeSound(Prompt);
|
||||
}
|
||||
|
|
@ -51,14 +51,13 @@ MMU2::MMU2()
|
|||
, unloadFilamentStarted(false)
|
||||
, loadingToNozzle(false)
|
||||
, toolchange_counter(0)
|
||||
, tmcFailures(0)
|
||||
{
|
||||
, tmcFailures(0) {
|
||||
}
|
||||
|
||||
void MMU2::Start() {
|
||||
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
|
||||
|
||||
extruder = MMU2_NO_TOOL;
|
||||
|
|
@ -75,13 +74,13 @@ void MMU2::Stop() {
|
|||
PowerOff(); // This also disables the MMU in the EEPROM.
|
||||
}
|
||||
|
||||
void MMU2::StopKeepPowered(){
|
||||
void MMU2::StopKeepPowered() {
|
||||
state = xState::Stopped;
|
||||
logic.Stop();
|
||||
mmu2Serial.close();
|
||||
}
|
||||
|
||||
void MMU2::Reset(ResetForm level){
|
||||
void MMU2::Reset(ResetForm level) {
|
||||
switch (level) {
|
||||
case Software:
|
||||
ResetX0();
|
||||
|
|
@ -101,13 +100,13 @@ void MMU2::ResetX0() {
|
|||
logic.ResetMMU(); // Send soft reset
|
||||
}
|
||||
|
||||
void MMU2::TriggerResetPin(){
|
||||
void MMU2::TriggerResetPin() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void MMU2::PowerCycle(){
|
||||
void MMU2::PowerCycle() {
|
||||
// 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
|
||||
// assert this function is never called in the MK3 FW? Do we even care?
|
||||
PowerOff();
|
||||
|
|
@ -115,36 +114,36 @@ void MMU2::PowerCycle(){
|
|||
PowerOn();
|
||||
}
|
||||
|
||||
void MMU2::PowerOff(){
|
||||
void MMU2::PowerOff() {
|
||||
power_off();
|
||||
}
|
||||
|
||||
void MMU2::PowerOn(){
|
||||
void MMU2::PowerOn() {
|
||||
power_on();
|
||||
}
|
||||
|
||||
bool MMU2::ReadRegister(uint8_t address){
|
||||
if( ! WaitForMMUReady())
|
||||
bool MMU2::ReadRegister(uint8_t address) {
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
do {
|
||||
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;
|
||||
}
|
||||
|
||||
bool MMU2::WriteRegister(uint8_t address, uint16_t data){
|
||||
if( ! WaitForMMUReady())
|
||||
bool MMU2::WriteRegister(uint8_t address, uint16_t data) {
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
do {
|
||||
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;
|
||||
}
|
||||
|
|
@ -193,13 +192,13 @@ struct ReportingRAII {
|
|||
: cip(cip) {
|
||||
BeginReport(cip, (uint16_t)ProgressCode::EngagingIdler);
|
||||
}
|
||||
inline ~ReportingRAII(){
|
||||
inline ~ReportingRAII() {
|
||||
EndReport(cip, (uint16_t)ProgressCode::OK);
|
||||
}
|
||||
};
|
||||
|
||||
bool MMU2::WaitForMMUReady(){
|
||||
switch(State()){
|
||||
bool MMU2::WaitForMMUReady() {
|
||||
switch (State()) {
|
||||
case xState::Stopped:
|
||||
return false;
|
||||
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()) {
|
||||
SetButtonResponse(ButtonOperations::Retry);
|
||||
// check, that Retry is actually allowed on that operation
|
||||
if( ButtonAvailable(ec) != NoButton ){
|
||||
if (ButtonAvailable(ec) != NoButton) {
|
||||
logic.SetInAutoRetry(true);
|
||||
SERIAL_ECHOLNPGM("RetryButtonPressed");
|
||||
// We don't decrement until the button is acknowledged by the MMU.
|
||||
|
|
@ -226,20 +225,19 @@ bool MMU2::RetryIfPossible(uint16_t ec){
|
|||
return false;
|
||||
}
|
||||
|
||||
bool MMU2::VerifyFilamentEnteredPTFE()
|
||||
{
|
||||
bool MMU2::VerifyFilamentEnteredPTFE() {
|
||||
planner_synchronize();
|
||||
|
||||
if (WhereIsFilament() == FilamentState::NOT_PRESENT) return false;
|
||||
if (WhereIsFilament() == FilamentState::NOT_PRESENT)
|
||||
return false;
|
||||
|
||||
uint8_t fsensorState = 0;
|
||||
// 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
|
||||
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
|
||||
// A single 0 reading will set the bit.
|
||||
fsensorState |= (WhereIsFilament() == FilamentState::NOT_PRESENT);
|
||||
|
|
@ -247,8 +245,7 @@ bool MMU2::VerifyFilamentEnteredPTFE()
|
|||
marlin_manage_inactivity(true);
|
||||
}
|
||||
|
||||
if (fsensorState)
|
||||
{
|
||||
if (fsensorState) {
|
||||
IncrementLoadFails();
|
||||
return false;
|
||||
} 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
|
||||
for(uint8_t retries = MAX_RETRIES; retries; --retries){
|
||||
for(;;) {
|
||||
for (uint8_t retries = MAX_RETRIES; retries; --retries) {
|
||||
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
|
||||
tool_change_extruder = slot;
|
||||
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;
|
||||
// otherwise: failed to perform the command - unload first and then let it run again
|
||||
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.
|
||||
}
|
||||
// reset current position to whatever the planner thinks it is
|
||||
planner_set_current_position_E( planner_get_current_position_E() );
|
||||
if (VerifyFilamentEnteredPTFE()){
|
||||
planner_set_current_position_E(planner_get_current_position_E());
|
||||
if (VerifyFilamentEnteredPTFE()) {
|
||||
return true; // success
|
||||
} else { // Prepare a retry attempt
|
||||
} else { // Prepare a retry attempt
|
||||
unload();
|
||||
if( retries == 2 && cutter_enabled()){
|
||||
if (retries == 2 && cutter_enabled()) {
|
||||
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
|
||||
}
|
||||
|
||||
void MMU2::ToolChangeCommon(uint8_t slot){
|
||||
while( ! ToolChangeCommonOnce(slot) ){ // while not successfully fed into extruder's PTFE tube
|
||||
void MMU2::ToolChangeCommon(uint8_t slot) {
|
||||
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
|
||||
// @@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);
|
||||
|
|
@ -312,7 +309,7 @@ void MMU2::ToolChangeCommon(uint8_t slot){
|
|||
}
|
||||
|
||||
bool MMU2::tool_change(uint8_t slot) {
|
||||
if( ! WaitForMMUReady())
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
|
||||
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.
|
||||
///- 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) {
|
||||
if( ! WaitForMMUReady())
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
|
||||
FSensorBlockRunout blockRunout;
|
||||
|
||||
switch (code) {
|
||||
case '?': {
|
||||
waitForHotendTargetTemp(100, []{});
|
||||
waitForHotendTargetTemp(100, [] {});
|
||||
load_filament_to_nozzle(slot);
|
||||
} break;
|
||||
|
||||
|
|
@ -357,7 +354,7 @@ bool MMU2::tool_change(char code, uint8_t slot) {
|
|||
} break;
|
||||
|
||||
case 'c': {
|
||||
waitForHotendTargetTemp(100, []{});
|
||||
waitForHotendTargetTemp(100, [] {});
|
||||
execute_load_to_nozzle_sequence();
|
||||
} break;
|
||||
}
|
||||
|
|
@ -378,25 +375,25 @@ uint8_t MMU2::get_tool_change_tool() const {
|
|||
}
|
||||
|
||||
bool MMU2::set_filament_type(uint8_t /*slot*/, uint8_t /*type*/) {
|
||||
if( ! WaitForMMUReady())
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
|
||||
// @@TODO - this is not supported in the new MMU yet
|
||||
// slot = slot; // @@TODO
|
||||
// type = type; // @@TODO
|
||||
// slot = slot; // @@TODO
|
||||
// type = type; // @@TODO
|
||||
// cmd_arg = filamentType;
|
||||
// command(MMU_CMD_F0 + index);
|
||||
|
||||
if( ! manage_response(false, false) ){
|
||||
if (!manage_response(false, false)) {
|
||||
// @@TODO failed to perform the command - retry
|
||||
;
|
||||
} // true, true); -- Comment: how is it possible for a filament type set to fail?
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MMU2::unload() {
|
||||
if( ! WaitForMMUReady())
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
|
||||
WaitForHotendTargetTempBeep();
|
||||
|
|
@ -408,10 +405,10 @@ bool MMU2::unload() {
|
|||
|
||||
// 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
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
Disable_E0();
|
||||
logic.UnloadFilament();
|
||||
if( manage_response(false, true) )
|
||||
if (manage_response(false, true))
|
||||
break;
|
||||
IncrementMMUFails();
|
||||
}
|
||||
|
|
@ -424,23 +421,23 @@ bool MMU2::unload() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /* = true */){
|
||||
if( ! WaitForMMUReady())
|
||||
bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /*= true*/) {
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
|
||||
if( enableFullScreenMsg ){
|
||||
if (enableFullScreenMsg) {
|
||||
FullScreenMsgCut(slot);
|
||||
}
|
||||
{
|
||||
if( FindaDetectsFilament() ){
|
||||
if (FindaDetectsFilament()) {
|
||||
unload();
|
||||
}
|
||||
|
||||
ReportingRAII rep(CommandInProgress::CutFilament);
|
||||
for(;;){
|
||||
for (;;) {
|
||||
Disable_E0();
|
||||
logic.CutFilament(slot);
|
||||
if( manage_response(false, true) )
|
||||
if (manage_response(false, true))
|
||||
break;
|
||||
IncrementMMUFails();
|
||||
}
|
||||
|
|
@ -451,7 +448,7 @@ bool MMU2::cut_filament(uint8_t slot, bool enableFullScreenMsg /* = true */){
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MMU2::loading_test(uint8_t slot){
|
||||
bool MMU2::loading_test(uint8_t slot) {
|
||||
FullScreenMsgTest(slot);
|
||||
tool_change(slot);
|
||||
planner_synchronize();
|
||||
|
|
@ -461,16 +458,16 @@ bool MMU2::loading_test(uint8_t slot){
|
|||
}
|
||||
|
||||
bool MMU2::load_filament(uint8_t slot) {
|
||||
if( ! WaitForMMUReady())
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
|
||||
FullScreenMsgLoad(slot);
|
||||
|
||||
ReportingRAII rep(CommandInProgress::LoadFilament);
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
Disable_E0();
|
||||
logic.LoadFilament(slot);
|
||||
if( manage_response(false, false) )
|
||||
if (manage_response(false, false))
|
||||
break;
|
||||
IncrementMMUFails();
|
||||
}
|
||||
|
|
@ -484,16 +481,17 @@ bool MMU2::load_filament(uint8_t slot) {
|
|||
|
||||
struct LoadingToNozzleRAII {
|
||||
MMU2 &mmu2;
|
||||
explicit inline LoadingToNozzleRAII(MMU2 &mmu2):mmu2(mmu2){
|
||||
explicit inline LoadingToNozzleRAII(MMU2 &mmu2)
|
||||
: mmu2(mmu2) {
|
||||
mmu2.loadingToNozzle = true;
|
||||
}
|
||||
inline ~LoadingToNozzleRAII(){
|
||||
inline ~LoadingToNozzleRAII() {
|
||||
mmu2.loadingToNozzle = false;
|
||||
}
|
||||
};
|
||||
|
||||
bool MMU2::load_filament_to_nozzle(uint8_t slot) {
|
||||
if( ! WaitForMMUReady())
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
|
||||
LoadingToNozzleRAII ln(*this);
|
||||
|
|
@ -506,7 +504,7 @@ bool MMU2::load_filament_to_nozzle(uint8_t slot) {
|
|||
ReportingRAII rep(CommandInProgress::ToolChange);
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
@ -521,22 +519,22 @@ bool MMU2::load_filament_to_nozzle(uint8_t slot) {
|
|||
}
|
||||
|
||||
bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
|
||||
if( ! WaitForMMUReady())
|
||||
if (!WaitForMMUReady())
|
||||
return false;
|
||||
|
||||
if( enableFullScreenMsg ){
|
||||
if (enableFullScreenMsg) {
|
||||
FullScreenMsgEject(slot);
|
||||
}
|
||||
{
|
||||
if( FindaDetectsFilament() ){
|
||||
if (FindaDetectsFilament()) {
|
||||
unload();
|
||||
}
|
||||
|
||||
ReportingRAII rep(CommandInProgress::EjectFilament);
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
Disable_E0();
|
||||
logic.EjectFilament(slot);
|
||||
if( manage_response(false, true) )
|
||||
if (manage_response(false, true))
|
||||
break;
|
||||
IncrementMMUFails();
|
||||
}
|
||||
|
|
@ -547,19 +545,20 @@ bool MMU2::eject_filament(uint8_t slot, bool enableFullScreenMsg /* = true */) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void MMU2::Button(uint8_t index){
|
||||
void MMU2::Button(uint8_t index) {
|
||||
LogEchoEvent_P(PSTR("Button"));
|
||||
logic.Button(index);
|
||||
}
|
||||
|
||||
void MMU2::Home(uint8_t mode){
|
||||
void MMU2::Home(uint8_t mode) {
|
||||
logic.Home(mode);
|
||||
}
|
||||
|
||||
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();
|
||||
resume_hotend_temp = thermal_degTargetHotend();
|
||||
mmu_print_saved |= SavedState::CooldownPending;
|
||||
|
|
@ -573,7 +572,7 @@ void MMU2::SaveAndPark(bool move_axes) {
|
|||
Disable_E0();
|
||||
planner_synchronize();
|
||||
|
||||
if (move_axes){
|
||||
if (move_axes) {
|
||||
mmu_print_saved |= SavedState::ParkExtruder;
|
||||
resume_position = planner_current_position(); // save current pos
|
||||
|
||||
|
|
@ -599,14 +598,14 @@ void MMU2::ResumeHotendTemp() {
|
|||
}
|
||||
if ((mmu_print_saved & SavedState::Cooldown) && resume_hotend_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);
|
||||
mmu_print_saved &= ~(SavedState::Cooldown);
|
||||
thermal_setTargetHotend(resume_hotend_temp);
|
||||
FullScreenMsgRestoringTemperature();
|
||||
//@todo better report the event and let the GUI do its work somewhere else
|
||||
ReportErrorHookSensorLineRender();
|
||||
waitForHotendTargetTemp(100, []{
|
||||
waitForHotendTargetTemp(100, [] {
|
||||
marlin_manage_inactivity(true);
|
||||
mmu2.mmu_loop_inner(false);
|
||||
ReportErrorHookDynamicRender();
|
||||
|
|
@ -617,13 +616,13 @@ void MMU2::ResumeHotendTemp() {
|
|||
}
|
||||
}
|
||||
|
||||
void MMU2::ResumeUnpark(){
|
||||
void MMU2::ResumeUnpark() {
|
||||
if (mmu_print_saved & SavedState::ParkExtruder) {
|
||||
LogEchoEvent_P(PSTR("Resuming XYZ"));
|
||||
|
||||
// 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));
|
||||
|
||||
|
||||
// Move Z_AXIS to saved position
|
||||
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);
|
||||
|
||||
// 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;
|
||||
lastButton = Buttons::NoButton; // Clear it.
|
||||
lastButton = Buttons::NoButton; // Clear it.
|
||||
}
|
||||
|
||||
switch (btn) {
|
||||
|
|
@ -648,7 +647,7 @@ void MMU2::CheckUserInput(){
|
|||
SERIAL_ECHOLN(btn);
|
||||
|
||||
// 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
|
||||
// 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,
|
||||
|
|
@ -668,7 +667,7 @@ void MMU2::CheckUserInput(){
|
|||
// A quick hack: for specific error codes move the E-motor every time.
|
||||
// Not sure if we can rely on the fsensor.
|
||||
// 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_TOO_EARLY:
|
||||
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
|
||||
safe_delay_keep_alive(0); // calls LogicStep() and remembers its return status
|
||||
|
||||
if (mmu_print_saved & SavedState::CooldownPending){
|
||||
if (!nozzleTimeout.running()){
|
||||
if (mmu_print_saved & SavedState::CooldownPending) {
|
||||
if (!nozzleTimeout.running()) {
|
||||
nozzleTimeout.start();
|
||||
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::Cooldown;
|
||||
thermal_setTargetHotend(0);
|
||||
|
|
@ -730,13 +729,13 @@ bool MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
|
|||
}
|
||||
|
||||
switch (logicStepLastStatus) {
|
||||
case Finished:
|
||||
case Finished:
|
||||
// command/operation completed, let Marlin continue its work
|
||||
// the E may have some more moves to finish - wait for them
|
||||
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.
|
||||
planner_synchronize();
|
||||
planner_synchronize();
|
||||
return true;
|
||||
case Interrupted:
|
||||
// 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 ProtocolError:
|
||||
case ButtonPushed:
|
||||
if (! logic.InAutoRetry()){
|
||||
if (!logic.InAutoRetry()) {
|
||||
// Don't proceed to the park/save if we are doing an autoretry.
|
||||
SaveAndPark(move_axes);
|
||||
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
|
||||
break;
|
||||
default:
|
||||
if(reportErrors) {
|
||||
switch (ss)
|
||||
{
|
||||
if (reportErrors) {
|
||||
switch (ss) {
|
||||
case CommandError:
|
||||
ReportError(logic.Error(), ErrorSourceMMU);
|
||||
break;
|
||||
|
|
@ -821,7 +819,7 @@ StepStatus MMU2::LogicStep(bool reportErrors) {
|
|||
}
|
||||
}
|
||||
|
||||
if( logic.Running() ){
|
||||
if (logic.Running()) {
|
||||
state = xState::Active;
|
||||
}
|
||||
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() {
|
||||
planner_synchronize();
|
||||
// Compensate for configurable Extra Loading Distance
|
||||
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]));
|
||||
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]));
|
||||
}
|
||||
|
||||
void MMU2::ReportError(ErrorCode ec, ErrorSource res) {
|
||||
// Due to a potential lossy error reporting layers linked to this hook
|
||||
// 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 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:
|
||||
// - skip reporting "MMU not responding" (at least for now)
|
||||
// - 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
|
||||
|
||||
// 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:
|
||||
unloadFilamentStarted = false;
|
||||
break;
|
||||
|
|
@ -882,12 +880,12 @@ void MMU2::ReportError(ErrorCode ec, ErrorSource res) {
|
|||
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;
|
||||
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();
|
||||
|
||||
// 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
|
||||
// or if 'Retry' operation is not available
|
||||
// raise the MMU error sceen and wait for user input
|
||||
ReportErrorHook((CommandInProgress)logic.CommandInProgress(), (uint16_t)ec, uint8_t(lastErrorSource));
|
||||
}
|
||||
|
||||
static_assert(mmu2Magic[0] == 'M'
|
||||
&& mmu2Magic[1] == 'M'
|
||||
&& mmu2Magic[2] == 'U'
|
||||
&& mmu2Magic[3] == '2'
|
||||
&& mmu2Magic[4] == ':'
|
||||
&& strlen_constexpr(mmu2Magic) == 5,
|
||||
"MMU2 logging prefix mismatch, must be updated at various spots"
|
||||
);
|
||||
static_assert(mmu2Magic[0] == 'M'
|
||||
&& mmu2Magic[1] == 'M'
|
||||
&& mmu2Magic[2] == 'U'
|
||||
&& mmu2Magic[3] == '2'
|
||||
&& mmu2Magic[4] == ':'
|
||||
&& strlen_constexpr(mmu2Magic) == 5,
|
||||
"MMU2 logging prefix mismatch, must be updated at various spots");
|
||||
}
|
||||
|
||||
void MMU2::ReportProgress(ProgressCode 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) {
|
||||
OnMMUProgressMsgChanged(pc);
|
||||
} else {
|
||||
|
|
@ -938,7 +935,7 @@ void MMU2::OnMMUProgressMsg(ProgressCode pc){
|
|||
}
|
||||
}
|
||||
|
||||
void MMU2::OnMMUProgressMsgChanged(ProgressCode pc){
|
||||
void MMU2::OnMMUProgressMsgChanged(ProgressCode pc) {
|
||||
ReportProgress(pc);
|
||||
lastProgressCode = pc;
|
||||
switch (pc) {
|
||||
|
|
@ -967,11 +964,11 @@ void MMU2::OnMMUProgressMsgChanged(ProgressCode pc){
|
|||
}
|
||||
}
|
||||
|
||||
void __attribute__((noinline)) MMU2::HelpUnloadToFinda(){
|
||||
MoveE(- MMU2_RETRY_UNLOAD_TO_FINDA_LENGTH, MMU2_RETRY_UNLOAD_TO_FINDA_FEED_RATE);
|
||||
void __attribute__((noinline)) MMU2::HelpUnloadToFinda() {
|
||||
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) {
|
||||
case ProgressCode::UnloadingToFinda:
|
||||
if (unloadFilamentStarted && !planner_any_moves()) { // Only plan a move if there is no move ongoing
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@
|
|||
#ifdef __AVR__
|
||||
#include "mmu2_protocol_logic.h"
|
||||
typedef float feedRate_t;
|
||||
|
||||
#else
|
||||
|
||||
#include "protocol_logic.h"
|
||||
#include "../../Marlin/src/core/macros.h"
|
||||
#include "../../Marlin/src/core/types.h"
|
||||
#include <atomic>
|
||||
#include "protocol_logic.h"
|
||||
#include "../../Marlin/src/core/macros.h"
|
||||
#include "../../Marlin/src/core/types.h"
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
struct E_Step;
|
||||
|
|
@ -34,34 +35,34 @@ struct Version {
|
|||
class MMU2 {
|
||||
public:
|
||||
MMU2();
|
||||
|
||||
|
||||
/// Powers ON the MMU, then initializes the UART and protocol logic
|
||||
void Start();
|
||||
|
||||
|
||||
/// Stops the protocol logic, closes the UART, powers OFF the MMU
|
||||
void Stop();
|
||||
|
||||
|
||||
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
|
||||
enum ResetForm : uint8_t {
|
||||
Software = 0, ///< sends a X0 command into the MMU, the MMU will watchdog-reset itself
|
||||
ResetPin = 1, ///< trigger the reset pin of the MMU
|
||||
Software = 0, ///< sends a X0 command into the MMU, the MMU will watchdog-reset itself
|
||||
ResetPin = 1, ///< trigger the reset pin of the MMU
|
||||
CutThePower = 2 ///< power off and power on (that includes +5V and +24V power lines)
|
||||
};
|
||||
|
||||
/// Saved print state on error.
|
||||
enum SavedState: uint8_t {
|
||||
None = 0, // No state saved.
|
||||
ParkExtruder = 1, // The extruder was parked.
|
||||
Cooldown = 2, // The extruder was allowed to cool.
|
||||
enum SavedState : uint8_t {
|
||||
None = 0, // No state saved.
|
||||
ParkExtruder = 1, // The extruder was parked.
|
||||
Cooldown = 2, // The extruder was allowed to cool.
|
||||
CooldownPending = 4,
|
||||
};
|
||||
|
||||
/// Source of operation error
|
||||
enum ErrorSource: uint8_t {
|
||||
enum ErrorSource : uint8_t {
|
||||
ErrorSourcePrinter = 0,
|
||||
ErrorSourceMMU = 1,
|
||||
ErrorSourceNone = 0xFF,
|
||||
|
|
@ -70,10 +71,10 @@ public:
|
|||
/// Perform a reset of the MMU
|
||||
/// @param level physical form of the reset
|
||||
void Reset(ResetForm level);
|
||||
|
||||
|
||||
/// Power off the MMU (cut the power)
|
||||
void PowerOff();
|
||||
|
||||
|
||||
/// Power on the MMU
|
||||
void PowerOn();
|
||||
|
||||
|
|
@ -97,7 +98,7 @@ public:
|
|||
/// @param slot of the slot to be selected
|
||||
/// @returns false if the operation cannot be performed (Stopped)
|
||||
bool tool_change(uint8_t slot);
|
||||
|
||||
|
||||
/// Handling of special Tx, Tc, T? commands
|
||||
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)
|
||||
/// @returns false if the operation cannot be performed (Stopped)
|
||||
bool load_filament(uint8_t slot);
|
||||
|
||||
|
||||
/// Load (push) filament from the MMU into the printer's nozzle
|
||||
/// @returns false if the operation cannot be performed (Stopped or cold extruder)
|
||||
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
|
||||
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;
|
||||
|
||||
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
|
||||
/// to select one of the 3 possible options to resolve the issue
|
||||
void Button(uint8_t index);
|
||||
|
||||
|
||||
/// Issue an explicit "homing" command into the MMU
|
||||
void Home(uint8_t mode);
|
||||
|
||||
/// @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
|
||||
inline ErrorCode MMUCurrentErrorCode() const { return logic.Error(); }
|
||||
|
|
@ -162,11 +163,11 @@ public:
|
|||
|
||||
/// @returns the version of the connected MMU FW.
|
||||
/// In the future we'll return the trully detected FW version
|
||||
Version GetMMUFWVersion()const {
|
||||
if( State() == xState::Active ){
|
||||
Version GetMMUFWVersion() const {
|
||||
if (State() == xState::Active) {
|
||||
return { logic.MmuFwVersionMajor(), logic.MmuFwVersionMinor(), logic.MmuFwVersionRevision() };
|
||||
} else {
|
||||
return { 0, 0, 0};
|
||||
return { 0, 0, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,21 +188,21 @@ public:
|
|||
/// Set toolchange counter to zero
|
||||
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 ClearTMCFailures() { tmcFailures = 0; }
|
||||
|
||||
private:
|
||||
/// Perform software self-reset of the MMU (sends an X0 command)
|
||||
void ResetX0();
|
||||
|
||||
|
||||
/// Trigger reset pin of the MMU
|
||||
void TriggerResetPin();
|
||||
|
||||
|
||||
/// 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)
|
||||
void PowerCycle();
|
||||
|
||||
|
||||
/// Stop the communication, but keep the MMU powered on (for scenarios with incorrect FW version)
|
||||
void StopKeepPowered();
|
||||
|
||||
|
|
@ -220,7 +221,7 @@ private:
|
|||
/// 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
|
||||
StepStatus LogicStep(bool reportErrors);
|
||||
|
||||
|
||||
void filament_ramming();
|
||||
void execute_extruder_sequence(const E_Step *sequence, uint8_t steps);
|
||||
void execute_load_to_nozzle_sequence();
|
||||
|
|
@ -233,7 +234,7 @@ private:
|
|||
/// Reports progress of operations into attached ExtUIs
|
||||
/// @param pc progress code, see ProgressCode
|
||||
void ReportProgress(ProgressCode pc);
|
||||
|
||||
|
||||
/// Responds to a change of MMU's progress
|
||||
/// - plans additional steps, e.g. starts the E-motor after fsensor trigger
|
||||
void OnMMUProgressMsg(ProgressCode pc);
|
||||
|
|
@ -296,26 +297,26 @@ private:
|
|||
|
||||
void HelpUnloadToFinda();
|
||||
|
||||
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
|
||||
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 tool_change_extruder; ///< only used for UI purposes
|
||||
|
||||
pos3d resume_position;
|
||||
int16_t resume_hotend_temp;
|
||||
|
||||
|
||||
ProgressCode lastProgressCode = ProgressCode::OK;
|
||||
ErrorCode lastErrorCode = ErrorCode::MMU_NOT_RESPONDING;
|
||||
ErrorSource lastErrorSource = ErrorSource::ErrorSourceNone;
|
||||
Buttons lastButton = Buttons::NoButton;
|
||||
|
||||
StepStatus logicStepLastStatus;
|
||||
|
||||
|
||||
enum xState state;
|
||||
|
||||
uint8_t mmu_print_saved;
|
||||
bool loadFilamentStarted;
|
||||
bool unloadFilamentStarted;
|
||||
|
||||
|
||||
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
|
||||
/// unlike the mid-print ToolChange commands, which only load the first ~30mm and then the G-code takes over.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
/// @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
|
||||
/// @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
|
||||
/// @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
|
||||
/// @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
|
||||
const char * PrusaErrorButtonMore();
|
||||
const char *PrusaErrorButtonMore();
|
||||
|
||||
/// Sets the selected button for later pick-up by the MMU state machine.
|
||||
/// Used to save the GUI selection/decoupling
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ namespace MMU2 {
|
|||
/// Beware, the numeric codes are important and sent into the MMU
|
||||
enum class FilamentState : uint_fast8_t {
|
||||
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
|
||||
IN_NOZZLE = 2, ///< filament detected by the filament sensor and also loaded in the nozzle
|
||||
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
|
||||
UNAVAILABLE = 3 ///< sensor not available (likely not connected due broken cable)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,18 +20,36 @@ void LogEchoEvent_P(const char *msg);
|
|||
|
||||
} // 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_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_ECHORPGM(S); }while(0)
|
||||
#define MMU2_ERROR_MSGRPGM(S) MMU2_ECHO_MSGRPGM(S) //!@todo Decide MMU2 errors on serial line
|
||||
#define MMU2_ECHO_MSGLN(S) \
|
||||
do { \
|
||||
SERIAL_ECHO_START(); \
|
||||
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
|
||||
|
||||
#define MMU2_ECHO_MSGLN(S) /* */
|
||||
#define MMU2_ERROR_MSGLN(S) /* */
|
||||
#define MMU2_ECHO_MSGRPGM(S) /* */
|
||||
#define MMU2_ERROR_MSGRPGM(S) /* */
|
||||
#define MMU2_ECHO_MSGLN(S) /* */
|
||||
#define MMU2_ERROR_MSGLN(S) /* */
|
||||
#define MMU2_ECHO_MSGRPGM(S) /* */
|
||||
#define MMU2_ERROR_MSGRPGM(S) /* */
|
||||
|
||||
#endif // #ifndef UNITTEST
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
#include "mmu2_fsensor.h"
|
||||
|
||||
#ifdef __AVR__
|
||||
// on MK3/S/+ we shuffle the timers a bit, thus "_millis" may not equal "millis"
|
||||
#include "system_timer.h"
|
||||
// on MK3/S/+ we shuffle the timers a bit, thus "_millis" may not equal "millis"
|
||||
#include "system_timer.h"
|
||||
#else
|
||||
// irrelevant on Buddy FW, just keep "_millis" as "millis"
|
||||
#include <wiring_time.h>
|
||||
#define _millis millis
|
||||
// irrelevant on Buddy FW, just keep "_millis" as "millis"
|
||||
#include <wiring_time.h>
|
||||
#define _millis millis
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
|
@ -18,13 +18,13 @@ namespace MMU2 {
|
|||
static const uint8_t supportedMmuFWVersion[3] PROGMEM = { 2, 1, 6 };
|
||||
|
||||
const uint8_t ProtocolLogic::regs8Addrs[ProtocolLogic::regs8Count] PROGMEM = {
|
||||
8, // FINDA state
|
||||
8, // FINDA state
|
||||
0x1b, // Selector slot
|
||||
0x1c, // Idler slot
|
||||
};
|
||||
|
||||
const uint8_t ProtocolLogic::regs16Addrs[ProtocolLogic::regs16Count] PROGMEM = {
|
||||
4, // MMU errors - aka statistics
|
||||
4, // MMU errors - aka statistics
|
||||
0x1a, // Pulley position [mm]
|
||||
};
|
||||
|
||||
|
|
@ -52,10 +52,10 @@ void ProtocolLogic::StartReading8bitRegisters() {
|
|||
SendReadRegister(pgm_read_byte(regs8Addrs + regIndex), ScopeState::Reading8bitRegisters);
|
||||
}
|
||||
|
||||
void ProtocolLogic::ProcessRead8bitRegister(){
|
||||
void ProtocolLogic::ProcessRead8bitRegister() {
|
||||
regs8[regIndex] = rsp.paramValue;
|
||||
++regIndex;
|
||||
if(regIndex >= regs8Count){
|
||||
if (regIndex >= regs8Count) {
|
||||
// proceed with reading 16bit registers
|
||||
StartReading16bitRegisters();
|
||||
} else {
|
||||
|
|
@ -68,10 +68,10 @@ void ProtocolLogic::StartReading16bitRegisters() {
|
|||
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;
|
||||
++regIndex;
|
||||
if(regIndex >= regs16Count){
|
||||
if (regIndex >= regs16Count) {
|
||||
return stateAtEnd;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
bool __attribute__((noinline)) ProtocolLogic::ProcessWritingInitRegister(){
|
||||
bool __attribute__((noinline)) ProtocolLogic::ProcessWritingInitRegister() {
|
||||
++regIndex;
|
||||
if(regIndex >= initRegs8Count){
|
||||
if (regIndex >= initRegs8Count) {
|
||||
return true;
|
||||
} else {
|
||||
SendWriteRegister(pgm_read_byte(initRegs8Addrs + regIndex), initRegs8[regIndex], ScopeState::WritingInitRegisters);
|
||||
|
|
@ -114,7 +114,7 @@ void ProtocolLogic::SendReadRegister(uint8_t index, 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));
|
||||
scopeState = nextState;
|
||||
}
|
||||
|
|
@ -124,18 +124,18 @@ struct OldMMUFWDetector {
|
|||
uint8_t ok;
|
||||
inline constexpr OldMMUFWDetector()
|
||||
: ok(0) {}
|
||||
|
||||
|
||||
enum class State : uint8_t { MatchingPart,
|
||||
SomethingElse,
|
||||
Matched };
|
||||
|
||||
|
||||
/// @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
|
||||
if(ok == 0 && c == 'o'){
|
||||
if (ok == 0 && c == 'o') {
|
||||
++ok;
|
||||
return State::MatchingPart;
|
||||
} else if(ok == 1 && c == 'k'){
|
||||
} else if (ok == 1 && c == 'k') {
|
||||
++ok;
|
||||
return State::Matched;
|
||||
}
|
||||
|
|
@ -146,9 +146,9 @@ struct OldMMUFWDetector {
|
|||
StepStatus ProtocolLogic::ExpectingMessage() {
|
||||
int bytesConsumed = 0;
|
||||
int c = -1;
|
||||
|
||||
|
||||
OldMMUFWDetector oldMMUh4x0r; // old MMU FW hacker ;)
|
||||
|
||||
|
||||
// try to consume as many rx bytes as possible (until a message has been completed)
|
||||
while ((c = uart->read()) >= 0) {
|
||||
++bytesConsumed;
|
||||
|
|
@ -162,16 +162,16 @@ StepStatus ProtocolLogic::ExpectingMessage() {
|
|||
return MessageReady;
|
||||
case DecodeStatus::NeedMoreData:
|
||||
break;
|
||||
case DecodeStatus::Error:{
|
||||
case DecodeStatus::Error: {
|
||||
// consume old MMU FW's data if any -> avoid confusion of protocol decoder
|
||||
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.
|
||||
return VersionMismatch;
|
||||
} else if( old == OldMMUFWDetector::State::MatchingPart ){
|
||||
} else if (old == OldMMUFWDetector::State::MatchingPart) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
[[fallthrough]]; // otherwise
|
||||
default:
|
||||
RecordUARTActivity(); // something has happened on the UART, update the timeout record
|
||||
|
|
@ -195,7 +195,7 @@ void ProtocolLogic::SendMsg(RequestMsg rq) {
|
|||
RecordUARTActivity();
|
||||
}
|
||||
|
||||
void ProtocolLogic::SendWriteMsg(RequestMsg rq){
|
||||
void ProtocolLogic::SendWriteMsg(RequestMsg rq) {
|
||||
uint8_t txbuff[Protocol::MaxRequestSize()];
|
||||
uint8_t len = Protocol::EncodeWriteRequest(rq.value, rq.value2, txbuff);
|
||||
uart->write(txbuff, len);
|
||||
|
|
@ -242,7 +242,7 @@ StepStatus ProtocolLogic::ProcessVersionResponse(uint8_t stage) {
|
|||
}
|
||||
|
||||
StepStatus ProtocolLogic::ScopeStep() {
|
||||
if ( ! ExpectsResponse() ) {
|
||||
if (!ExpectsResponse()) {
|
||||
// we are waiting for something
|
||||
switch (currentScope) {
|
||||
case Scope::DelayedRestart:
|
||||
|
|
@ -296,7 +296,7 @@ StepStatus ProtocolLogic::StartSeqStep() {
|
|||
}
|
||||
return Processing;
|
||||
case ScopeState::WritingInitRegisters:
|
||||
if( ProcessWritingInitRegister() ){
|
||||
if (ProcessWritingInitRegister()) {
|
||||
SendAndUpdateFilamentSensor();
|
||||
}
|
||||
return Processing;
|
||||
|
|
@ -354,7 +354,7 @@ StepStatus ProtocolLogic::ProcessCommandQueryResponse() {
|
|||
case ResponseMsgParamCodes::Finished:
|
||||
// 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.
|
||||
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;
|
||||
scopeState = ScopeState::Ready;
|
||||
rq = RequestMsg(RequestMsgCodes::unknown, 0); // clear the successfully finished request
|
||||
|
|
@ -449,7 +449,7 @@ StepStatus ProtocolLogic::IdleStep() {
|
|||
StartReading8bitRegisters();
|
||||
return ButtonPushed;
|
||||
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!
|
||||
// this must be solved by the upper layer, protocol logic doesn't have all the context (like unload before trying again)
|
||||
IdleRestart();
|
||||
|
|
@ -526,8 +526,7 @@ ProtocolLogic::ProtocolLogic(MMU2Serial *uart, uint8_t extraLoadDistance, uint8_
|
|||
, lastFSensor((uint8_t)WhereIsFilament())
|
||||
, regIndex(0)
|
||||
, retryAttempts(MAX_RETRIES)
|
||||
, inAutoRetry(false)
|
||||
{
|
||||
, inAutoRetry(false) {
|
||||
// @@TODO currently, I don't see a way of writing the initialization better :(
|
||||
// I'd like to write something like: initRegs8 { extraLoadDistance, pulleySlowFeedrate }
|
||||
// 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));
|
||||
}
|
||||
|
||||
void ProtocolLogic::ReadRegister(uint8_t address){
|
||||
void ProtocolLogic::ReadRegister(uint8_t 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));
|
||||
}
|
||||
|
||||
|
|
@ -599,23 +598,23 @@ void ProtocolLogic::PlanGenericRequest(RequestMsg rq) {
|
|||
}
|
||||
|
||||
bool ProtocolLogic::ActivatePlannedRequest() {
|
||||
switch(plannedRq.code){
|
||||
switch (plannedRq.code) {
|
||||
case RequestMsgCodes::Button:
|
||||
// only issue the button to the MMU and do not restart the state machines
|
||||
SendButton(plannedRq.value);
|
||||
plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);
|
||||
return true;
|
||||
case RequestMsgCodes::Read:
|
||||
SendReadRegister(plannedRq.value, ScopeState::ReadRegisterSent );
|
||||
SendReadRegister(plannedRq.value, ScopeState::ReadRegisterSent);
|
||||
plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);
|
||||
return true;
|
||||
case RequestMsgCodes::Write:
|
||||
SendWriteRegister(plannedRq.value, plannedRq.value2, ScopeState::WriteRegisterSent );
|
||||
SendWriteRegister(plannedRq.value, plannedRq.value2, ScopeState::WriteRegisterSent);
|
||||
plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);
|
||||
return true;
|
||||
case RequestMsgCodes::unknown:
|
||||
return false;
|
||||
default:// commands
|
||||
default: // commands
|
||||
currentScope = Scope::Command;
|
||||
SetRequestMsg(plannedRq);
|
||||
plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue