From ef86e9eb47dcbe68098267d6b4be82c5c1916fee Mon Sep 17 00:00:00 2001 From: Tomas Vybiral Date: Mon, 29 Jan 2024 12:02:33 +0100 Subject: [PATCH 001/223] Remove default IP address for metrics & logs --- .../store_instances/config_store/defaults.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/persistent_stores/store_instances/config_store/defaults.hpp b/src/persistent_stores/store_instances/config_store/defaults.hpp index fdc80e60e8..7ecf618fab 100644 --- a/src/persistent_stores/store_instances/config_store/defaults.hpp +++ b/src/persistent_stores/store_instances/config_store/defaults.hpp @@ -134,18 +134,10 @@ namespace defaults { inline constexpr std::array connect_token { "" }; inline constexpr uint16_t connect_port { 443 }; - // Defaults for metrics -#if DEVELOPMENT_ITEMS() - // Development build has metrics allowed - inline constexpr MetricsAllow metrics_allow { MetricsAllow::All }; - inline constexpr std::array metrics_host { "matrix.prusa.vc" }; - inline constexpr bool metrics_init { true }; -#else /*DEVELOPMENT_ITEMS()*/ // Production build need user to intentionally allow them inline constexpr MetricsAllow metrics_allow { MetricsAllow::None }; inline constexpr std::array metrics_host { "" }; inline constexpr bool metrics_init { false }; -#endif /*DEVELOPMENT_ITEMS()*/ inline constexpr uint16_t metrics_port { 8514 }; inline constexpr uint16_t syslog_port { 13514 }; From 2d996ab50ad2dc999623422805a7e7b3b372466b Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Wed, 22 Feb 2023 13:35:35 +0100 Subject: [PATCH 002/223] Disable sending crashdumps by default We don't have consent from the user right now and they are not encrypted. Shouldn't go to "production". BFW-3468. --- src/common/crash_dump/crash_dump_distribute.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/common/crash_dump/crash_dump_distribute.hpp b/src/common/crash_dump/crash_dump_distribute.hpp index 173c690f1f..08ad7a5c77 100644 --- a/src/common/crash_dump/crash_dump_distribute.hpp +++ b/src/common/crash_dump/crash_dump_distribute.hpp @@ -6,9 +6,7 @@ namespace crash_dump { -// inline constexpr const char *server { "crashdump.dragomirecky.com" }; -// inline constexpr uint16_t port { 80 }; -inline constexpr const char *server { "94.142.234.223" }; // temporary server +inline constexpr const char *server { "" }; // Empty -> disabled inline constexpr uint16_t port { 8888 }; // temporary port inline constexpr size_t url_buff_size { 128 }; From 56a50766b18dbaa5b22991dea41520125eec2b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Proch=C3=A1zka?= Date: Wed, 1 Mar 2023 17:07:41 +0100 Subject: [PATCH 003/223] Remove uploading dumps to server --- src/gui/screen_home.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/screen_home.cpp b/src/gui/screen_home.cpp index 97a2fe19ef..29128fd8ad 100644 --- a/src/gui/screen_home.cpp +++ b/src/gui/screen_home.cpp @@ -285,7 +285,6 @@ void screen_home_data_t::handle_crash_dump() { }; do_stage(_("Saving to USB"), [](const ::crash_dump::DumpHandler *handler) { handler->usb_save(); }); - do_stage(_("Sending to Prusa"), [](const ::crash_dump::DumpHandler *handler) { handler->server_upload(); }); } for (const auto &dump_handler : present_dumps) { From fdc90119bea9db9e124b17da9d715252be23f126 Mon Sep 17 00:00:00 2001 From: Michal Rudolf Date: Thu, 7 Mar 2024 10:46:51 +0100 Subject: [PATCH 004/223] Adjust retraction distance in UnloadInner (retract further back to ensure getting the filament out of the gear) --- .../Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp index aeb4c40e63..19c7002c3f 100644 --- a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp @@ -548,7 +548,7 @@ bool MMU2::ToolChangeCommonOnce(uint8_t slot) { ResumeHotendTemp(); // if the extruder has been parked, it will get unparked once the ToolChange command finishes OK // - so no ResumeUnpark() at this spot - UnloadInner(PreUnloadPolicy::ExtraRelieveFilament); + UnloadInner(PreUnloadPolicy::RelieveFilament); // if we run out of retries, we must do something ... may be raise an error screen and allow the user to do something // but honestly - if the MMU restarts during every toolchange, // something else is seriously broken and stopping a print is probably our best option. @@ -720,7 +720,16 @@ void MMU2::UnloadInner(PreUnloadPolicy preUnloadPolicy) { filament_ramming(); break; case PreUnloadPolicy::RelieveFilament: - extruder_move(-40.F, 60.F); + extruder_move( +#ifdef USE_TRY_LOAD + // try-loads are symmetrical + -40.F, +#else + // But E-stall detection is not symmetrical - it needs to retract way more (because the filament may still be somewhere in the nozzle) + // Theoretically, we should be able to retract the same distance as the failed load (when the E-motor skipped) + some extra margin + -120.F, +#endif + 60.F); planner_synchronize(); break; case PreUnloadPolicy::ExtraRelieveFilament: @@ -731,7 +740,7 @@ void MMU2::UnloadInner(PreUnloadPolicy preUnloadPolicy) { #else // But E-stall detection is not symmetrical - it needs to retract way more (because the filament may still be somewhere in the nozzle) // Theoretically, we should be able to retract the same distance as the failed load (when the E-motor skipped) + some extra margin - -90.F, + -180.F, #endif 60.F); planner_synchronize(); @@ -815,7 +824,7 @@ bool MMU2::loading_test(uint8_t slot) { thermal_setExtrudeMintemp(0); // Allow cold extrusion - load test doesn't push filament all the way into the nozzle ToolChangeCommon(slot); planner_synchronize(); - UnloadInner(PreUnloadPolicy::ExtraRelieveFilament); + UnloadInner(PreUnloadPolicy::RelieveFilament); thermal_setExtrudeMintemp(EXTRUDE_MINTEMP); } ScreenUpdateEnable(); From 270ed0cbe5fd6e25d1754bab5053fa3e18be3d81 Mon Sep 17 00:00:00 2001 From: Dano Pernis Date: Thu, 7 Mar 2024 13:39:35 +0100 Subject: [PATCH 005/223] Fix BSOD when aborting selftest while homing --- lib/Marlin/Marlin/src/module/prusa/homing_corexy.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/Marlin/Marlin/src/module/prusa/homing_corexy.cpp b/lib/Marlin/Marlin/src/module/prusa/homing_corexy.cpp index 25946c7ac8..857f9bf06b 100644 --- a/lib/Marlin/Marlin/src/module/prusa/homing_corexy.cpp +++ b/lib/Marlin/Marlin/src/module/prusa/homing_corexy.cpp @@ -13,6 +13,7 @@ #include "feature/prusa/crash_recovery.hpp" #endif #include "bsod.h" +#include "log.h" #include "feature/phase_stepping/phase_stepping.hpp" @@ -289,6 +290,8 @@ static bool wait_for_standstill(uint8_t axis_mask, millis_t max_delay = 150) { } } +LOG_COMPONENT_REF(Marlin); + /** * @brief Precise homing on core-XY. * @return true on success @@ -318,7 +321,11 @@ bool refine_corexy_origin() { stepper.position(B_AXIS) + phase_backoff_steps(B_AXIS) }; plan_corexy_raw_move(origin_steps, fr_mm_s); if (stepper.position(A_AXIS) != origin_steps[A_AXIS] || stepper.position(B_AXIS) != origin_steps[B_AXIS]) { - bsod("raw move didn't reach requested position"); + // This does actually happen. + // For example, somebody may call planner.quick_stop() + // while we were waiting in planner.synchronize() + log_warning(Marlin, "raw move didn't reach requested position"); + return false; } // sanity checks From 144ee98536dbd43293f91bae62253ac990925abe Mon Sep 17 00:00:00 2001 From: Dano Pernis Date: Tue, 5 Mar 2024 19:32:56 +0100 Subject: [PATCH 006/223] Fix focus stealing (not only) in DialogToolActionBox Dialog stores the state of underlying screen upon construction and loads it back upon destruction. Consistently. Like, always. Without this, ToolBox::DialogToolActionBox would set focused item which would prevent menu screen from serializing its focused item. --- src/gui/ScreenHandler.cpp | 6 ---- src/gui/dialogs/DialogHandler.cpp | 7 ----- src/gui/dialogs/DialogHandler.hpp | 5 ---- src/gui/dialogs/IDialog.cpp | 34 +++++++++++++++++++--- src/gui/dialogs/IDialog.hpp | 5 +++- src/guiapi/include/screen_init_variant.hpp | 2 +- 6 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/gui/ScreenHandler.cpp b/src/gui/ScreenHandler.cpp index 4a3abc891c..e1263d6bd0 100644 --- a/src/gui/ScreenHandler.cpp +++ b/src/gui/ScreenHandler.cpp @@ -375,10 +375,6 @@ void Screens::SetDisplayReinitialized() { } void Screens::gui_loop_until_dialog_closed(std::function callback) { - screen_t *screen = Get(); - assert(screen); - screen_init_variant underlying_screen_state = screen->GetCurrentState(); - for (;;) { const bool dialog_closed = close || close_all; close = false; // Note: We reset close flag because it is reused for closing both dialogs and screens @@ -392,6 +388,4 @@ void Screens::gui_loop_until_dialog_closed(std::function callback) { callback(); } } - - screen->InitState(underlying_screen_state); } diff --git a/src/gui/dialogs/DialogHandler.cpp b/src/gui/dialogs/DialogHandler.cpp index 6e40ed367c..9c6820c5a3 100644 --- a/src/gui/dialogs/DialogHandler.cpp +++ b/src/gui/dialogs/DialogHandler.cpp @@ -80,10 +80,6 @@ void DialogHandler::open(ClientFSM fsm_type, fsm::BaseData data) { dialog_cache = last_fsm_change; ptr = nullptr; - } else { - auto *screen = Screens::Access()->Get(); - assert(screen); - underlying_screen_state_ = screen->GetCurrentState(); } last_fsm_change = std::make_pair(fsm_type, data); @@ -174,9 +170,6 @@ void DialogHandler::close(ClientFSM fsm_type) { dialog_cache = std::nullopt; open(cache.first, cache.second); } else { - auto *screen = Screens::Access()->Get(); - assert(screen); - screen->InitState(underlying_screen_state_); ptr = nullptr; // destroy current dialog } } diff --git a/src/gui/dialogs/DialogHandler.hpp b/src/gui/dialogs/DialogHandler.hpp index f33fcf721c..9af734907f 100644 --- a/src/gui/dialogs/DialogHandler.hpp +++ b/src/gui/dialogs/DialogHandler.hpp @@ -3,7 +3,6 @@ #include #include "IDialogMarlin.hpp" #include "fsm_types.hpp" -#include "screen_init_variant.hpp" #include "static_alocation_ptr.hpp" class DialogHandler { @@ -30,8 +29,4 @@ class DialogHandler { bool IsOpen(ClientFSM fsm) const; bool IsAnyOpen() const; - -private: - /// When a dialog is opened, underlying screen state is saved. It then gets restored on dialog close - screen_init_variant underlying_screen_state_; }; diff --git a/src/gui/dialogs/IDialog.cpp b/src/gui/dialogs/IDialog.cpp index bd0fc6cc67..546ee11ec2 100644 --- a/src/gui/dialogs/IDialog.cpp +++ b/src/gui/dialogs/IDialog.cpp @@ -1,13 +1,39 @@ #include "IDialog.hpp" -#include + #include "ScreenHandler.hpp" +#include "log.h" + +LOG_COMPONENT_REF(GUI); IDialog::IDialog(Rect16 rc) - : AddSuperWindow(Screens::Access()->Get(), rc, win_type_t::dialog) { - Enable(); + : IDialog(Screens::Access()->Get(), rc) { +} + +static screen_init_variant get_underlying_screen_state() { + if (screen_t *screen = Screens::Access()->Get()) { + return screen->GetCurrentState(); + } else { + // TODO investigate if this happens in the wild after we collect some telemetry + log_info(GUI, "get_underlying_screen_state() without screen"); + return screen_init_variant {}; + } +} + +static void set_underlying_screen_state(const screen_init_variant &underlying_screen_state) { + if (screen_t *screen = Screens::Access()->Get()) { + screen->InitState(underlying_screen_state); + } else { + // TODO investigate if this happens in the wild after we collect some telemetry + log_info(GUI, "set_underlying_screen_state() without screen"); + } } IDialog::IDialog(window_t *parent, Rect16 rc) - : AddSuperWindow(parent, rc, win_type_t::dialog) { + : AddSuperWindow(parent, rc, win_type_t::dialog) + , underlying_screen_state { get_underlying_screen_state() } { Enable(); } + +IDialog::~IDialog() { + set_underlying_screen_state(underlying_screen_state); +} diff --git a/src/gui/dialogs/IDialog.hpp b/src/gui/dialogs/IDialog.hpp index 7df85966ce..7bc05a6566 100644 --- a/src/gui/dialogs/IDialog.hpp +++ b/src/gui/dialogs/IDialog.hpp @@ -2,14 +2,17 @@ #pragma once #include +#include "screen_init_variant.hpp" #include "window_frame.hpp" #include "guitypes.hpp" #include -#include // interface for dialog class IDialog : public AddSuperWindow { + screen_init_variant underlying_screen_state; + public: IDialog(Rect16 rc = GuiDefaults::DialogFrameRect); IDialog(window_t *parent, Rect16 rc = GuiDefaults::DialogFrameRect); + ~IDialog(); }; diff --git a/src/guiapi/include/screen_init_variant.hpp b/src/guiapi/include/screen_init_variant.hpp index 4a1112c356..705d008e19 100644 --- a/src/guiapi/include/screen_init_variant.hpp +++ b/src/guiapi/include/screen_init_variant.hpp @@ -84,7 +84,7 @@ class screen_init_variant { return fsm_base_data; } - constexpr bool IsValid() { + constexpr bool IsValid() const { return type != type_t::data_not_valid; } From 76ca7d7a70340eb788558bc66a9fe98adaa483fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C5=A0m=C3=ADd?= Date: Fri, 8 Mar 2024 10:48:00 +0100 Subject: [PATCH 007/223] More robust variant of usbh_power_cycle reset after an usb error BFW-5178 --- include/usb_host/usb_host.h | 15 ++++++--- src/buddy/usb_host.cpp | 48 ++++++++++++++++++++-------- src/common/marlin_client.cpp | 4 +++ src/common/marlin_client.hpp | 2 ++ src/common/marlin_server.cpp | 3 ++ src/common/marlin_server_request.hpp | 1 + src/common/media.cpp | 42 +++++++++++++++++------- src/common/media.hpp | 1 + src/gui/screen_home.cpp | 4 ++- 9 files changed, 88 insertions(+), 32 deletions(-) diff --git a/include/usb_host/usb_host.h b/include/usb_host/usb_host.h index 6936d08e24..5a2d3d87c7 100644 --- a/include/usb_host/usb_host.h +++ b/include/usb_host/usb_host.h @@ -7,14 +7,19 @@ namespace usbh_power_cycle { void init(); -/// callback from media_loop when printing is paused -void media_state_error(); - -/// callback from USBH_MSC_Worker when an io error occurs +// callback from USBH_MSC_Worker when an io error occurs void io_error(); -/// callback from isr, it is called when the USB is disconnected or when USB flash is deadlocked +// callback from isr, it is called when the USB is disconnected or when USB flash is deadlocked void port_disabled(); + +// indication that the one click dialog during USB recovery reset should be blocked +bool block_one_click_print(); + +// indication that a USB error dialog should be displayed +// usb reset was unsuccessful and nothing else remains after emptying the prefetch buffer +extern std::atomic trigger_usb_failed_dialog; + } // namespace usbh_power_cycle extern "C" { diff --git a/src/buddy/usb_host.cpp b/src/buddy/usb_host.cpp index a0d4bf86aa..e82c2d8938 100644 --- a/src/buddy/usb_host.cpp +++ b/src/buddy/usb_host.cpp @@ -25,11 +25,15 @@ namespace usbh_power_cycle { // if printing was in progress: // if the usb is successfully initialized within 5s, it will connect automatically, // otherwise the "USB drive or file error" warning will appear. +// network transfers should continue (it's actually a new flash insertion) +// other operations may fail (highly unlikely situation) // timer to handle the restart procedure TimerHandle_t restart_timer; void restart_timer_callback(TimerHandle_t); +uint32_t block_one_click_print_until_ms = 0; + enum class Phase : uint_fast8_t { idle, power_off, @@ -38,6 +42,7 @@ enum class Phase : uint_fast8_t { std::atomic phase = Phase::idle; std::atomic printing_paused = false; +std::atomic trigger_usb_failed_dialog = true; // Initialize FreeRTOS timer void init() { @@ -48,6 +53,7 @@ void init() { // callback from USBH_MSC_Worker when an io error occurs => start the restart procedure void io_error() { if (phase == Phase::idle) { + trigger_usb_failed_dialog = false; xTimerChangePeriod(restart_timer, 10, portMAX_DELAY); } } @@ -55,23 +61,17 @@ void io_error() { // callback from isr => start the restart procedure void port_disabled() { if (phase == Phase::idle) { + trigger_usb_failed_dialog = false; xTimerChangePeriodFromISR(restart_timer, 10, nullptr); } } -// callback from marlin media_loop -// it means that printing has been paused and in the case of a successful reinitialization it will be necessary to call resume -void media_state_error() { - printing_paused = true; -} - // called from USBH_Thread -// usb msc has been connected => if a reinitialization attempt is in progress, it is completed successfully, and if the print was paused, resume it void msc_active() { - if (phase == Phase::power_on && printing_paused) { - printing_paused = false; + if (phase == Phase::power_on) { xTimerStop(restart_timer, portMAX_DELAY); phase = Phase::idle; + block_one_click_print_until_ms = ticks_ms() + 1000; // lazy initialization of marlin_client static bool marlin_client_initializated = false; @@ -79,19 +79,28 @@ void msc_active() { marlin_client_initializated = true; marlin_client::init(); } - marlin_client::print_resume(); + switch (media_print_get_state()) { + case media_print_state_NONE: + break; + case media_print_state_PAUSED: + marlin_client::print_resume(); + break; + case media_print_state_PRINTING: + marlin_client::media_print_reopen(); + trigger_usb_failed_dialog = true; + break; + } } } // called from SVC task void restart_timer_callback(TimerHandle_t) { - static bool marlin_client_initializated = false; - switch (phase) { case Phase::idle: phase = Phase::power_off; xTimerChangePeriod(restart_timer, 150, portMAX_DELAY); USBH_Stop(&hUsbHostHS); + block_one_click_print_until_ms = ticks_ms() + 5000; break; case Phase::power_off: phase = Phase::power_on; @@ -100,19 +109,30 @@ void restart_timer_callback(TimerHandle_t) { break; case Phase::power_on: phase = Phase::idle; - - if (printing_paused) { + trigger_usb_failed_dialog = true; + + switch (media_print_get_state()) { + case media_print_state_NONE: + case media_print_state_PRINTING: + break; + case media_print_state_PAUSED: + static bool marlin_client_initializated = false; // lazy initialization of marlin_client if (!marlin_client_initializated) { marlin_client_initializated = true; marlin_client::init(); } marlin_client::set_warning(WarningType::USBFlashDiskError); + break; } break; } } +bool block_one_click_print() { + return block_one_click_print_until_ms > ticks_ms(); +} + } // namespace usbh_power_cycle static uint32_t one_click_print_timeout { 0 }; diff --git a/src/common/marlin_client.cpp b/src/common/marlin_client.cpp index 2c6daf11d0..18da709c2b 100644 --- a/src/common/marlin_client.cpp +++ b/src/common/marlin_client.cpp @@ -427,6 +427,10 @@ void print_resume() { _send_request_id_to_server_and_wait(Request::Type::PrintResume); } +void media_print_reopen() { + _send_request_id_to_server_and_wait(Request::Type::MediaPrintReopen); +} + void park_head() { _send_request_id_to_server_and_wait(Request::Type::Park); } diff --git a/src/common/marlin_client.hpp b/src/common/marlin_client.hpp index d2f758eda5..b8f28125ad 100644 --- a/src/common/marlin_client.hpp +++ b/src/common/marlin_client.hpp @@ -152,6 +152,8 @@ void print_pause(); void print_resume(); +void media_print_reopen(); + void park_head(); void notify_server_about_encoder_move(); diff --git a/src/common/marlin_server.cpp b/src/common/marlin_server.cpp index 9ca4c4322a..cf36b5766b 100644 --- a/src/common/marlin_server.cpp +++ b/src/common/marlin_server.cpp @@ -2735,6 +2735,9 @@ bool _process_server_valid_request(const Request &request, int client_id) { case Request::Type::PrintResume: print_resume(); return true; + case Request::Type::MediaPrintReopen: + media_print_reopen(); + return true; case Request::Type::PrintExit: print_exit(); return true; diff --git a/src/common/marlin_server_request.hpp b/src/common/marlin_server_request.hpp index 917fd51324..38e1a63651 100644 --- a/src/common/marlin_server_request.hpp +++ b/src/common/marlin_server_request.hpp @@ -20,6 +20,7 @@ struct __attribute__((packed)) Request { PrintAbort, PrintPause, PrintResume, + MediaPrintReopen, PrintExit, Park, KnobMove, diff --git a/src/common/media.cpp b/src/common/media.cpp index fb97bf3f99..e5aeba0031 100644 --- a/src/common/media.cpp +++ b/src/common/media.cpp @@ -35,7 +35,7 @@ namespace { volatile media_state_t media_state = media_state_REMOVED; volatile media_error_t media_error = media_error_OK; -media_print_state_t media_print_state = media_print_state_NONE; +std::atomic media_print_state = media_print_state_NONE; AnyGcodeFormatReader *media_print_file; ///< File used to print AnyGcodeFormatReader *gcode_info_file; ///< File used to scan GcodeInfo uint32_t media_print_size_estimate = 0; ///< Estimated uncompressed G-code size in bytes @@ -391,6 +391,18 @@ void media_print_pause(bool repeat_last = false) { skip_gcode = !repeat_last; } +static bool media_print_file_reset_position() { + media_print_size_estimate = media_print_file->get()->get_gcode_stream_size_estimate(); + if (media_reset_position != GCodeQueue::SDPOS_INVALID) { + media_print_set_position(media_reset_position); + media_reset_position = GCodeQueue::SDPOS_INVALID; + } + if (media_print_file->get_prusa_pack()) { + media_print_file->get_prusa_pack()->set_restore_info(media_get_restore_info()); + } + return media_print_file->get()->stream_gcode_start(media_current_position); +} + void media_print_resume(void) { assert(prefetch_mutex_file_reader && media_print_file); @@ -404,16 +416,8 @@ void media_print_resume(void) { media_print_file->open(marlin_vars()->media_SFN_path.get_ptr()); } if (media_print_file->is_open()) { - media_print_size_estimate = media_print_file->get()->get_gcode_stream_size_estimate(); - if (media_reset_position != GCodeQueue::SDPOS_INVALID) { - media_print_set_position(media_reset_position); - media_reset_position = GCodeQueue::SDPOS_INVALID; - } - if (media_print_file->get_prusa_pack()) { - media_print_file->get_prusa_pack()->set_restore_info(media_get_restore_info()); - } // file was left open between pause/resume or re-opened successfully - if (media_print_file->get()->stream_gcode_start(media_current_position)) { + if (media_print_file_reset_position()) { gcode_filter.reset(); media_print_state = media_print_state_PRINTING; osSignalSet(prefetch_thread_id, PREFETCH_SIGNAL_START); @@ -427,6 +431,19 @@ void media_print_resume(void) { xSemaphoreGive(prefetch_mutex_file_reader); } +void media_print_reopen() { + xSemaphoreTake(prefetch_mutex_file_reader, portMAX_DELAY); + if (media_print_file->is_open()) { + media_print_file->close(); + skip_gcode = true; + media_print_file->open(marlin_vars()->media_SFN_path.get_ptr()); + if (!media_print_file->is_open() || !media_print_file_reset_position()) { + usbh_power_cycle::trigger_usb_failed_dialog = true; + } + } + xSemaphoreGive(prefetch_mutex_file_reader); +} + media_print_state_t media_print_get_state(void) { return media_print_state; } @@ -516,9 +533,10 @@ void media_loop(void) { // Pause in case of some issue usbh_error_count++; metric_record_integer(&usbh_error_cnt, usbh_error_count); - usbh_power_cycle::media_state_error(); media_print_pause(); - media_print_resume(); + if (usbh_power_cycle::trigger_usb_failed_dialog) { + marlin_server::set_warning(WarningType::USBFlashDiskError); + } return; case GCodeFilter::State::Eof: // Stop print on EOF diff --git a/src/common/media.hpp b/src/common/media.hpp index fddb3677c2..db208bf980 100644 --- a/src/common/media.hpp +++ b/src/common/media.hpp @@ -54,6 +54,7 @@ extern void media_print_stop(void); /// \param repeat_last Repeat last command after print resume extern void media_print_pause(bool repeat_last); extern void media_print_resume(void); +void media_print_reopen(); /// Stop adding new commands immediately and pause the reading /// \param pos position in the file where the print should be resumed diff --git a/src/gui/screen_home.cpp b/src/gui/screen_home.cpp index 29128fd8ad..7f2eecfdda 100644 --- a/src/gui/screen_home.cpp +++ b/src/gui/screen_home.cpp @@ -55,6 +55,8 @@ #include #include +#include "usb_host.h" + // TODO remove netdev_is_enabled after it is defined bool __attribute__((weak)) netdev_is_enabled([[maybe_unused]] const uint32_t netdev_id) { return true; } @@ -488,7 +490,7 @@ void screen_home_data_t::windowEvent(EventLock /*has private ctor*/, window_t *s #if ENABLED(POWER_PANIC) TaskDeps::check(TaskDeps::Dependency::usb_and_temp_ready) && !power_panic::is_power_panic_resuming() && #endif // ENABLED(POWER_PANIC) - GuiMediaEventsHandler::ConsumeOneClickPrinting()) { + GuiMediaEventsHandler::ConsumeOneClickPrinting() && !usbh_power_cycle::block_one_click_print()) { // TODO this should be done in main thread before Event::MediaInserted is generated // if it is not the latest gcode might not be selected if (find_latest_gcode( From 4ad08c752778880f10e629e717dbb544c53ec106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 8 Mar 2024 15:01:43 +0100 Subject: [PATCH 008/223] IS: Fix the issue with a random printer stopping during printing. --- lib/Marlin/Marlin/src/feature/input_shaper/input_shaper.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Marlin/Marlin/src/feature/input_shaper/input_shaper.cpp b/lib/Marlin/Marlin/src/feature/input_shaper/input_shaper.cpp index 9d7bf5a7b1..0fc03abcd0 100644 --- a/lib/Marlin/Marlin/src/feature/input_shaper/input_shaper.cpp +++ b/lib/Marlin/Marlin/src/feature/input_shaper/input_shaper.cpp @@ -513,6 +513,11 @@ step_event_info_t input_shaper_step_generator_next_step_event(input_shaper_step_ if (input_shaper_state_update(*step_generator.is_state, step_generator.axis) && step_generator.is_state->nearest_next_change < MAX_PRINT_TIME) { next_step_event.flags |= STEP_EVENT_FLAG_KEEP_ALIVE; next_step_event.status = STEP_EVENT_INFO_STATUS_GENERATED_KEEP_ALIVE; + } else { + // We reached the ending move segment, so we will never produce any valid step event from this micro move segment. + // When we return GENERATED_INVALID, we always have to return the value of nearest_next_change for this new micro + // move segment and not for the previous one. + next_step_event.time = step_generator.is_state->nearest_next_change; } // Update step direction flag, which is cached until this move segment is processed. From b02e018c012a9fb30058913076b644f4a461bf9f Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Fri, 8 Mar 2024 13:16:55 +0100 Subject: [PATCH 009/223] MMU: Count tool changes in the odometer BFW-5138. --- .../Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp | 1 + .../src/feature/prusa/MMU2/mmu2_reporting.h | 3 +++ src/common/odometer.cpp | 15 +++++++++++++++ src/common/odometer.hpp | 11 +++++++++++ src/gui/MItem_tools.cpp | 8 ++++++++ src/gui/MItem_tools.hpp | 8 ++++++++ src/gui/screen_menu_odometer.cpp | 4 ++++ src/gui/screen_menu_odometer.hpp | 3 +++ src/mmu2/mmu2_reporting.cpp | 5 +++++ .../config_store/store_definition.hpp | 2 ++ tests/unit/lib/Marlin/MMU2/mmu2-printer_test.cpp | 2 +- .../unit/lib/Marlin/MMU2/stubs/mmu2_reporting.cpp | 4 ++++ 12 files changed, 65 insertions(+), 1 deletion(-) diff --git a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp index 19c7002c3f..a7206a768a 100644 --- a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp @@ -586,6 +586,7 @@ void MMU2::ToolChangeCommon(uint8_t slot) { // @@TODO SpoolJoin::spooljoin.setSlot(slot); ++toolchange_counter; + IncrementMMUChanges(); } bool MMU2::tool_change(uint8_t slot) { diff --git a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_reporting.h b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_reporting.h index fdb9719ca6..d4d2eda26c 100644 --- a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_reporting.h +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_reporting.h @@ -198,6 +198,9 @@ void IncrementLoadFails(); /// Increments EEPROM cell - number of MMU errors void IncrementMMUFails(); +/// Increments EEPROM cell - number of filament changes +void IncrementMMUChanges(); + /// @returns true when Cutter is enabled in the menus bool cutter_enabled(); diff --git a/src/common/odometer.cpp b/src/common/odometer.cpp index aff4f8a6cf..d6dcc02b32 100644 --- a/src/common/odometer.cpp +++ b/src/common/odometer.cpp @@ -29,6 +29,10 @@ bool Odometer_s::changed() { return true; } + if (mmu_changes != 0) { + return true; + } + return false; } @@ -54,6 +58,9 @@ void Odometer_s::force_to_eeprom() { config_store().odometer_time.set(get_time()); duration_time = 0; + + config_store().mmu_changes.set(get_mmu_changes()); + mmu_changes = 0; } void Odometer_s::add_axis(axis_t axis, float value) { @@ -109,6 +116,14 @@ uint32_t Odometer_s::get_toolpick_all() { return sum; } +void Odometer_s::add_mmu_change() { + mmu_changes++; +} + +uint32_t Odometer_s::get_mmu_changes() { + return config_store().mmu_changes.get() + mmu_changes; +} + void Odometer_s::add_time(uint32_t value) { duration_time += value; } diff --git a/src/common/odometer.hpp b/src/common/odometer.hpp index cd8bd36347..2aa8828c39 100644 --- a/src/common/odometer.hpp +++ b/src/common/odometer.hpp @@ -27,6 +27,7 @@ class Odometer_s { std::atomic extruded[HOTENDS] = {}; std::atomic toolpick[HOTENDS] = {}; std::atomic duration_time = 0; + std::atomic mmu_changes = 0; Odometer_s() = default; @@ -93,6 +94,16 @@ class Odometer_s { */ uint32_t get_toolpick_all(); + /** + * @brief Add one MMU filament change. + */ + void add_mmu_change(); + + /** + * @brief Get count of MMU filament changes. + */ + uint32_t get_mmu_changes(); + /** * @brief Save new print duration. * @param value print time to accumulate [second] diff --git a/src/gui/MItem_tools.cpp b/src/gui/MItem_tools.cpp index b76ca7990e..cc92c86fc0 100644 --- a/src/gui/MItem_tools.cpp +++ b/src/gui/MItem_tools.cpp @@ -656,6 +656,14 @@ MI_ODOMETER_DIST_E::MI_ODOMETER_DIST_E() : MI_ODOMETER_DIST(_(generic_label), nullptr, is_enabled_t::yes, is_hidden_t::no, -1) { } +MI_ODOMETER_MMU_CHANGES::MI_ODOMETER_MMU_CHANGES() + : WI_FORMATABLE_LABEL_t( + _(label), nullptr, is_enabled_t::yes, is_hidden_t::no, {}, + [&](char *buffer) { + snprintf(buffer, GuiDefaults::infoDefaultLen, "%lu %s", value, times_label); + }) { +} + MI_ODOMETER_TIME::MI_ODOMETER_TIME() : WI_FORMATABLE_LABEL_t(_(label), nullptr, is_enabled_t::yes, is_hidden_t::no, 0, [&](char *buffer) { format_duration(std::span { buffer, GuiDefaults::infoDefaultLen }, value); diff --git a/src/gui/MItem_tools.hpp b/src/gui/MItem_tools.hpp index 09673f80bc..085bbcf4fd 100644 --- a/src/gui/MItem_tools.hpp +++ b/src/gui/MItem_tools.hpp @@ -586,6 +586,14 @@ class MI_ODOMETER_TOOL : public WI_FORMATABLE_LABEL_t { MI_ODOMETER_TOOL(); }; +class MI_ODOMETER_MMU_CHANGES : public WI_FORMATABLE_LABEL_t { + constexpr static const char *const label = N_("MMU Changed"); + constexpr static const char *const times_label = N_("times"); // MMU Changed 123 times + +public: + MI_ODOMETER_MMU_CHANGES(); +}; + class MI_ODOMETER_TIME : public WI_FORMATABLE_LABEL_t { constexpr static const char *const label = N_("Print Time"); diff --git a/src/gui/screen_menu_odometer.cpp b/src/gui/screen_menu_odometer.cpp index e1c8b42008..2691409ac5 100644 --- a/src/gui/screen_menu_odometer.cpp +++ b/src/gui/screen_menu_odometer.cpp @@ -8,6 +8,7 @@ #include "MItem_tools.hpp" #include "DialogMoveZ.hpp" #include