diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f0e931ec32..d9a2aa1890 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,6 +38,12 @@ repos: entry: python utils/logging/generate_overview.py language: python language_version: python3 + - id: python3-requirements + name: python3-requirements + description: Check if requirements.txt matches the buildsystem. + entry: 'utils/check-requirements.py' + language: script + files: requirements\.txt$ - repo: https://github.com/pre-commit/pre-commit-hooks rev: 'v2.4.0' hooks: diff --git a/.vscode/launch.json b/.vscode/launch.json index dcde8a3253..3cc97e0427 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,8 +9,15 @@ "type": "cortex-debug", "servertype": "openocd", "armToolchainPath": "${workspaceRoot}/.dependencies/gcc-arm-none-eabi-13.2.1/bin", - "openOCDPreConfigLaunchCommands": ["set bbf_over_debugger_path ./build-vscode-buddy/firmware.bbf"], - "configFiles": ["${workspaceRoot}/utils/debug/00_common.cfg", "${workspaceRoot}/utils/debug/10_custom_config.cfg", "${workspaceRoot}/utils/debug/20_board_buddy.cfg", "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg"], + "openOCDPreConfigLaunchCommands": [ + "set bbf_over_debugger_path ./build-vscode-buddy/firmware.bbf" + ], + "configFiles": [ + "${workspaceRoot}/utils/debug/00_common.cfg", + "${workspaceRoot}/utils/debug/10_custom_config.cfg", + "${workspaceRoot}/utils/debug/20_board_buddy.cfg", + "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg" + ], "toolchainPrefix": "arm-none-eabi", "device": "STM32F427ZI", // swd file is disabled, it is known to cause issues in some cases. Enable it if you need to see register view. @@ -18,6 +25,9 @@ "rtos": "FreeRTOS", "breakAfterReset": false, "preLaunchTask": "Backup current ELF", + "liveWatch": { + "enabled": true, + }, "rttConfig": { "enabled": true, "address": "auto", @@ -43,13 +53,23 @@ "type": "cortex-debug", "servertype": "openocd", "armToolchainPath": "${workspaceRoot}/.dependencies/gcc-arm-none-eabi-13.2.1/bin", - "openOCDPreConfigLaunchCommands": ["set bbf_over_debugger_path ./build-vscode-buddy/firmware.bbf"], - "configFiles": ["${workspaceRoot}/utils/debug/00_common.cfg", "${workspaceRoot}/utils/debug/10_custom_config.cfg", "${workspaceRoot}/utils/debug/20_board_buddy.cfg", "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg"], + "openOCDPreConfigLaunchCommands": [ + "set bbf_over_debugger_path ./build-vscode-buddy/firmware.bbf" + ], + "configFiles": [ + "${workspaceRoot}/utils/debug/00_common.cfg", + "${workspaceRoot}/utils/debug/10_custom_config.cfg", + "${workspaceRoot}/utils/debug/20_board_buddy.cfg", + "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg" + ], "toolchainPrefix": "arm-none-eabi", "device": "STM32F427ZI", // swd file is disabled, it is known to cause issues in some cases. Enable it if you need to see register view. //"svdFile": "${workspaceRoot}/.dependencies/cmsis-svd-0.4.9999/STM32F427.svd", "rtos": "FreeRTOS", + "liveWatch": { + "enabled": true, + }, "rttConfig": { "enabled": true, "address": "auto", @@ -75,8 +95,15 @@ "type": "cortex-debug", "servertype": "openocd", "armToolchainPath": "${workspaceRoot}/.dependencies/gcc-arm-none-eabi-13.2.1/bin", - "openOCDPreConfigLaunchCommands": ["set PUPPY_TYPE dwarf"], - "configFiles": ["${workspaceRoot}/utils/debug/00_common.cfg", "${workspaceRoot}/utils/debug/10_custom_config.cfg", "${workspaceRoot}/utils/debug/20_board_puppy.cfg", "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg"], + "openOCDPreConfigLaunchCommands": [ + "set PUPPY_TYPE dwarf" + ], + "configFiles": [ + "${workspaceRoot}/utils/debug/00_common.cfg", + "${workspaceRoot}/utils/debug/10_custom_config.cfg", + "${workspaceRoot}/utils/debug/20_board_puppy.cfg", + "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg" + ], "toolchainPrefix": "arm-none-eabi", "device": "STM32G07", "svdFile": "${workspaceRoot}/.dependencies/cmsis-svd-0.4.9999/STM32G07x.svd", @@ -110,8 +137,15 @@ "type": "cortex-debug", "servertype": "openocd", "armToolchainPath": "${workspaceRoot}/.dependencies/gcc-arm-none-eabi-13.2.1/bin", - "openOCDPreConfigLaunchCommands": ["set PUPPY_TYPE dwarf"], - "configFiles": ["${workspaceRoot}/utils/debug/00_common.cfg", "${workspaceRoot}/utils/debug/10_custom_config.cfg", "${workspaceRoot}/utils/debug/20_board_puppy.cfg", "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg"], + "openOCDPreConfigLaunchCommands": [ + "set PUPPY_TYPE dwarf" + ], + "configFiles": [ + "${workspaceRoot}/utils/debug/00_common.cfg", + "${workspaceRoot}/utils/debug/10_custom_config.cfg", + "${workspaceRoot}/utils/debug/20_board_puppy.cfg", + "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg" + ], "toolchainPrefix": "arm-none-eabi", "device": "STM32G07", "svdFile": "${workspaceRoot}/.dependencies/cmsis-svd-0.4.9999/STM32G07x.svd", @@ -141,8 +175,15 @@ "type": "cortex-debug", "servertype": "openocd", "armToolchainPath": "${workspaceRoot}/.dependencies/gcc-arm-none-eabi-13.2.1/bin", - "openOCDPreConfigLaunchCommands": ["set PUPPY_TYPE modularbed"], - "configFiles": ["${workspaceRoot}/utils/debug/00_common.cfg", "${workspaceRoot}/utils/debug/10_custom_config.cfg", "${workspaceRoot}/utils/debug/20_board_puppy.cfg", "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg"], + "openOCDPreConfigLaunchCommands": [ + "set PUPPY_TYPE modularbed" + ], + "configFiles": [ + "${workspaceRoot}/utils/debug/00_common.cfg", + "${workspaceRoot}/utils/debug/10_custom_config.cfg", + "${workspaceRoot}/utils/debug/20_board_puppy.cfg", + "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg" + ], "toolchainPrefix": "arm-none-eabi", "device": "STM32G07", "svdFile": "${workspaceRoot}/.dependencies/cmsis-svd-0.4.9999/STM32G07x.svd", @@ -160,8 +201,15 @@ "type": "cortex-debug", "servertype": "openocd", "armToolchainPath": "${workspaceRoot}/.dependencies/gcc-arm-none-eabi-13.2.1/bin", - "openOCDPreConfigLaunchCommands": ["set PUPPY_TYPE modularbed"], - "configFiles": ["${workspaceRoot}/utils/debug/00_common.cfg", "${workspaceRoot}/utils/debug/10_custom_config.cfg", "${workspaceRoot}/utils/debug/20_board_puppy.cfg", "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg"], + "openOCDPreConfigLaunchCommands": [ + "set PUPPY_TYPE modularbed" + ], + "configFiles": [ + "${workspaceRoot}/utils/debug/00_common.cfg", + "${workspaceRoot}/utils/debug/10_custom_config.cfg", + "${workspaceRoot}/utils/debug/20_board_puppy.cfg", + "${workspaceRoot}/utils/debug/30_rtt_workaround.cfg" + ], "toolchainPrefix": "arm-none-eabi", "device": "STM32G07", "svdFile": "${workspaceRoot}/.dependencies/cmsis-svd-0.4.9999/STM32G07x.svd", @@ -188,7 +236,9 @@ "type": "cortex-debug", "servertype": "qemu", "serverpath": "${workspaceRoot}/.venv/bin/simulator_as_qemu", - "serverArgs": ["--scripted"], + "serverArgs": [ + "--scripted" + ], "windows": { "serverpath": "${workspaceRoot}/.venv/Scripts/simulator_as_qemu" }, @@ -221,7 +271,11 @@ "compounds": [ { "name": "XL - ALL", - "configurations": ["Launch Buddy","Launch Dwarf", "Launch ModularBed"], + "configurations": [ + "Launch Buddy", + "Launch Dwarf", + "Launch ModularBed" + ], "presentation": { "group": "XL Puppies", }, diff --git a/CMakeLists.txt b/CMakeLists.txt index 94cfcc555a..a8bf133cf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,6 @@ include(ExternalProject) include(cmake/Utilities.cmake) include(cmake/GetGitRevisionDescription.cmake) include(cmake/ProjectVersion.cmake) -include(cmake/CheckRemotes.cmake) include(cmake/Littlefs.cmake) include(cmake/Options.cmake) diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 62ebb3376e..0000000000 --- a/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM python:3.8 - -WORKDIR /buddy - -COPY ./utils/bootstrap.py /buddy/utils/bootstrap.py -RUN python /buddy/utils/bootstrap.py && (cd .dependencies && find . -type f -executable | xargs echo chmod +x) diff --git a/ProjectOptions.cmake b/ProjectOptions.cmake index 31fb8fa8ea..152a6c5f3c 100644 --- a/ProjectOptions.cmake +++ b/ProjectOptions.cmake @@ -327,6 +327,9 @@ set(PRINTERS_WITH_REMOTE_ACCELEROMETER "XL" "XL_DEV_KIT") set(PRINTERS_WITH_COLDPULL "MK4") +set(PRINTERS_WITH_BED_LEVEL_CORRECTION "MK3.5" "MINI") + +set(PRINTERS_WITH_SHEET_SUPPORT "MINI" "MK3.5") # Set printer board set(BOARDS_WITH_ADVANCED_POWER "XBUDDY" "XLBUDDY" "DWARF") set(BOARDS_WITH_ILI9488 "XBUDDY" "XLBUDDY") @@ -722,6 +725,12 @@ else() define_boolean_option(HAS_COLDPULL NO) endif() +if(${PRINTER} IN_LIST PRINTERS_WITH_SHEET_SUPPORT) + define_boolean_option(HAS_SHEET_SUPPORT YES) +else() + define_boolean_option(HAS_SHEET_SUPPORT NO) +endif() + if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(DEBUG YES) define_boolean_option(NETWORKING_BENCHMARK_ENABLED YES) diff --git a/cmake/CheckRemotes.cmake b/cmake/CheckRemotes.cmake deleted file mode 100644 index 8a6b396787..0000000000 --- a/cmake/CheckRemotes.cmake +++ /dev/null @@ -1,47 +0,0 @@ -find_package(Git QUIET) - -if(NOT GIT_FOUND) - message(STATUS "Not Git Executable found. Skipping check for dangerous Git remotes.") - return() -endif() - -function(check_git_repo_for_dangerous_remotes repo_dir) - execute_process( - COMMAND "${GIT_EXECUTABLE}" remote - WORKING_DIRECTORY "${repo_dir}" - RESULT_VARIABLE res - OUTPUT_VARIABLE lst - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if(NOT res STREQUAL "0") - message(WARNING "Failed to check dangerousness of your Git remotes!") - return() - endif() - - string(REPLACE "\n" ";" lst ${lst}) - foreach(item ${lst}) - execute_process( - COMMAND "${GIT_EXECUTABLE}" remote get-url --push ${item} - WORKING_DIRECTORY "${repo_dir}" - RESULT_VARIABLE res - OUTPUT_VARIABLE url - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if(NOT res STREQUAL 0) - message(WARNING "Failed to check dangerousness of remote '${item}'!") - endif() - - if(url MATCHES "Prusa\-Firmware\-Buddy.git" OR url MATCHES "Marlin.git") - message( - FATAL_ERROR - "Oh, your remote '${item}' appears to have its push URL set to a public repository! Let me say, that this is a bad, bad idea! You are \"one push\" away from mistakenly publishing private things. Please remove this remote or set its push url to some nonsense (see below).\n git -C \"${repo_dir}\" remote set-url --push ${item} DISABLED\n" - ) - endif() - - endforeach() -endfunction() - -check_git_repo_for_dangerous_remotes("${CMAKE_SOURCE_DIR}") -check_git_repo_for_dangerous_remotes("${CMAKE_SOURCE_DIR}/lib/Marlin") diff --git a/doc/logging_components.md b/doc/logging_components.md index 2ceb8678e3..8aa9ba02ed 100644 --- a/doc/logging_components.md +++ b/doc/logging_components.md @@ -17,7 +17,6 @@ This file is generated automatically so don't edit it directly - EEPROM: LOG_SEVERITY_INFO, src/persistent_stores/store_instances/config_store/store_c_api.cpp - ESPIF: LOG_SEVERITY_INFO, lib/WUI/espif.cpp - EspFlash: LOG_SEVERITY_DEBUG, lib/WUI/esp_flash.cpp -- FSM: LOG_SEVERITY_INFO, src/common/fsm_types.cpp - FSensor: LOG_SEVERITY_INFO, src/common/filament_sensors_handler.cpp - FileSystem: LOG_SEVERITY_INFO, src/buddy/filesystem.cpp - GUI: LOG_SEVERITY_DEBUG, src/gui/logger.cpp diff --git a/include/buddy/lwipopts.h b/include/buddy/lwipopts.h index f163ce4dfa..3ee82bca60 100644 --- a/include/buddy/lwipopts.h +++ b/include/buddy/lwipopts.h @@ -15,19 +15,30 @@ extern "C" { #define CHECKSUM_BY_HARDWARE 0 #define LWIP_DHCP 1 #define MEM_ALIGNMENT 4 -// TODO: Investigate why we suddenly need so many timeouts BFW-5183 -#define MEMP_NUM_SYS_TIMEOUT 13 #define LWIP_ETHERNET 1 #define LWIP_DNS_SECURE 7 #define DNS_MAX_NAME_LENGTH 128 #if MDNS() + #define MDNS_MAX_STORED_PKTS 1 + // Each interface takes up to 6 timeouts (in addition to the packets). + // One is the "main" one, the other 5 deal with some delayed answering (and + // probably can be lowered, a lot of these could come in sequence instead + // of starting them in parallel). + // + // We limit ourselves to only one active interface and don't do mdns on the + // other. + #define MDNS_EXTRA_TIMEOUTS 6 + MDNS_MAX_STORED_PKTS #define LWIP_MDNS_RESPONDER 1 // For MDNS #define LWIP_IGMP 1 #define LWIP_NUM_NETIF_CLIENT_DATA 1 #define LWIP_NETIF_EXT_STATUS_CALLBACK 1 +#else + // No extra timeouts if no MDNS + #define MDNS_EXTRA_TIMEOUTS 0 #endif +#define MEMP_NUM_SYS_TIMEOUT 8 + MDNS_EXTRA_TIMEOUTS #define TCP_MSS 1024 #define TCP_WND (8 * TCP_MSS) diff --git a/include/buddy/lwippools.h b/include/buddy/lwippools.h index f32bc9d1d6..e6ccfff157 100644 --- a/include/buddy/lwippools.h +++ b/include/buddy/lwippools.h @@ -4,7 +4,7 @@ LWIP_MEMPOOL(PBUF_POOL_SMALL, PBUF_POOL_SMALL_SIZE, (LWIP_MEM_ALIGN_SIZE(sizeof( LWIP_MALLOC_MEMPOOL_START #if MDNS() -LWIP_MALLOC_MEMPOOL(8, 128) +LWIP_MALLOC_MEMPOOL(7, 128) #else LWIP_MALLOC_MEMPOOL(6, 128) #endif diff --git a/include/common/fsm_base_types.hpp b/include/common/fsm_base_types.hpp index 93be010e48..da61b5bd4a 100644 --- a/include/common/fsm_base_types.hpp +++ b/include/common/fsm_base_types.hpp @@ -36,12 +36,8 @@ class BaseData { SetPhase(phase); SetData(data); } - constexpr bool operator==(const BaseData &other) const { - return GetPhase() == other.GetPhase() && GetData() == other.GetData(); - } - constexpr bool operator!=(const BaseData &other) const { - return !((*this) == other); - } + + constexpr auto operator<=>(const BaseData &) const = default; }; static_assert(sizeof(BaseData) == BaseDataSZ, "Wrong size of BaseData"); diff --git a/include/common/hotend_type.hpp b/include/common/hotend_type.hpp index 15be2213b4..61f3dd6a57 100644 --- a/include/common/hotend_type.hpp +++ b/include/common/hotend_type.hpp @@ -31,7 +31,7 @@ static constexpr EnumArray hotend_ty /// Some hotend types are only supported by some printers, but the enum is the same for all -> hence this filtering array static constexpr EnumArray hotend_type_supported { { HotendType::stock, true }, - { HotendType::stock_with_sock, true }, + { HotendType::stock_with_sock, PRINTER_IS_PRUSA_MK4 || PRINTER_IS_PRUSA_MK3_5 || PRINTER_IS_PRUSA_iX }, { HotendType::e3d_revo, PRINTER_IS_PRUSA_MK3_5 }, }; diff --git a/include/guiconfig/GuiDefaults.hpp b/include/guiconfig/GuiDefaults.hpp index 54d214be45..c2fba4d361 100644 --- a/include/guiconfig/GuiDefaults.hpp +++ b/include/guiconfig/GuiDefaults.hpp @@ -173,7 +173,7 @@ struct GuiDefaults { static constexpr padding_ui8_t MenuPaddingSpecial = padding_ui8_t({ 0, 6, 0, 0 }); #elif defined(USE_ILI9488) static constexpr size_t MenuUseFixedUnitWidth = 0; // 0 == calculate in runtime - static constexpr Rect16::Width_t MenuScrollbarWidth = 4; + static constexpr Rect16::Width_t MenuScrollbarWidth = 8; static constexpr uint8_t MenuItemCornerRadius = 5; // static constexpr padding_ui8_t MenuItemDelimiterPadding = padding_ui8_t({ 41, 0, 37, 0 }); static constexpr padding_ui8_t MenuPaddingItems = padding_ui8_t({ 6, 10, 6, 10 }); diff --git a/include/marlin/Configuration_MINI.h b/include/marlin/Configuration_MINI.h index aeb57c3d43..86e36429c4 100644 --- a/include/marlin/Configuration_MINI.h +++ b/include/marlin/Configuration_MINI.h @@ -687,6 +687,12 @@ #define DEFAULT_MAX_FEEDRATE \ { 180, 180, 12, 80 } +/// HW limits of feed rate +#define HWLIMIT_NORMAL_MAX_FEEDRATE \ + { 400, 400, 12, 80 } +#define HWLIMIT_STEALTH_MAX_FEEDRATE \ + { 180, 180, 12, 80 } + /** * Default Max Acceleration (change/s) change = mm/s * (Maximum start speed for accelerated moves) @@ -696,6 +702,12 @@ #define DEFAULT_MAX_ACCELERATION \ { 1250, 1250, 400, 4000 } +/// HW limits of max acceleration +#define HWLIMIT_NORMAL_MAX_ACCELERATION \ + { 4000, 4000, 400, 5000 } +#define HWLIMIT_STEALTH_MAX_ACCELERATION \ + { 2500, 2500, 400, 5000 } + /** * Default Acceleration (change/s) change = mm/s * Override with M204 @@ -708,6 +720,14 @@ #define DEFAULT_RETRACT_ACCELERATION 1250 // E acceleration for retracts #define DEFAULT_TRAVEL_ACCELERATION 1250 // X, Y, Z acceleration for travel (non printing) moves +/// HW limits of Acceleration +#define HWLIMIT_NORMAL_ACCELERATION 4000 +#define HWLIMIT_STEALTH_ACCELERATION 2500 +#define HWLIMIT_NORMAL_RETRACT_ACCELERATION 1250 +#define HWLIMIT_STEALTH_RETRACT_ACCELERATION 1250 +#define HWLIMIT_NORMAL_TRAVEL_ACCELERATION 4000 +#define HWLIMIT_STEALTH_TRAVEL_ACCELERATION 2500 + // // Use Junction Deviation instead of traditional Jerk Limiting // @@ -734,6 +754,10 @@ #define DEFAULT_EJERK 10 // May be used by Linear Advance +/// HW limits of Jerk +#define HWLIMIT_NORMAL_JERK { 8, 8, 2, 10 } +#define HWLIMIT_STEALTH_JERK { 8, 8, 2, 10 } + /** * S-Curve Acceleration * diff --git a/include/marlin/Configuration_MK3.5.h b/include/marlin/Configuration_MK3.5.h index 8799ed3dc8..9f431956c4 100644 --- a/include/marlin/Configuration_MK3.5.h +++ b/include/marlin/Configuration_MK3.5.h @@ -751,6 +751,12 @@ #define DEFAULT_MAX_FEEDRATE \ { 200, 200, 40, 45 } +/// HW limits of feed rate +#define HWLIMIT_NORMAL_MAX_FEEDRATE \ + { 300, 300, 12, 120 } +#define HWLIMIT_STEALTH_MAX_FEEDRATE \ + { 160, 160, 40, 100 } + /** * Default Max Acceleration (change/s) change = mm/s * (Maximum start speed for accelerated moves) @@ -760,6 +766,12 @@ #define DEFAULT_MAX_ACCELERATION \ { 1250, 1250, 400, 4000 } +/// HW limits of max acceleration +#define HWLIMIT_NORMAL_MAX_ACCELERATION \ + { 4000, 4000, 200, 2500 } +#define HWLIMIT_STEALTH_MAX_ACCELERATION \ + { 2500, 2500, 200, 2500 } + /** * Default Acceleration (change/s) change = mm/s * Override with M204 @@ -772,6 +784,14 @@ #define DEFAULT_RETRACT_ACCELERATION 1250 // E acceleration for retracts #define DEFAULT_TRAVEL_ACCELERATION 1250 // X, Y, Z acceleration for travel (non printing) moves +/// HW limits of Acceleration +#define HWLIMIT_NORMAL_ACCELERATION 4000 +#define HWLIMIT_STEALTH_ACCELERATION 2500 +#define HWLIMIT_NORMAL_RETRACT_ACCELERATION 1250 +#define HWLIMIT_STEALTH_RETRACT_ACCELERATION 1200 +#define HWLIMIT_NORMAL_TRAVEL_ACCELERATION 4000 +#define HWLIMIT_STEALTH_TRAVEL_ACCELERATION 2500 + // // Use Junction Deviation instead of traditional Jerk Limiting // @@ -796,6 +816,10 @@ #define DEFAULT_EJERK 5 // May be used by Linear Advance +/// HW limits of Jerk +#define HWLIMIT_NORMAL_JERK { 8, 8, 2, 5 } +#define HWLIMIT_STEALTH_JERK { 8, 8, 2, 5 } + /** * S-Curve Acceleration * diff --git a/include/marlin/Configuration_MK3.5_adv.h b/include/marlin/Configuration_MK3.5_adv.h index 52599e526b..46994d30e0 100644 --- a/include/marlin/Configuration_MK3.5_adv.h +++ b/include/marlin/Configuration_MK3.5_adv.h @@ -1087,10 +1087,26 @@ #if EITHER(MESH_BED_LEVELING, AUTO_BED_LEVELING_UBL) // Override the mesh area if the automatic (max) area is too large -#define MESH_MIN_X 0 -#define MESH_MIN_Y 0 -#define MESH_MAX_X X_BED_SIZE -#define MESH_MAX_Y Y_BED_SIZE +// The numbers are from the distance equation combined with relative position due to probe offset MESH_X_DIST define and function position_reachable_by_probe from motion.h respectively + +// 1|19 for corner probe positions +// 20 for number of travels between probe points (21 set by Marlin) +// offset is defined in printer config +// bounds were found by trial and error using G0 and looking whether position is "nice" + +// min + 1 * (max - min) / 20 - offset = low_bound; +// min + 19 * (max - min) / 20 - offset = high_bound;. +// Highbounds: +// Leftmost position for X is 225 +// Reartmost postition for Y is 204 +// Lowbounds: +// Rightmost position for X is 0 +// Frontmost position for Y is -4 (defined elsewhere: Y_MIN_POS) + +#define MESH_MIN_X (10.5f) +#define MESH_MIN_Y (-10.5f) +#define MESH_MAX_X (X_BED_SIZE + MESH_MIN_X) +#define MESH_MAX_Y (Y_BED_SIZE - MESH_MIN_Y) #endif /** diff --git a/include/marlin/Configuration_MK4.h b/include/marlin/Configuration_MK4.h index 38d3de000e..dcb7ff3f5d 100644 --- a/include/marlin/Configuration_MK4.h +++ b/include/marlin/Configuration_MK4.h @@ -761,6 +761,12 @@ #define DEFAULT_MAX_FEEDRATE \ { 400, 400, 40, 50 } +/// HW limits of feed rate +#define HWLIMIT_NORMAL_MAX_FEEDRATE \ + { 300, 300, 40, 100 } +#define HWLIMIT_STEALTH_MAX_FEEDRATE \ + { 160, 160, 40, 100 } + /** * Default Max Acceleration (change/s) change = mm/s * (Maximum start speed for accelerated moves) @@ -770,6 +776,13 @@ #define DEFAULT_MAX_ACCELERATION \ { 1250, 1250, 200, 1500 } +/// HW limits of max acceleration +#define HWLIMIT_NORMAL_MAX_ACCELERATION \ + { 4000, 4000, 200, 2500 } +#define HWLIMIT_STEALTH_MAX_ACCELERATION \ + { 2500, 2500, 200, 2500 } + + /** * Default Acceleration (change/s) change = mm/s * Override with M204 @@ -782,6 +795,14 @@ #define DEFAULT_RETRACT_ACCELERATION 800 // E acceleration for retracts #define DEFAULT_TRAVEL_ACCELERATION 1250 // X, Y, Z acceleration for travel (non printing) moves +/// HW limits of Acceleration +#define HWLIMIT_NORMAL_ACCELERATION 4000 +#define HWLIMIT_STEALTH_ACCELERATION 2500 +#define HWLIMIT_NORMAL_RETRACT_ACCELERATION 1200 +#define HWLIMIT_STEALTH_RETRACT_ACCELERATION 1200 +#define HWLIMIT_NORMAL_TRAVEL_ACCELERATION 4000 +#define HWLIMIT_STEALTH_TRAVEL_ACCELERATION 2500 + // // Use Junction Deviation instead of traditional Jerk Limiting // @@ -806,6 +827,10 @@ #define DEFAULT_EJERK 5 // May be used by Linear Advance +/// HW limits of Jerk +#define HWLIMIT_NORMAL_JERK { 8, 8, 2, 10 } +#define HWLIMIT_STEALTH_JERK { 8, 8, 2, 10 } + /** * S-Curve Acceleration * diff --git a/include/marlin/Configuration_XL.h b/include/marlin/Configuration_XL.h index 967bdff763..7e6d445eb4 100644 --- a/include/marlin/Configuration_XL.h +++ b/include/marlin/Configuration_XL.h @@ -785,6 +785,12 @@ #define DEFAULT_MAX_FEEDRATE \ { 550, 550, 12, DEFAULT_MAX_MAX_E_FEEDRATE } +/// HW limits of feed rate +#define HWLIMIT_NORMAL_MAX_FEEDRATE \ + { 400, 400, 40, 100 } +#define HWLIMIT_STEALTH_MAX_FEEDRATE \ + { 140, 140, 12, 100 } + /** * Default feedrate after startup as used by G0/G1 etc * First G0 F overrides this @@ -800,6 +806,12 @@ #define DEFAULT_MAX_ACCELERATION \ { 5000, 5000, 200, 1500 } +/// HW limits of max acceleration +#define HWLIMIT_NORMAL_MAX_ACCELERATION \ + { 7000, 7000, 200, 2500 } +#define HWLIMIT_STEALTH_MAX_ACCELERATION \ + { 2500, 2500, 200, 2500 } + /** * Default Acceleration (change/s) change = mm/s * Override with M204 @@ -812,6 +824,14 @@ #define DEFAULT_RETRACT_ACCELERATION 1200 // E acceleration for retracts #define DEFAULT_TRAVEL_ACCELERATION 5000 // X, Y, Z acceleration for travel (non printing) moves +/// HW limits of Acceleration +#define HWLIMIT_NORMAL_ACCELERATION 7000 +#define HWLIMIT_STEALTH_ACCELERATION 2500 +#define HWLIMIT_NORMAL_RETRACT_ACCELERATION 1200 +#define HWLIMIT_STEALTH_RETRACT_ACCELERATION 1200 +#define HWLIMIT_NORMAL_TRAVEL_ACCELERATION 7000 +#define HWLIMIT_STEALTH_TRAVEL_ACCELERATION 2500 + // // Use Junction Deviation instead of traditional Jerk Limiting // @@ -837,6 +857,10 @@ #define DEFAULT_EJERK 5 // May be used by Linear Advance +/// HW limits of Jerk +#define HWLIMIT_NORMAL_JERK { 8, 8, 2, 10 } +#define HWLIMIT_STEALTH_JERK {8, 8, 2, 10 } + /** * S-Curve Acceleration * diff --git a/include/marlin/Configuration_XL_DEV_KIT.h b/include/marlin/Configuration_XL_DEV_KIT.h index c65af45e56..03a24bbe59 100644 --- a/include/marlin/Configuration_XL_DEV_KIT.h +++ b/include/marlin/Configuration_XL_DEV_KIT.h @@ -785,6 +785,12 @@ #define DEFAULT_MAX_FEEDRATE \ { 3000, 3000, 12, DEFAULT_MAX_MAX_E_FEEDRATE } +/// HW limits of feed rate +#define HWLIMIT_NORMAL_MAX_FEEDRATE \ + { 400, 400, 40, 100 } +#define HWLIMIT_STEALTH_MAX_FEEDRATE \ + { 140, 140, 12, 100 } + /** * Default feedrate after startup as used by G0/G1 etc * First G0 F overrides this @@ -800,6 +806,12 @@ #define DEFAULT_MAX_ACCELERATION \ { 5000, 5000, 200, 1500 } +/// HW limits of max acceleration +#define HWLIMIT_NORMAL_MAX_ACCELERATION \ + { 7000, 7000, 200, 2500 } +#define HWLIMIT_STEALTH_MAX_ACCELERATION \ + { 2500, 2500, 200, 2500 } + /** * Default Acceleration (change/s) change = mm/s * Override with M204 @@ -812,6 +824,14 @@ #define DEFAULT_RETRACT_ACCELERATION 1200 // E acceleration for retracts #define DEFAULT_TRAVEL_ACCELERATION 5000 // X, Y, Z acceleration for travel (non printing) moves +/// HW limits of Acceleration +#define HWLIMIT_NORMAL_ACCELERATION 7000 +#define HWLIMIT_STEALTH_ACCELERATION 2500 +#define HWLIMIT_NORMAL_RETRACT_ACCELERATION 1200 +#define HWLIMIT_STEALTH_RETRACT_ACCELERATION 1200 +#define HWLIMIT_NORMAL_TRAVEL_ACCELERATION 7000 +#define HWLIMIT_STEALTH_TRAVEL_ACCELERATION 2500 + // // Use Junction Deviation instead of traditional Jerk Limiting // @@ -837,6 +857,10 @@ #define DEFAULT_EJERK 5 // May be used by Linear Advance +/// HW limits of Jerk +#define HWLIMIT_NORMAL_JERK { 8, 8, 2, 10 } +#define HWLIMIT_STEALTH_JERK {8, 8, 2, 10 } + /** * S-Curve Acceleration * diff --git a/include/marlin/Configuration_XL_Dwarf.h b/include/marlin/Configuration_XL_Dwarf.h index b57ec6d505..0130b1fc03 100644 --- a/include/marlin/Configuration_XL_Dwarf.h +++ b/include/marlin/Configuration_XL_Dwarf.h @@ -733,6 +733,12 @@ #define DEFAULT_MAX_FEEDRATE \ { 180, 180, 12, 80 } +/// HW limits of feed rate +#define HWLIMIT_NORMAL_MAX_FEEDRATE \ + { 180, 180, 40, 100 } +#define HWLIMIT_STEALTH_MAX_FEEDRATE \ + { 180, 180, 40, 100 } + /** * Default Max Acceleration (change/s) change = mm/s * (Maximum start speed for accelerated moves) @@ -742,6 +748,12 @@ #define DEFAULT_MAX_ACCELERATION \ { 1250, 1250, 400, 4000 } +/// HW limits of max acceleration +#define HWLIMIT_NORMAL_MAX_ACCELERATION \ + { 7000, 7000, 200, 2500 } +#define HWLIMIT_STEALTH_MAX_ACCELERATION \ + { 2500, 2500, 200, 2500 } + /** * Default Acceleration (change/s) change = mm/s * Override with M204 @@ -754,6 +766,14 @@ #define DEFAULT_RETRACT_ACCELERATION 1250 // E acceleration for retracts #define DEFAULT_TRAVEL_ACCELERATION 250 // X, Y, Z acceleration for travel (non printing) moves +/// HW limits of Acceleration +#define HWLIMIT_NORMAL_ACCELERATION 7000 +#define HWLIMIT_STEALTH_ACCELERATION 2500 +#define HWLIMIT_NORMAL_RETRACT_ACCELERATION 1200 +#define HWLIMIT_STEALTH_RETRACT_ACCELERATION 1200 +#define HWLIMIT_NORMAL_TRAVEL_ACCELERATION 7000 +#define HWLIMIT_STEALTH_TRAVEL_ACCELERATION 2500 + // // Use Junction Deviation instead of traditional Jerk Limiting // @@ -778,6 +798,10 @@ #define DEFAULT_EJERK 10 // May be used by Linear Advance +/// HW limits of Jerk +#define HWLIMIT_NORMAL_JERK { 10, 10, 2, 10 } +#define HWLIMIT_STEALTH_JERK { 10, 10, 2, 10 } + /** * S-Curve Acceleration * diff --git a/include/marlin/Configuration_iX.h b/include/marlin/Configuration_iX.h index 0db53b30b4..74e5c61989 100644 --- a/include/marlin/Configuration_iX.h +++ b/include/marlin/Configuration_iX.h @@ -756,6 +756,12 @@ { 100, 100, 800, 380 } +/// HW limits of feed rate +#define HWLIMIT_NORMAL_MAX_FEEDRATE \ + { 400, 400, 40, 100 } +#define HWLIMIT_STEALTH_MAX_FEEDRATE \ + { 140, 140, 12, 100 } + /** * Default Max Feed Rate (mm/s) * Override with M203 @@ -764,6 +770,12 @@ #define DEFAULT_MAX_FEEDRATE \ { 200, 200, 12, 60 } +/// HW limits of max acceleration +#define HWLIMIT_NORMAL_MAX_ACCELERATION \ + { 7000, 7000, 200, 2500 } +#define HWLIMIT_STEALTH_MAX_ACCELERATION \ + { 2500, 2500, 200, 2500 } + /** * Default Max Acceleration (change/s) change = mm/s * (Maximum start speed for accelerated moves) @@ -773,6 +785,14 @@ #define DEFAULT_MAX_ACCELERATION \ { 1500, 1500, 1000, 5000 } +/// HW limits of Acceleration +#define HWLIMIT_NORMAL_ACCELERATION 7000 +#define HWLIMIT_STEALTH_ACCELERATION 2500 +#define HWLIMIT_NORMAL_RETRACT_ACCELERATION 1200 +#define HWLIMIT_STEALTH_RETRACT_ACCELERATION 1200 +#define HWLIMIT_NORMAL_TRAVEL_ACCELERATION 7000 +#define HWLIMIT_STEALTH_TRAVEL_ACCELERATION 2500 + /** * Default Acceleration (change/s) change = mm/s * Override with M204 @@ -809,6 +829,10 @@ #define DEFAULT_EJERK 5 // May be used by Linear Advance +/// HW limits of Jerk +#define HWLIMIT_NORMAL_JERK { 8, 8, 2, 10 } +#define HWLIMIT_STEALTH_JERK {8, 8, 2, 10 } + /** * S-Curve Acceleration * diff --git a/include/puppies/Dwarf.hpp b/include/puppies/Dwarf.hpp index f00bde77fc..4bc75f3b04 100644 --- a/include/puppies/Dwarf.hpp +++ b/include/puppies/Dwarf.hpp @@ -420,7 +420,6 @@ void ToolsMappingBody::windowEvent(EventLock, [[maybe_unused]] window_t *sender, CommunicationStatus read_discrete_general_status(); CommunicationStatus read_general_status(); void handle_dwarf_fault(); - void report_accelerometer(int samples_received); bool raw_set_loadcell(bool active); // Low level loadcell enable/disable, no dependencies bool raw_set_accelerometer(bool active); // Low level accelerometer enable/disable, no dependencies CommunicationStatus read_fifo(std::array &fifo, size_t &read); // Handle fifo read retries 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/lib/Marlin/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/lib/Marlin/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index d66441a378..0ba144748c 100644 --- a/lib/Marlin/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/lib/Marlin/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -21,6 +21,7 @@ */ #include "../../../inc/MarlinConfig.h" +#include "config_store/store_instance.hpp" #if ENABLED(AUTO_BED_LEVELING_UBL) @@ -295,6 +296,35 @@ * features of all three systems combined. */ + #if PRINTER_IS_PRUSA_MK3_5 || PRINTER_IS_PRUSA_MINI + + // Apply weighted correction on each point based on it's location. + // The whole correction is then conversed from µm to mm. + + float x_axis_correction(int x, int y) { + int32_t left_correction_um{config_store().left_bed_correction.get()}; + int32_t right_correction_um{config_store().right_bed_correction.get()}; + + int32_t x_len{GRID_MAX_POINTS_X-1}; + + return ( (left_correction_um*(x_len-x)) + (right_correction_um*(x)) ) / static_cast(x_len); + } + + float y_axis_correction(int x, int y) { + int32_t front_correction_um{config_store().front_bed_correction.get()}; + int32_t rear_correction_um{config_store().rear_bed_correction.get()}; + + int32_t y_len{GRID_MAX_POINTS_Y-1}; + + return ( (front_correction_um*(y_len-y)) + (rear_correction_um*(y)) ) / static_cast(y_len); + } + + void apply_bed_level_correction(int x, int y) { + ubl.z_values[x][y] += 0.001f*(x_axis_correction(x, y) + y_axis_correction(x,y)); + } + + #endif + void unified_bed_leveling::G29() { bool probe_deployed = false; @@ -806,8 +836,12 @@ #endif #if UBL_TRAVEL_ACCELERATION - auto saved_acceleration = planner.settings.travel_acceleration; - planner.settings.travel_acceleration = UBL_TRAVEL_ACCELERATION; + auto saved_acceleration = planner.user_settings.travel_acceleration; + { + auto s = planner.user_settings; + s.travel_acceleration = UBL_TRAVEL_ACCELERATION; + planner.apply_settings(s); + } #endif uint16_t count = GRID_MAX_POINTS; @@ -857,7 +891,11 @@ #endif #if UBL_TRAVEL_ACCELERATION - planner.settings.travel_acceleration = saved_acceleration; + { + auto s = planner.user_settings; + s.travel_acceleration = saved_acceleration; + planner.apply_settings(s); + } #endif restore_ubl_active_state_and_leave(); @@ -878,7 +916,11 @@ #if UBL_TRAVEL_ACCELERATION auto saved_acceleration = planner.settings.travel_acceleration; - planner.settings.travel_acceleration = UBL_TRAVEL_ACCELERATION; + { + auto s = planner.user_settings; + s.travel_acceleration = UBL_TRAVEL_ACCELERATION; + planner.apply_settings(s); + } #endif PrintArea::rect_t probe_area(area_a, area_b); @@ -947,6 +989,12 @@ return; } z_values[x][y] = measured_z; + + #if PRINTER_IS_PRUSA_MK3_5 || PRINTER_IS_PRUSA_MINI + //apply bed level correction on each probed point + apply_bed_level_correction(x,y); + #endif + #if ENABLED(EXTENSIBLE_UI) ExtUI::onMeshUpdate(x, y, measured_z); #endif @@ -964,7 +1012,11 @@ #endif #if UBL_TRAVEL_ACCELERATION - planner.settings.travel_acceleration = saved_acceleration; + { + auto s = planner.user_settings; + s.travel_acceleration = saved_acceleration; + planner.apply_settings(s); + } #endif restore_ubl_active_state_and_leave(); 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. diff --git a/lib/Marlin/Marlin/src/feature/phase_stepping/calibration.cpp b/lib/Marlin/Marlin/src/feature/phase_stepping/calibration.cpp index ef819f1917..4290dafb55 100644 --- a/lib/Marlin/Marlin/src/feature/phase_stepping/calibration.cpp +++ b/lib/Marlin/Marlin/src/feature/phase_stepping/calibration.cpp @@ -16,9 +16,6 @@ using namespace phase_stepping::opts; LOG_COMPONENT_REF(PhaseStepping); -// Currently re/set by M977 -CalibrationResult phase_stepping::last_calibration_result = CalibrationResult::make_unknown(); - // Temporary debugging to Marlin serial for convenience #define SERIAL_DEBUG @@ -379,7 +376,6 @@ std::vector phase_stepping::analyze_resonance(AxisEnum axis, } }); - log_info(PhaseStepping, "Accelerometer sampling freq: %f", sampling_freq); if (sampling_freq < 1100 || sampling_freq > 1500) { log_error(PhaseStepping, "Sampling freq out of range: %f", sampling_freq); return {}; @@ -431,7 +427,7 @@ class CalibrationPhaseExecutor { AxisEnum _axis; const PrinterCalibrationConfig &_printer_config; const CalibrationPhase &_phase_config; - CalibrationReporterBase &_reporter; + CalibrateAxisHooks &_hooks; int _progress = 0; int _progress_tick_count() const { @@ -443,6 +439,14 @@ class CalibrationPhaseExecutor { template requires requires(F f, MotorPhaseCorrection &mpc, int i, float x) { f(mpc, i, x); } std::optional> _run_simultaneous_search( +#define IDLE() \ + do { \ + idle(true, true); \ + if (_hooks.on_idle() == phase_stepping::CalibrateAxisHooks::ContinueOrAbort::Abort) { \ + return {}; \ + } \ + } while (0) + InterruptableGoldenSearch forward_search, InterruptableGoldenSearch backward_search, int iterations, @@ -461,13 +465,13 @@ class CalibrationPhaseExecutor { apply_x(table, 0, forward_search.x()); }); - idle(true, true); + IDLE(); axis_state.backward_current.modify_correction([&](auto &table) { apply_x(table, 1, backward_search.x()); }); - idle(true, true); + IDLE(); for (int retries = 0; retries <= RETRY_COUNT; retries++) { if (retries == RETRY_COUNT) { @@ -481,12 +485,12 @@ class CalibrationPhaseExecutor { auto b_res = phase_stepping::analyze_resonance(_axis, _phase_config.speed, _printer_config.calib_revs, { _phase_config.harmonic }); - idle(true, true); + IDLE(); auto f_res = phase_stepping::analyze_resonance(_axis, _phase_config.speed, -_printer_config.calib_revs, { _phase_config.harmonic }); - idle(true, true); + IDLE(); if (!f_res.empty() && !b_res.empty()) { forward_search.submit(f_res[0]); @@ -495,23 +499,24 @@ class CalibrationPhaseExecutor { } log_error(PhaseStepping, "Resonance analysis failed in argument search"); } - _reporter.on_calibration_phase_progress(100 * (_progress++) / _progress_tick_count()); + _hooks.on_calibration_phase_progress(100 * (_progress++) / _progress_tick_count()); - idle(true, true); + IDLE(); } // Apply the result axis_state.forward_current.modify_correction([&](auto &table) { apply_x(table, 0, forward_search.arg_min()); }); - idle(true, true); + IDLE(); axis_state.backward_current.modify_correction([&](auto &table) { apply_x(table, 1, backward_search.arg_min()); }); - idle(true, true); + IDLE(); return { { forward_search.min(), backward_search.min() } }; +#undef IDLE } const SpectralItem &_get_fwd_item() const { @@ -525,11 +530,11 @@ class CalibrationPhaseExecutor { public: CalibrationPhaseExecutor( AxisEnum axis, const PrinterCalibrationConfig &printer_config, - const CalibrationPhase &phase_config, CalibrationReporterBase &reporter) + const CalibrationPhase &phase_config, CalibrateAxisHooks &hooks) : _axis(axis) , _printer_config(printer_config) , _phase_config(phase_config) - , _reporter(reporter) {} + , _hooks(hooks) {} std::optional> baseline() { for (int retries = 0; retries != RETRY_COUNT; retries++) { @@ -588,7 +593,7 @@ class CalibrationPhaseExecutor { }; std::optional> -phase_stepping::calibrate_axis(AxisEnum axis, CalibrationReporterBase &reporter) { +phase_stepping::calibrate_axis(AxisEnum axis, CalibrateAxisHooks &hooks) { std::optional> r; const auto config = get_printer_calibration_config(); @@ -597,17 +602,17 @@ phase_stepping::calibrate_axis(AxisEnum axis, CalibrationReporterBase &reporter) phase_stepping::EnsureEnabled _; - reporter.on_initial_movement(); + hooks.on_initial_movement(); move_to_calibration_start(axis, config); Planner::synchronize(); - reporter.set_calibration_phases_count(config.phases.size()); + hooks.set_calibration_phases_count(config.phases.size()); for (std::size_t phase_i = 0; phase_i != config.phases.size(); phase_i++) { const CalibrationPhase &calib_phase = config.phases[phase_i]; - reporter.on_enter_calibration_phase(phase_i); + hooks.on_enter_calibration_phase(phase_i); - auto executor = CalibrationPhaseExecutor(axis, config, calib_phase, reporter); + auto executor = CalibrationPhaseExecutor(axis, config, calib_phase, hooks); auto baseline_res = executor.baseline(); if (!baseline_res.has_value()) { return r; @@ -620,9 +625,9 @@ phase_stepping::calibrate_axis(AxisEnum axis, CalibrationReporterBase &reporter) } auto [min_f, min_b] = *calib_res; - reporter.on_calibration_phase_result(min_f / baseline_f, min_b / baseline_b); + hooks.on_calibration_phase_result(min_f / baseline_f, min_b / baseline_b); } - reporter.on_termination(); + hooks.on_termination(); r.emplace(); std::get<0>(*r) = phase_stepping::axis_states[axis]->forward_current.get_correction(); diff --git a/lib/Marlin/Marlin/src/feature/phase_stepping/calibration.hpp b/lib/Marlin/Marlin/src/feature/phase_stepping/calibration.hpp index ce003889d4..e4a55d33cd 100644 --- a/lib/Marlin/Marlin/src/feature/phase_stepping/calibration.hpp +++ b/lib/Marlin/Marlin/src/feature/phase_stepping/calibration.hpp @@ -41,13 +41,9 @@ std::vector analyze_resonance(AxisEnum axis, * Calibration routine notifies about the progress made via this class. Subclass * it and pass it to the calibration routine. */ -class CalibrationReporterBase { -protected: - int _calibration_phases_count = -1; - int _current_calibration_phase = 0; - +class CalibrateAxisHooks { public: - virtual ~CalibrationReporterBase() = default; + virtual ~CalibrateAxisHooks() = default; /** * Report initial movement is in progress @@ -57,16 +53,12 @@ class CalibrationReporterBase { /** * Set number of calibration phases */ - virtual void set_calibration_phases_count(int phases) { - _calibration_phases_count = phases; - } + virtual void set_calibration_phases_count(int phases) = 0; /** * Report beginning of the new phase */ - virtual void on_enter_calibration_phase(int phase) { - _current_calibration_phase = phase; - } + virtual void on_enter_calibration_phase(int phase) = 0; /** * Report progress in percent for given phase @@ -82,64 +74,21 @@ class CalibrationReporterBase { * Report calibration termination */ virtual void on_termination() = 0; + + enum class ContinueOrAbort { + Continue, + Abort, + }; + virtual ContinueOrAbort on_idle() = 0; }; /** * Assuming the printer is homed, calibrate given axis. The progress is reported - * via reporter. The routine is blocking. + * via hooks. The routine is blocking. * * Returns a tuple with forward and backward calibration */ std::optional> -calibrate_axis(AxisEnum axis, CalibrationReporterBase &reporter); - -class CalibrationResult { -public: - struct Scores { - float p1f; - float p1b; - float p2f; - float p2b; - }; - - enum class State { - unknown, // calibration not run - known, // calibration ran to completion - error, // calibration failed - }; - -private: - Scores scores; - State state; - - constexpr CalibrationResult(const Scores &scores, const State &state) - : scores { scores } - , state { state } {} - -public: - constexpr State get_state() const { return state; } - - constexpr static CalibrationResult make_unknown() { - return { Scores {}, State::unknown }; - } - - constexpr static CalibrationResult make_error() { - return { Scores {}, State::error }; - } - - constexpr static CalibrationResult make_known(const Scores &scores) { - return { scores, State::known }; - } - - constexpr const Scores &get_scores() const { - assert(get_state() == State::known); - return scores; - } -}; - -/** - * Global state of the last axis calibration. Re/set by M977. - */ -extern CalibrationResult last_calibration_result; +calibrate_axis(AxisEnum axis, CalibrateAxisHooks &hooks); } // namespace phase_stepping diff --git a/lib/Marlin/Marlin/src/feature/phase_stepping/phase_stepping.cpp b/lib/Marlin/Marlin/src/feature/phase_stepping/phase_stepping.cpp index c41042fe9b..56152d5316 100644 --- a/lib/Marlin/Marlin/src/feature/phase_stepping/phase_stepping.cpp +++ b/lib/Marlin/Marlin/src/feature/phase_stepping/phase_stepping.cpp @@ -449,7 +449,7 @@ void phase_stepping::enable(AxisEnum axis_num, bool enable) { if (enable) { // Enable phase stepping and reset PS to update the phase origin phase_stepping::enable_phase_stepping(axis_num); - PreciseStepping::reset_from_halt(true); + PreciseStepping::reset_from_halt(); } else { phase_stepping::disable_phase_stepping(axis_num); } @@ -821,8 +821,12 @@ void load_correction_from_file(CorrectedCurrentLut &lut, const char *file_path) void save_to_persistent_storage(AxisEnum axis) { assert(axis < SUPPORTED_AXIS_COUNT); + save_to_persistent_storage_without_enabling(axis); config_store().set_phase_stepping_enabled(axis, axis_states[axis]->active); +} +void save_to_persistent_storage_without_enabling(AxisEnum axis) { + assert(axis < SUPPORTED_AXIS_COUNT); save_correction_to_file(axis_states[axis]->forward_current, get_correction_file_path(axis, CorrectionType::forward)); save_correction_to_file(axis_states[axis]->backward_current, get_correction_file_path(axis, CorrectionType::backward)); } diff --git a/lib/Marlin/Marlin/src/feature/phase_stepping/phase_stepping.hpp b/lib/Marlin/Marlin/src/feature/phase_stepping/phase_stepping.hpp index ff741d67bc..5a2589e573 100644 --- a/lib/Marlin/Marlin/src/feature/phase_stepping/phase_stepping.hpp +++ b/lib/Marlin/Marlin/src/feature/phase_stepping/phase_stepping.hpp @@ -339,9 +339,21 @@ class EnsureState { } EnsureState(const EnsureState &) = delete; - EnsureState(const EnsureState &&) = delete; + EnsureState(EnsureState &&other) { + *this = std::move(other); + }; EnsureState &operator=(const EnsureState &) = delete; - EnsureState &operator=(const EnsureState &&) = delete; + EnsureState &operator=(EnsureState &&other) { + released = other.released; + any_axis_change = other.any_axis_change; + _prev_active = other._prev_active; + + // Invalidate the previous object so it doesn't reset the settings + other.released = true; + other.any_axis_change = false; + + return *this; + }; ~EnsureState() { release(); @@ -413,6 +425,9 @@ void save_correction_to_file(const CorrectedCurrentLut &lut, const char *file_pa */ void load_correction_from_file(CorrectedCurrentLut &lut, const char *file_path); +/** Like save_to_persistent_storage() but does not enable */ +void save_to_persistent_storage_without_enabling(AxisEnum axis); + /** * @brief Call to save current state into persistent media (ie eeprom/xflash) * state == lookup tables, is enabled/disabled diff --git a/lib/Marlin/Marlin/src/feature/precise_stepping/common.hpp b/lib/Marlin/Marlin/src/feature/precise_stepping/common.hpp index 3d16b6c4f6..7aba8e35db 100644 --- a/lib/Marlin/Marlin/src/feature/precise_stepping/common.hpp +++ b/lib/Marlin/Marlin/src/feature/precise_stepping/common.hpp @@ -248,7 +248,7 @@ struct step_generator_state_t { StepEventFlag_t flags; // current axis/direction flags step_event_i32_t buffered_step; // accumulator for multi-axis step fusion - xyze_long_t current_distance; + xyze_long_t current_distance; // current axis position (steps, physical) // Number of markers indicating the start of move segments that need to be inserted into step events. // Be aware that very short move segments could produce just one single step event or none step event diff --git a/lib/Marlin/Marlin/src/feature/precise_stepping/precise_stepping.cpp b/lib/Marlin/Marlin/src/feature/precise_stepping/precise_stepping.cpp index fe6d66887d..7fb823d953 100644 --- a/lib/Marlin/Marlin/src/feature/precise_stepping/precise_stepping.cpp +++ b/lib/Marlin/Marlin/src/feature/precise_stepping/precise_stepping.cpp @@ -295,6 +295,7 @@ bool append_move_segments_to_queue(const block_t &block) { print_time += decel_t; } + PreciseStepping::flags |= active_axis; PreciseStepping::total_start_pos_msteps += get_oriented_msteps_from_block(block); PreciseStepping::total_start_pos = convert_oriented_msteps_to_distance(PreciseStepping::total_start_pos_msteps); PreciseStepping::total_print_time = print_time; @@ -563,23 +564,49 @@ void PreciseStepping::init() { } void PreciseStepping::reset_from_halt(bool preserve_step_fraction) { - PreciseStepping::step_generator_state_clear(); - PreciseStepping::total_print_time = 0.; - PreciseStepping::flags = 0; - - if (preserve_step_fraction) { - // Because of pressure advance, the amount of material in total_start_pos_msteps doesn't - // have to equal to step_generator_state.current_distance.e. So we always reset extrude - // steps to zero because losing a fraction of a step in the E-axis shouldn't cause any - // issues. - total_start_pos_msteps.e = 0; + assert(!PreciseStepping::has_blocks_queued()); - PreciseStepping::total_start_pos = convert_oriented_msteps_to_distance(PreciseStepping::total_start_pos_msteps); + if (!preserve_step_fraction) { + // rebuild msteps from the stepper counters unconditionally +#ifdef COREXY + total_start_pos_msteps.x = (stepper.count_position_from_startup.x + stepper.count_position_from_startup.y) * PLANNER_STEPS_MULTIPLIER / 2; + total_start_pos_msteps.y = (stepper.count_position_from_startup.x - stepper.count_position_from_startup.y) * PLANNER_STEPS_MULTIPLIER / 2; + total_start_pos_msteps.z = stepper.count_position_from_startup.z * PLANNER_STEPS_MULTIPLIER; +#else + total_start_pos_msteps = stepper.count_position_from_startup * PLANNER_STEPS_MULTIPLIER; +#endif } else { - PreciseStepping::total_start_pos_msteps = stepper.count_position_from_startup * PLANNER_STEPS_MULTIPLIER; - PreciseStepping::total_start_pos = convert_oriented_msteps_to_distance(PreciseStepping::total_start_pos_msteps); + // Attempt to recover the step fraction only on axes which weren't interrupted by a stop as + // the generator state can be ahead of the actual motion. We rely on reset_from_halt being + // called from the main thread just before clearing the stop_pending flag + +#ifdef COREXY + // Handle XY as linked, resetting both if any is used + if (PreciseStepping::stop_pending && (PreciseStepping::flags & (PRECISE_STEPPING_FLAG_X_USED | PRECISE_STEPPING_FLAG_Y_USED))) { + total_start_pos_msteps.x = (stepper.count_position_from_startup.x + stepper.count_position_from_startup.y) * PLANNER_STEPS_MULTIPLIER / 2; + total_start_pos_msteps.y = (stepper.count_position_from_startup.x - stepper.count_position_from_startup.y) * PLANNER_STEPS_MULTIPLIER / 2; + } + + if (PreciseStepping::stop_pending && (PreciseStepping::flags & PRECISE_STEPPING_FLAG_Z_USED)) { + total_start_pos_msteps.z = stepper.count_position_from_startup.z * PLANNER_STEPS_MULTIPLIER; + } +#else + LOOP_XYZ(i) { + if (PreciseStepping::stop_pending && (PreciseStepping::flags & (PRECISE_STEPPING_FLAG_X_USED << i))) { + total_start_pos_msteps[i] = stepper.count_position_from_startup[i] * PLANNER_STEPS_MULTIPLIER; + } + } +#endif } + // Because of pressure advance, the amount of material in total_start_pos_msteps doesn't + // have to equal to step_generator_state.current_distance.e. So we always reset extrude + // steps to zero because losing a fraction of a step in the E-axis shouldn't cause any + // issues. + total_start_pos_msteps.e = 0; + + total_start_pos = convert_oriented_msteps_to_distance(total_start_pos_msteps); + #if HAS_PHASE_STEPPING() #ifdef COREXY phase_stepping::set_phase_origin(X_AXIS, total_start_pos[X_AXIS] + total_start_pos[Y_AXIS]); @@ -589,6 +616,10 @@ void PreciseStepping::reset_from_halt(bool preserve_step_fraction) { phase_stepping::set_phase_origin(Y_AXIS, total_start_pos[Y_AXIS]); #endif #endif + + PreciseStepping::step_generator_state_clear(); + PreciseStepping::total_print_time = 0.; + PreciseStepping::flags = 0; } uint16_t PreciseStepping::process_one_step_event_from_queue() { @@ -889,7 +920,7 @@ void PreciseStepping::process_queue_of_blocks() { } // we can now reset to a halt - reset_from_halt(true); + reset_from_halt(); } // fetch next block @@ -1274,17 +1305,8 @@ void PreciseStepping::step_generator_state_init(const move_t &move) { step_generator_state.previous_step_time = 0.; step_generator_state.previous_step_time_ticks = 0; step_generator_state.buffered_step.flags = 0; - step_generator_state.current_distance = xyze_long_t { -#ifdef COREXY - LROUND((float(move.start_pos.x) + float(move.start_pos.y)) * Planner::settings.axis_steps_per_mm[X_AXIS]), - LROUND((float(move.start_pos.x) - float(move.start_pos.y)) * Planner::settings.axis_steps_per_mm[Y_AXIS]), -#else - LROUND(float(move.start_pos.x) * Planner::settings.axis_steps_per_mm[X_AXIS]), - LROUND(float(move.start_pos.y) * Planner::settings.axis_steps_per_mm[Y_AXIS]), -#endif - LROUND(float(move.start_pos.z) * Planner::settings.axis_steps_per_mm[Z_AXIS]), - LROUND(float(move.start_pos.e) * Planner::settings.axis_steps_per_mm[E_AXIS]) - }; + step_generator_state.current_distance = stepper.count_position_from_startup; + step_generator_state.current_distance.e = 0; step_generator_state.left_insert_start_of_move_segment = 0; // Reset step events and index @@ -1353,7 +1375,7 @@ void PreciseStepping::reset_queues() { #if HAS_PHASE_STEPPING() phase_stepping::stop_immediately(); #endif - reset_from_halt(false); + reset_from_halt(); // at this point the planner might still have queued extra moves, flush them planner.clear_block_buffer(); diff --git a/lib/Marlin/Marlin/src/feature/precise_stepping/precise_stepping.hpp b/lib/Marlin/Marlin/src/feature/precise_stepping/precise_stepping.hpp index 91803e58d6..f7cb52c21a 100644 --- a/lib/Marlin/Marlin/src/feature/precise_stepping/precise_stepping.hpp +++ b/lib/Marlin/Marlin/src/feature/precise_stepping/precise_stepping.hpp @@ -38,6 +38,12 @@ enum PreciseSteppingFlag : PreciseSteppingFlag_t { PRECISE_STEPPING_FLAG_RESET_POSITION_Y = _BV(1), PRECISE_STEPPING_FLAG_RESET_POSITION_Z = _BV(2), PRECISE_STEPPING_FLAG_RESET_POSITION_E = _BV(3), + + // Indicating logical axis usage until reset + PRECISE_STEPPING_FLAG_X_USED = _BV(8), + PRECISE_STEPPING_FLAG_Y_USED = _BV(9), + PRECISE_STEPPING_FLAG_Z_USED = _BV(10), + PRECISE_STEPPING_FLAG_E_USED = _BV(11), }; // Ensure XYZE bits are always adjacent and ordered. @@ -51,6 +57,11 @@ static_assert(MoveFlag::MOVE_FLAG_RESET_POSITION_Y == (PreciseSteppingFlag::PREC static_assert(MoveFlag::MOVE_FLAG_RESET_POSITION_Z == (PreciseSteppingFlag::PRECISE_STEPPING_FLAG_RESET_POSITION_Z << MOVE_FLAG_RESET_POSITION_SHIFT)); static_assert(MoveFlag::MOVE_FLAG_RESET_POSITION_E == (PreciseSteppingFlag::PRECISE_STEPPING_FLAG_RESET_POSITION_E << MOVE_FLAG_RESET_POSITION_SHIFT)); +static_assert(MoveFlag::MOVE_FLAG_X_ACTIVE == (MoveFlag)PreciseSteppingFlag::PRECISE_STEPPING_FLAG_X_USED); +static_assert(MoveFlag::MOVE_FLAG_Y_ACTIVE == (MoveFlag)PreciseSteppingFlag::PRECISE_STEPPING_FLAG_Y_USED); +static_assert(MoveFlag::MOVE_FLAG_Z_ACTIVE == (MoveFlag)PreciseSteppingFlag::PRECISE_STEPPING_FLAG_Z_USED); +static_assert(MoveFlag::MOVE_FLAG_E_ACTIVE == (MoveFlag)PreciseSteppingFlag::PRECISE_STEPPING_FLAG_E_USED); + class PreciseStepping { public: @@ -82,9 +93,10 @@ class PreciseStepping { // ordering of step events. static double max_lookback_time; - static double total_print_time; - static xyze_double_t total_start_pos; - static xyze_long_t total_start_pos_msteps; + static xyze_double_t initial_start_pos; // Initial absolute position (mm, cartesian) + static double total_print_time; // Cumulative time since beginning of motion (s) + static xyze_double_t total_start_pos; // Current absolute position (mm, cartesian) + static xyze_long_t total_start_pos_msteps; // Current absolute position in mini-steps (msteps, cartesian) // Flags that affect the whole precise stepping. Those flags are reset when all queues are empty. // For now, used only for resetting the positions of axes. diff --git a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_bootloader_result.h b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_bootloader_result.h new file mode 100644 index 0000000000..0bcf38377e --- /dev/null +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_bootloader_result.h @@ -0,0 +1,18 @@ +#pragma once + +enum class MMU2BootloaderResult { + /// Bootloader was not detected + not_detected, + + /// Bootloader detected, firmware up to date + fw_up_to_date, + + /// A new firmware was successfully flashed + fw_updated, + + /// Error during firmware flashing + flashing_error, + + /// Bootloader detected, but had a communication error + comm_error, +}; diff --git a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_config.h b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_config.h index a77d3bea77..f6623df46b 100644 --- a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_config.h +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_config.h @@ -62,7 +62,7 @@ static constexpr float MMU2_VERIFY_LOAD_TO_NOZZLE_FEED_RATE = 50.F; #define MMU2_LOAD_TO_NOZZLE_SEQUENCE \ { \ { MMU2_EXTRUDER_HEATBREAK_LENGTH, MMU2_LOAD_TO_NOZZLE_FEED_RATE }, \ - { MMU2_EXTRUDER_NOZZLE_LENGTH, 5.F } \ + { MMU2_EXTRUDER_NOZZLE_LENGTH + 40, 5.F } \ } #else static constexpr float MMU2_EXTRUDER_HEATBREAK_LENGTH = 67.F; 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..e74188d242 100644 --- a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.cpp @@ -26,6 +26,8 @@ #endif #include "strlen_cx.h" +#include "../../../../src/mmu2/mmu2_bootloader.hpp" + #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 @@ -153,14 +155,25 @@ void MMU2::Start() { mmu2Serial.flush(); // make sure the UART buffer is clear before starting communication extruder = MMU2_NO_TOOL; - state = xState::Connecting; // start the communication - logic.Start(); logic.ResetRetryAttempts(); logic.ResetCommunicationTimeoutAttempts(); + + #if MMU_USE_BOOTLOADER() + state = xState::Bootloader; + bootloader = std::make_unique(mmu2Serial); + bootloader->start(); + + #else + state = xState::Connecting; + logic.Start(); + + #endif } +MMU2::~MMU2() {} + void MMU2::Stop() { StopKeepPowered(); PowerOff(); @@ -169,7 +182,7 @@ void MMU2::Stop() { void MMU2::StopKeepPowered() { state = xState::Stopped; logic.Stop(); - mmu2Serial.close(); + /* mmu2Serial.close(); closing serial comm bricks "Tmr Svc" thread during MMU reflash on MMU_FW_UPDATE_NEEDED screen (low percentage reproducibility) */ // This should reset the error reporter to no error ReportProgressHook(ProgressData(CommandInProgress::Reset)); @@ -259,6 +272,7 @@ bool MMU2::ReadRegister(uint8_t address) { enum MK4Register : uint8_t { TryLoadVsEStall = 0x80, // 0 tryload, 1 estall NominalEPosFSOff = 0x81, // 14mm + FailNextLoadToExtr = 0x82, // write "1" to fail the next load to extr operation }; bool __attribute__((noinline)) MMU2::WriteRegister(uint8_t address, uint16_t data) { @@ -281,6 +295,9 @@ bool __attribute__((noinline)) MMU2::WriteRegister(uint8_t address, uint16_t dat case MK4Register::NominalEPosFSOff: nominalEMotorFSOffReg = data; // raw millimeters return true; // not an MMU register + case MK4Register::FailNextLoadToExtr: + failNextLoadToExtr = data; + break; default: break; // do not intercept any other register writes } @@ -301,14 +318,30 @@ void MMU2::mmu_loop() { return; } avoidRecursion = true; - mmu_loop_inner(true); - avoidRecursion = false; } void __attribute__((noinline)) MMU2::mmu_loop_inner(bool reportErrors) { - logicStepLastStatus = LogicStep(reportErrors); // it looks like the mmu_loop doesn't need to be a blocking call + mmu2Serial.check_recovery(); + + #if MMU_USE_BOOTLOADER() + if (state == xState::Bootloader) { + bootloader->loop(); + + if (!bootloader->is_active()) { + bootloader_result_ = bootloader->result(); + bootloader.reset(); + state = xState::Connecting; + logic.Start(); + } + + } else + #endif + { + logicStepLastStatus = LogicStep(reportErrors); // it looks like the mmu_loop doesn't need to be a blocking call + } + CheckErrorScreenUserInput(); } @@ -339,6 +372,7 @@ bool MMU2::WaitForMMUReady() { case xState::Stopped: return false; case xState::Connecting: + case xState::Bootloader: // shall we wait until the MMU reconnects? // fire-up a fsm_dlg and show "MMU not responding"? default: @@ -362,6 +396,14 @@ bool MMU2::RetryIfPossible(ErrorCode ec) { return false; } +bool MMU2::CheckFailLoadToExtr(bool b) { + if (failNextLoadToExtr > 0) { + --failNextLoadToExtr; + return false; + } + return b; +} + #ifdef USE_TRY_LOAD bool MMU2::TryLoad() { // MMU has finished its load, push the filament further by some defined constant length @@ -407,7 +449,7 @@ bool MMU2::TryLoad() { } } tlur.DumpToSerial(); - return filament_inserted; + return CheckFailLoadToExtr(filament_inserted); } #else // not USE_TRY_LOAD bool MMU2::MeasureEStallAtDifferentSpeeds() { @@ -481,7 +523,7 @@ bool MMU2::FeedWithEStallDetection() { return false; // power panic or a similar issue happened, bail out fast } } - return true; + return CheckFailLoadToExtr(true); } #endif // USE_TRY_LOAD @@ -548,7 +590,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. @@ -586,6 +628,7 @@ void MMU2::ToolChangeCommon(uint8_t slot) { // @@TODO SpoolJoin::spooljoin.setSlot(slot); ++toolchange_counter; + IncrementMMUChanges(); } bool MMU2::tool_change(uint8_t slot) { @@ -720,7 +763,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 +783,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 +867,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(); diff --git a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.h b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.h index 8951378182..8c077f3cda 100644 --- a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.h +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_mk4.h @@ -5,6 +5,7 @@ #include "mmu2_marlin.h" #include "mmu2_reporting.h" #include "mmu2_command_guard.h" +#include "mmu2_bootloader_result.h" #ifdef __AVR__ #include "mmu2_protocol_logic.h" @@ -13,10 +14,17 @@ typedef float feedRate_t; #else #include "protocol_logic.h" #include + #include #endif struct E_Step; +#ifdef UNITTEST + #define MMU_USE_BOOTLOADER() 0 +#else + #define MMU_USE_BOOTLOADER() 1 +#endif + namespace MMU2 { // general MMU setup for MK3 @@ -28,12 +36,15 @@ struct Version { uint8_t major, minor, build; }; +class MMU2BootloaderManager; + /// Top-level interface between Logic and Marlin. /// Intentionally named MMU2 to be (almost) a drop-in replacement for the previous implementation. /// Most of the public methods share the original naming convention as well. class MMU2 { public: MMU2(); + ~MMU2(); /// Powers ON the MMU, then initializes the UART and protocol logic void Start(); @@ -75,6 +86,11 @@ class MMU2 { /// Power on the MMU void PowerOn(); + /// Returns result of the last MMU bootloader run + inline MMU2BootloaderResult bootloader_result() const { + return bootloader_result_; + } + /// Read from a MMU register (See gcode M707) /// @param address Address of register in hexidecimal /// @returns true upon success @@ -362,6 +378,12 @@ class MMU2 { void CutFilamentInner(uint8_t slot); ProtocolLogic logic; ///< implementation of the protocol logic layer + +#if MMU_USE_BOOTLOADER() + std::unique_ptr bootloader; ///< Bootloader manager, handles firmware updates and such +#endif + std::atomic bootloader_result_ = MMU2BootloaderResult::not_detected; + 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 @@ -396,6 +418,12 @@ class MMU2 { float nominalEMotorFSOffReg = nominalEMotorFSOff; /// A record of the last E-motor position when fsensor turned off while unloading float unloadEPosOnFSOff = nominalEMotorFSOff; + /// register - fail the next n loads to extr intentionally + /// write a nonzero value into this register, it will screw up the load returned value (even if it went perfectly smooth on the machine) + /// the register is decremented after each load to extr. automatically + uint8_t failNextLoadToExtr = 0; + + bool CheckFailLoadToExtr(bool b); }; /// following Marlin's way of doing stuff - one and only instance of MMU implementation in the code base 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/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_serial.h b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_serial.h index f00f437b21..ce91a4ee55 100644 --- a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_serial.h +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_serial.h @@ -14,6 +14,13 @@ class MMU2Serial { int read(); void flush(); size_t write(const uint8_t *buffer, size_t size); + + /// Checks if serial recovery is necessary and potentially performs it + void check_recovery(); + +private: + uint32_t baud_rate = 0; + uint32_t recovery_start_ms = 0; }; extern MMU2Serial mmu2Serial; diff --git a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_state.h b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_state.h index 46026cded4..d5d81480bb 100644 --- a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_state.h +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_state.h @@ -13,9 +13,13 @@ namespace MMU2 { /// When the printer's FW starts, the MMU mode is either Stopped or NotResponding (based on user's preference). /// When the MMU successfully establishes communication, the state changes to Active. enum class xState : uint_fast8_t { + /// The user doesn't want the printer to work with the MMU. The MMU itself is not powered and does not work at all. + /// !!! Must be 0 !!! marlin_vars.mmu2_state is set to 0 if not active + Stopped, + Active, ///< MMU has been detected, connected, communicates and is ready to be worked with. Connecting, ///< MMU is connected but it doesn't communicate (yet). The user wants the MMU, but it is not ready to be worked with. - Stopped ///< The user doesn't want the printer to work with the MMU. The MMU itself is not powered and does not work at all. + Bootloader, ///< Trying to communicate with the MMU bootloader }; } // namespace MMU2 diff --git a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_supported_version.h b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_supported_version.h index 9ed7d4278b..140d01a251 100644 --- a/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_supported_version.h +++ b/lib/Marlin/Marlin/src/feature/prusa/MMU2/mmu2_supported_version.h @@ -5,6 +5,6 @@ namespace MMU2 { static constexpr uint8_t mmuVersionMajor = 3; static constexpr uint8_t mmuVersionMinor = 0; -static constexpr uint8_t mmuVersionPatch = 2; +static constexpr uint8_t mmuVersionPatch = 3; } // namespace MMU2 diff --git a/lib/Marlin/Marlin/src/gcode/calibrate/G28.cpp b/lib/Marlin/Marlin/src/gcode/calibrate/G28.cpp index 28e6c7739f..195bfa38f0 100644 --- a/lib/Marlin/Marlin/src/gcode/calibrate/G28.cpp +++ b/lib/Marlin/Marlin/src/gcode/calibrate/G28.cpp @@ -283,14 +283,15 @@ static inline void MINDA_BROKEN_CABLE_DETECTION__END() {} Motion_Parameters motion_parameters; motion_parameters.save(); - planner.settings.max_acceleration_mm_per_s2[X_AXIS] = XY_HOMING_ACCELERATION; - planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = XY_HOMING_ACCELERATION; - planner.settings.travel_acceleration = XY_HOMING_ACCELERATION; + auto s = planner.user_settings; + s.max_acceleration_mm_per_s2[X_AXIS] = XY_HOMING_ACCELERATION; + s.max_acceleration_mm_per_s2[Y_AXIS] = XY_HOMING_ACCELERATION; + s.travel_acceleration = XY_HOMING_ACCELERATION; #if HAS_CLASSIC_JERK - planner.max_jerk.set(XY_HOMING_JERK, XY_HOMING_JERK); + s.max_jerk.set(XY_HOMING_JERK, XY_HOMING_JERK); #endif - - planner.refresh_acceleration_rates(); + planner.apply_settings(s); + return motion_parameters; } @@ -838,6 +839,8 @@ bool GcodeSuite::G28_no_parser(bool always_home_all, bool O, float R, bool S, bo sync_plan_position(); + // clear any step fraction: we're at home + PreciseStepping::reset_from_halt(false); #endif /** diff --git a/lib/Marlin/Marlin/src/gcode/config/M200-M205.cpp b/lib/Marlin/Marlin/src/gcode/config/M200-M205.cpp index 857ca16f73..d54df72742 100644 --- a/lib/Marlin/Marlin/src/gcode/config/M200-M205.cpp +++ b/lib/Marlin/Marlin/src/gcode/config/M200-M205.cpp @@ -108,12 +108,15 @@ void GcodeSuite::M204() { SERIAL_ECHOLNPAIR(" T", planner.settings.travel_acceleration); } else { + auto s = planner.user_settings; //planner.synchronize(); // 'S' for legacy compatibility. Should NOT BE USED for new development - if (parser.seenval('S')) planner.settings.travel_acceleration = planner.settings.acceleration = parser.value_linear_units(); - if (parser.seenval('P')) planner.settings.acceleration = parser.value_linear_units(); - if (parser.seenval('R')) planner.settings.retract_acceleration = parser.value_linear_units(); - if (parser.seenval('T')) planner.settings.travel_acceleration = parser.value_linear_units(); + if (parser.seenval('S')) s.travel_acceleration = s.acceleration = parser.value_linear_units(); + if (parser.seenval('P')) s.acceleration = parser.value_linear_units(); + if (parser.seenval('R')) s.retract_acceleration = parser.value_linear_units(); + if (parser.seenval('T')) s.travel_acceleration = parser.value_linear_units(); + + planner.apply_settings(s); } } @@ -143,9 +146,15 @@ void GcodeSuite::M205() { if (!parser.seen("BST" J_PARAM XYZE_PARAM)) return; //planner.synchronize(); - if (parser.seen('B')) planner.settings.min_segment_time_us = parser.value_ulong(); - if (parser.seen('S')) planner.settings.min_feedrate_mm_s = parser.value_linear_units(); - if (parser.seen('T')) planner.settings.min_travel_feedrate_mm_s = parser.value_linear_units(); + { + auto s = planner.user_settings; + + if (parser.seen('B')) s.min_segment_time_us = parser.value_ulong(); + if (parser.seen('S')) s.min_feedrate_mm_s = parser.value_linear_units(); + if (parser.seen('T')) s.min_travel_feedrate_mm_s = parser.value_linear_units(); + + planner.apply_settings(s); + } #if DISABLED(CLASSIC_JERK) if (parser.seen('J')) { const float junc_dev = parser.value_linear_units(); @@ -165,7 +174,7 @@ void GcodeSuite::M205() { if (parser.seen('Z')) { planner.set_max_jerk(Z_AXIS, parser.value_linear_units()); #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING) - if (planner.max_jerk.z <= 0.1f) + if (planner.settings.max_jerk.z <= 0.1f) SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses."); #endif } diff --git a/lib/Marlin/Marlin/src/gcode/config/M92.cpp b/lib/Marlin/Marlin/src/gcode/config/M92.cpp index aa8cf2ccb9..dc15354b76 100644 --- a/lib/Marlin/Marlin/src/gcode/config/M92.cpp +++ b/lib/Marlin/Marlin/src/gcode/config/M92.cpp @@ -74,26 +74,32 @@ void GcodeSuite::M92() { #endif )) return report_M92(true, target_extruder); - LOOP_XYZE(i) { - if (parser.seenval(axis_codes[i])) { - if (i == E_AXIS) { - const float value = parser.value_per_axis_units((AxisEnum)(E_AXIS_N(target_extruder))); - if (value < 20) { - float factor = planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] / value; // increase e constants if M92 E14 is given for netfab. - #if HAS_CLASSIC_E_JERK - planner.max_jerk.e *= factor; - #endif - planner.settings.max_feedrate_mm_s[E_AXIS_N(target_extruder)] *= factor; - planner.max_acceleration_msteps_per_s2[E_AXIS_N(target_extruder)] *= factor; + { + auto s = planner.user_settings; + + LOOP_XYZE(i) { + if (parser.seenval(axis_codes[i])) { + if (i == E_AXIS) { + const float value = parser.value_per_axis_units((AxisEnum)(E_AXIS_N(target_extruder))); + if (value < 20) { + float factor = planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] / value; // increase e constants if M92 E14 is given for netfab. + #if HAS_CLASSIC_E_JERK + s.max_jerk.e *= factor; + #endif + s.max_feedrate_mm_s[E_AXIS_N(target_extruder)] *= factor; + planner.max_acceleration_msteps_per_s2[E_AXIS_N(target_extruder)] *= factor; + } + s.axis_steps_per_mm[E_AXIS_N(target_extruder)] = value; + s.axis_msteps_per_mm[E_AXIS_N(target_extruder)] = value * PLANNER_STEPS_MULTIPLIER; + } + else { + s.axis_steps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i); + s.axis_msteps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i) * PLANNER_STEPS_MULTIPLIER; } - planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] = value; - planner.settings.axis_msteps_per_mm[E_AXIS_N(target_extruder)] = value * PLANNER_STEPS_MULTIPLIER; - } - else { - planner.settings.axis_steps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i); - planner.settings.axis_msteps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i) * PLANNER_STEPS_MULTIPLIER; } } + + planner.apply_settings(s); } planner.refresh_positioning(); diff --git a/lib/Marlin/Marlin/src/gcode/feature/phase_stepping/M970-M977.cpp b/lib/Marlin/Marlin/src/gcode/feature/phase_stepping/M970-M977.cpp index fb1269986c..9783194539 100644 --- a/lib/Marlin/Marlin/src/gcode/feature/phase_stepping/M970-M977.cpp +++ b/lib/Marlin/Marlin/src/gcode/feature/phase_stepping/M970-M977.cpp @@ -403,12 +403,14 @@ void GcodeSuite::M976() { } } -class GCodeCalibrationReporter : public phase_stepping::CalibrationReporterBase { +class CalibrateAxisHooks final : public phase_stepping::CalibrateAxisHooks { std::vector> _calibration_results; + int _calibration_phases_count = -1; + int _current_calibration_phase = 0; public: void set_calibration_phases_count(int phases) override { - phase_stepping::CalibrationReporterBase::set_calibration_phases_count(phases); + _calibration_phases_count = phases; _calibration_results.resize(phases); } @@ -416,6 +418,10 @@ class GCodeCalibrationReporter : public phase_stepping::CalibrationReporterBase SERIAL_ECHOLN("Moving to calibration position"); } + virtual void on_enter_calibration_phase(int phase) override { + _current_calibration_phase = phase; + } + void on_calibration_phase_progress(int progress) override { SERIAL_ECHO("Phase "); SERIAL_ECHO(_current_calibration_phase + 1); @@ -456,15 +462,12 @@ class GCodeCalibrationReporter : public phase_stepping::CalibrationReporterBase SERIAL_ECHO("%, "); SERIAL_ECHO(100.f * (1.f - p2_b * p4_b)); SERIAL_ECHO("%\n"); - phase_stepping::last_calibration_result = phase_stepping::CalibrationResult::make_known( - phase_stepping::CalibrationResult::Scores { - .p1f = p1_f * p3_f, - .p1b = p1_b * p3_b, - .p2f = p2_f * p4_f, - .p2b = p2_b * p4_b, - }); #endif } + + ContinueOrAbort on_idle() override { + return ContinueOrAbort::Continue; + } }; /** @@ -477,7 +480,6 @@ class GCodeCalibrationReporter : public phase_stepping::CalibrationReporterBase **/ void GcodeSuite::M977() { TEMPORARY_AUTO_REPORT_OFF(suspend_auto_report); - phase_stepping::last_calibration_result = phase_stepping::CalibrationResult::make_error(); bool valid = true; @@ -511,8 +513,8 @@ void GcodeSuite::M977() { ); Planner::synchronize(); - GCodeCalibrationReporter reporter; - auto result = phase_stepping::calibrate_axis(axis, reporter); + CalibrateAxisHooks hooks; + auto result = phase_stepping::calibrate_axis(axis, hooks); if (!result.has_value()) { print_error("Calibration failed"); @@ -533,7 +535,5 @@ void GcodeSuite::M977() { SERIAL_PRINT(backward[i].pha, SERIAL_DECIMALS); SERIAL_ECHO("\n"); } - - phase_stepping::save_correction_to_file(phase_stepping::axis_states[axis]->forward_current, phase_stepping::get_correction_file_path(axis, phase_stepping::CorrectionType::forward)); - phase_stepping::save_correction_to_file(phase_stepping::axis_states[axis]->backward_current, phase_stepping::get_correction_file_path(axis, phase_stepping::CorrectionType::backward)); + phase_stepping::save_to_persistent_storage_without_enabling(axis); } diff --git a/lib/Marlin/Marlin/src/gcode/gcode.h b/lib/Marlin/Marlin/src/gcode/gcode.h index 023108e576..efea7244c7 100644 --- a/lib/Marlin/Marlin/src/gcode/gcode.h +++ b/lib/Marlin/Marlin/src/gcode/gcode.h @@ -406,6 +406,8 @@ class GcodeSuite { // while allowing background processing. It does not synchronize. static void dwell(millis_t time, bool no_stepper_sleep=false); + static void M104(); + /** * @brief Home. * @param * see GcodeSuite::G28() for details @@ -631,7 +633,6 @@ class GcodeSuite { #endif #if EXTRUDERS - static void M104(); static void M109(); #endif diff --git a/lib/Marlin/Marlin/src/gcode/lcd/M73_PE.cpp b/lib/Marlin/Marlin/src/gcode/lcd/M73_PE.cpp index 707c519b9a..ce9ffc5a6b 100644 --- a/lib/Marlin/Marlin/src/gcode/lcd/M73_PE.cpp +++ b/lib/Marlin/Marlin/src/gcode/lcd/M73_PE.cpp @@ -6,6 +6,7 @@ #include "M73_PE.h" #include "../Marlin/src/libs/stopwatch.h" +#include "marlin_vars.hpp" extern Stopwatch print_job_timer; ClProgressData oProgressData; @@ -21,20 +22,20 @@ void ClValidityValue::mSetValue(uint32_t nN, uint32_t nNow) { bIsUsed = true; } -uint32_t ClValidityValue::mGetValue(void) { +uint32_t ClValidityValue::mGetValue(void) const { return (nValue); } -bool ClValidityValue::mIsActual(uint32_t nNow) { +bool ClValidityValue::mIsActual(uint32_t nNow) const { return (mIsActual(nNow, PROGRESS_DATA_VALIDITY_PERIOD)); } -bool ClValidityValue::mIsActual(uint32_t nNow, uint16_t nPeriod) { +bool ClValidityValue::mIsActual(uint32_t nNow, uint16_t nPeriod) const { // return((nTime+nPeriod)>=nNow); return (mIsUsed() && ((nTime + nPeriod) >= nNow)); } -bool ClValidityValue::mIsUsed(void) { +bool ClValidityValue::mIsUsed(void) const { // return(nTime>0); return (bIsUsed); } @@ -59,10 +60,13 @@ void ClValidityValueSec::mFormatSeconds(char *sStr, uint16_t nFeedrate) { } void ClProgressData::mInit(void) { - oPercentDirectControl.mInit(); - oPercentDone.mInit(); - oTime2End.mInit(); - oTime2Pause.mInit(); + const auto mode_specific = [](ModeSpecificData &d) { + d.percent_done.mInit(); + d.time_to_end.mInit(); + d.time_to_pause.mInit(); + }; + mode_specific(standard_mode); + mode_specific(stealth_mode); } #if ENABLED(M73_PRUSA) @@ -77,57 +81,85 @@ void ClProgressData::mInit(void) { * ## Parameters * * - `P` - [percentage] Set percentage value + * - `Q` - [percentage] Set percentage value in stealth mode * - `R` - [minutes] Set time to end / percentage done + * - `S` - [minutes] Set time to end / percentage done in stealth mode * - `C` - [minutes] Set time to pause * (historically also `T`, which is not documented anywhere and we couldn't * track anyone producing it, but the code accepted it previously - probably * a typo, but keeping it for backwards compatibility anyway). + * - `D` - [minutes] Set time to pause in stealth mode */ void GcodeSuite::M73_PE() { - std::optional P = std::nullopt; - std::optional R = std::nullopt; - std::optional C = std::nullopt; + M73_Params p; if (parser.seen('P')) { - P = parser.value_byte(); + p.standard_mode.percentage = parser.value_byte(); } if (parser.seen('R')) { - R = parser.value_ulong() * 60; + p.standard_mode.time_to_end = parser.value_ulong() * 60; + } + if (parser.seen('C')) { + p.standard_mode.time_to_pause = parser.value_ulong() * 60; } if (parser.seen('T')) { - C = parser.value_ulong() * 60; + p.standard_mode.time_to_pause = parser.value_ulong() * 60; } - if (parser.seen('C')) { - C = parser.value_ulong() * 60; + + if (parser.seen('Q')) { + p.stealth_mode.percentage = parser.value_byte(); + } + if (parser.seen('S')) { + p.stealth_mode.time_to_end = parser.value_ulong() * 60; + } + if (parser.seen('D')) { + p.stealth_mode.time_to_pause = parser.value_ulong() * 60; } - M73_PE_no_parser(P, R, C); + M73_PE_no_parser(p); } /** @}*/ -void M73_PE_no_parser(std::optional P, std::optional R, std::optional C) { - uint32_t nTimeNow; - uint8_t nValue; - - // ui.set_progress_time(...); - nTimeNow = print_job_timer.duration(); // !!! [s] - if (P) { - nValue = *P; - if (R) { - oProgressData.oPercentDone.mSetValue((uint32_t)nValue, nTimeNow); - oProgressData.oTime2End.mSetValue(*R, nTimeNow); // [min] -> [s] - } else { - oProgressData.oPercentDirectControl.mSetValue((uint32_t)nValue, nTimeNow); +void M73_PE_no_parser(const M73_Params ¶ms) { + /// [s] + const uint32_t nTimeNow = print_job_timer.duration(); + + const auto mode_specific_update = [&](const M73_Params::ModeSpecificParams &mparams, ClProgressData::ModeSpecificData &mdata) { + if (auto v = mparams.percentage) { + mdata.percent_done.mSetValue((uint32_t)*v, nTimeNow); + } + if (auto v = mparams.time_to_end) { + mdata.time_to_end.mSetValue(*v, nTimeNow); // [min] -> [s] + } + if (auto v = mparams.time_to_pause) { + if (*v == 0) { + // Pause happening now, reset the countdown (there doesn't have to be another until the end). + mdata.time_to_pause.mInit(); + } else { + mdata.time_to_pause.mSetValue(*v, nTimeNow); // [min] -> [s] + } + } + }; + + mode_specific_update(params.standard_mode, oProgressData.standard_mode); + mode_specific_update(params.stealth_mode, oProgressData.stealth_mode); + + // Print progress report. Do not remove as third party tools might depend on this + if (params == M73_Params {}) { + SERIAL_ECHO_START(); + SERIAL_ECHOLNPAIR(" M73 Progress: ", marlin_vars()->sd_percent_done, "%;"); + const uint32_t time_to_end = marlin_vars_t().time_to_end; + if (time_to_end != marlin_server::TIME_TO_END_INVALID) { + SERIAL_ECHOPAIR(" Time left: ", time_to_end / 60, "m;"); + SERIAL_EOL(); } - } - if (C) { - if (*C == 0) { - // Pause happening now, reset the countdown (there doesn't have to be another until the end). - oProgressData.oTime2Pause.mInit(); - } else { - oProgressData.oTime2Pause.mSetValue(*C, nTimeNow); // [min] -> [s] + const uint32_t time_to_pause = oProgressData.mode_specific(marlin_vars()->stealth_mode).time_to_pause.mGetValue(); + if (time_to_pause != marlin_server::TIME_TO_END_INVALID) { + const int print_speed = marlin_vars()->print_speed; + SERIAL_ECHOPAIR(" Change: ", print_speed > 0 ? ((time_to_pause * 100) / print_speed) / 60 : 0, "m;"); + SERIAL_EOL(); } } } diff --git a/lib/Marlin/Marlin/src/gcode/lcd/M73_PE.h b/lib/Marlin/Marlin/src/gcode/lcd/M73_PE.h index 7a6cd77c05..b4d58bc38b 100644 --- a/lib/Marlin/Marlin/src/gcode/lcd/M73_PE.h +++ b/lib/Marlin/Marlin/src/gcode/lcd/M73_PE.h @@ -21,11 +21,11 @@ class ClValidityValue { public: void mSetValue(uint32_t nN, uint32_t nNow); - uint32_t mGetValue(void); + uint32_t mGetValue(void) const; void mInit(void); - bool mIsActual(uint32_t nNow); - bool mIsActual(uint32_t nNow, uint16_t nPeriod); - bool mIsUsed(void); + bool mIsActual(uint32_t nNow) const; + bool mIsActual(uint32_t nNow, uint16_t nPeriod) const; + bool mIsUsed(void) const; // void mFormatSeconds(char *sStr,uint16_t nFeedrate); }; @@ -36,16 +36,39 @@ class ClValidityValueSec : public ClValidityValue { class ClProgressData { public: - ClValidityValue oPercentDirectControl; - ClValidityValue oPercentDone; - ClValidityValueSec oTime2End; - ClValidityValueSec oTime2Pause; + struct ModeSpecificData { + ClValidityValue percent_done; + ClValidityValueSec time_to_end; + ClValidityValueSec time_to_pause; + }; + + ModeSpecificData standard_mode; + ModeSpecificData stealth_mode; -public: void mInit(void); + + ModeSpecificData &mode_specific(bool stealth) { + return stealth ? stealth_mode : standard_mode; + } }; extern ClProgressData oProgressData; -void M73_PE_no_parser(std::optional P = std::nullopt, std::optional R = std::nullopt, std::optional C = std::nullopt); + +struct M73_Params { + struct ModeSpecificParams { + std::optional percentage; + std::optional time_to_end; + std::optional time_to_pause; + + bool operator==(const ModeSpecificParams &) const = default; + }; + + ModeSpecificParams standard_mode; + ModeSpecificParams stealth_mode; + + bool operator==(const M73_Params &) const = default; +}; + +void M73_PE_no_parser(const M73_Params ¶ms); #endif /* SRC_GCODE_LCD_M73_PE_H_ */ diff --git a/lib/Marlin/Marlin/src/lcd/extensible_ui/ui_api.cpp b/lib/Marlin/Marlin/src/lcd/extensible_ui/ui_api.cpp index 8f00592a00..1f975108c1 100644 --- a/lib/Marlin/Marlin/src/lcd/extensible_ui/ui_api.cpp +++ b/lib/Marlin/Marlin/src/lcd/extensible_ui/ui_api.cpp @@ -574,14 +574,18 @@ namespace ExtUI { } void setAxisSteps_per_mm(const float value, const axis_t axis) { - planner.settings.axis_steps_per_mm[axis] = value; - planner.settings.axis_msteps_per_mm[axis] = value * PLANNER_STEPS_MULTIPLIER; + auto s = planner.user_settings; + s.axis_steps_per_mm[axis] = value; + s.axis_msteps_per_mm[axis] = value * PLANNER_STEPS_MULTIPLIER; + planner.apply_settings(s); } void setAxisSteps_per_mm(const float value, const extruder_t extruder) { UNUSED_E(extruder); - planner.settings.axis_steps_per_mm[E_AXIS_N(axis - E0)] = value; - planner.settings.axis_msteps_per_mm[E_AXIS_N(axis - E0)] = value * PLANNER_STEPS_MULTIPLIER; + auto s = planner.user_settings; + s.axis_steps_per_mm[E_AXIS_N(axis - E0)] = value; + s.axis_msteps_per_mm[E_AXIS_N(axis - E0)] = value * PLANNER_STEPS_MULTIPLIER; + planner.apply_settings(s); } feedRate_t getAxisMaxFeedrate_mm_s(const axis_t axis) { @@ -655,11 +659,11 @@ namespace ExtUI { #else float getAxisMaxJerk_mm_s(const axis_t axis) { - return planner.max_jerk[axis]; + return planner.settings.max_jerk[axis]; } float getAxisMaxJerk_mm_s(const extruder_t) { - return planner.max_jerk.e; + return planner.settings.max_jerk.e; } void setAxisMaxJerk_mm_s(const float value, const axis_t axis) { @@ -678,11 +682,31 @@ namespace ExtUI { float getRetractAcceleration_mm_s2() { return planner.settings.retract_acceleration; } float getTravelAcceleration_mm_s2() { return planner.settings.travel_acceleration; } void setFeedrate_mm_s(const feedRate_t fr) { feedrate_mm_s = fr; } - void setMinFeedrate_mm_s(const feedRate_t fr) { planner.settings.min_feedrate_mm_s = fr; } - void setMinTravelFeedrate_mm_s(const feedRate_t fr) { planner.settings.min_travel_feedrate_mm_s = fr; } - void setPrintingAcceleration_mm_s2(const float acc) { planner.settings.acceleration = acc; } - void setRetractAcceleration_mm_s2(const float acc) { planner.settings.retract_acceleration = acc; } - void setTravelAcceleration_mm_s2(const float acc) { planner.settings.travel_acceleration = acc; } + void setMinFeedrate_mm_s(const feedRate_t fr) { + auto s = planner.user_settings; + s.min_feedrate_mm_s = fr; + planner.apply_settings(s); + } + void setMinTravelFeedrate_mm_s(const feedRate_t fr) { + auto s = planner.user_settings; + s.min_travel_feedrate_mm_s = fr; + planner.apply_settings(s); + } + void setPrintingAcceleration_mm_s2(const float acc) { + auto s = planner.user_settings; + s.acceleration = acc; + planner.apply_settings(s); + } + void setRetractAcceleration_mm_s2(const float acc) { + auto s = planner.user_settings; + s.retract_acceleration = acc; + planner.apply_settings(s); + } + void setTravelAcceleration_mm_s2(const float acc) { + auto s = planner.user_settings; + s.travel_acceleration = acc; + planner.apply_settings(s); + } #if ENABLED(BABYSTEPPING) bool babystepAxis_steps(const int16_t steps, const axis_t axis) { diff --git a/lib/Marlin/Marlin/src/module/configuration_store.cpp b/lib/Marlin/Marlin/src/module/configuration_store.cpp index e27887dac5..9707783c1c 100644 --- a/lib/Marlin/Marlin/src/module/configuration_store.cpp +++ b/lib/Marlin/Marlin/src/module/configuration_store.cpp @@ -2223,19 +2223,21 @@ void MarlinSettings::postprocess() { * Resets motion parameters only (speed, accel., etc.) */ void MarlinSettings::reset_motion() { + auto s = planner.user_settings; + LOOP_XYZE_N(i) { - planner.settings.max_acceleration_mm_per_s2[i] = pgm_read_dword(&_DMA[ALIM(i, _DMA)]); - planner.settings.axis_steps_per_mm[i] = get_steps_per_unit(i); - planner.settings.axis_msteps_per_mm[i] = get_steps_per_unit(i) * PLANNER_STEPS_MULTIPLIER; - planner.settings.max_feedrate_mm_s[i] = pgm_read_float(&_DMF[ALIM(i, _DMF)]); + s.max_acceleration_mm_per_s2[i] = pgm_read_dword(&_DMA[ALIM(i, _DMA)]); + s.axis_steps_per_mm[i] = get_steps_per_unit(i); + s.axis_msteps_per_mm[i] = get_steps_per_unit(i) * PLANNER_STEPS_MULTIPLIER; + s.max_feedrate_mm_s[i] = pgm_read_float(&_DMF[ALIM(i, _DMF)]); } - planner.settings.min_segment_time_us = DEFAULT_MINSEGMENTTIME; - planner.settings.acceleration = DEFAULT_ACCELERATION; - planner.settings.retract_acceleration = DEFAULT_RETRACT_ACCELERATION; - planner.settings.travel_acceleration = DEFAULT_TRAVEL_ACCELERATION; - planner.settings.min_feedrate_mm_s = feedRate_t(DEFAULT_MINIMUMFEEDRATE); - planner.settings.min_travel_feedrate_mm_s = feedRate_t(DEFAULT_MINTRAVELFEEDRATE); + s.min_segment_time_us = DEFAULT_MINSEGMENTTIME; + s.acceleration = DEFAULT_ACCELERATION; + s.retract_acceleration = DEFAULT_RETRACT_ACCELERATION; + s.travel_acceleration = DEFAULT_TRAVEL_ACCELERATION; + s.min_feedrate_mm_s = feedRate_t(DEFAULT_MINIMUMFEEDRATE); + s.min_travel_feedrate_mm_s = feedRate_t(DEFAULT_MINTRAVELFEEDRATE); #if HAS_CLASSIC_JERK #ifndef DEFAULT_XJERK @@ -2247,15 +2249,17 @@ void MarlinSettings::reset_motion() { #ifndef DEFAULT_ZJERK #define DEFAULT_ZJERK 0 #endif - planner.max_jerk.set(DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK); + s.max_jerk.set(DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK); #if HAS_CLASSIC_E_JERK - planner.max_jerk.e = DEFAULT_EJERK; + s.max_jerk.e = DEFAULT_EJERK; #endif #endif #if DISABLED(CLASSIC_JERK) planner.junction_deviation_mm = float(JUNCTION_DEVIATION_MM); #endif + + planner.apply_settings(s); } /** @@ -2793,11 +2797,11 @@ void MarlinSettings::reset() { , " J", LINEAR_UNIT(planner.junction_deviation_mm) #endif #if HAS_CLASSIC_JERK - , " X", LINEAR_UNIT(planner.max_jerk.x) - , " Y", LINEAR_UNIT(planner.max_jerk.y) - , " Z", LINEAR_UNIT(planner.max_jerk.z) + , " X", LINEAR_UNIT(planner.settings.max_jerk.x) + , " Y", LINEAR_UNIT(planner.settings.max_jerk.y) + , " Z", LINEAR_UNIT(planner.settings.max_jerk.z) #if HAS_CLASSIC_E_JERK - , " E", LINEAR_UNIT(planner.max_jerk.e) + , " E", LINEAR_UNIT(planner.settings.max_jerk.e) #endif #endif ); diff --git a/lib/Marlin/Marlin/src/module/planner.cpp b/lib/Marlin/Marlin/src/module/planner.cpp index bd49185dda..b2ba91eddf 100644 --- a/lib/Marlin/Marlin/src/module/planner.cpp +++ b/lib/Marlin/Marlin/src/module/planner.cpp @@ -127,7 +127,62 @@ bool Planner::draining_buffer; // A flag to indicate that that buffer is being emptied intentionally bool Planner::emptying_buffer; -planner_settings_t Planner::settings; // Initialized by settings.load() +planner_settings_t Planner::working_settings_; +user_planner_settings_t Planner::user_settings_; + +const planner_settings_t &Planner::settings = working_settings_; +const user_planner_settings_t &Planner::user_settings = user_settings_; + +bool Planner::stealth_mode_ = false; + +void Planner::apply_settings(const user_planner_settings_t &settings) { + static constexpr planner_settings_t standard_limits = { + .max_acceleration_mm_per_s2 = HWLIMIT_NORMAL_MAX_ACCELERATION, + .max_feedrate_mm_s = HWLIMIT_NORMAL_MAX_FEEDRATE, + .acceleration = HWLIMIT_NORMAL_ACCELERATION, + .retract_acceleration = HWLIMIT_NORMAL_RETRACT_ACCELERATION, + .travel_acceleration = HWLIMIT_NORMAL_TRAVEL_ACCELERATION, + }; + static constexpr planner_settings_t stealth_limits = { + .max_acceleration_mm_per_s2 = HWLIMIT_STEALTH_MAX_ACCELERATION, + .max_feedrate_mm_s = HWLIMIT_STEALTH_MAX_FEEDRATE, + .acceleration = HWLIMIT_STEALTH_ACCELERATION, + .retract_acceleration = HWLIMIT_STEALTH_RETRACT_ACCELERATION, + .travel_acceleration = HWLIMIT_STEALTH_TRAVEL_ACCELERATION, + }; + const auto &limits = stealth_mode_ ? stealth_limits : standard_limits; + + user_settings_ = settings; + working_settings_ = settings; + + const auto apply_limit = [&](T planner_settings_t::*member) { + auto &value = working_settings_.*member; + const auto &limit = limits.*member; + + if constexpr(std::is_array_v) { + for(size_t i = 0; i maxj) { // cs > mj : New current speed too fast? if (limited) { // limited already? const float mjerk = block->nominal_speed * maxj; // ns*mj @@ -1902,8 +1950,8 @@ bool Planner::_populate_block(block_t * const block, : // v_exit <= v_entry coasting axis reversal ( (v_entry < 0 || v_exit > 0) ? (v_entry - v_exit) : _MAX(-v_exit, v_entry) ); - if (jerk > max_jerk[axis]) { - v_factor *= max_jerk[axis] / jerk; + if (jerk > settings.max_jerk[axis]) { + v_factor *= settings.max_jerk[axis] / jerk; ++limited; } } @@ -2301,10 +2349,10 @@ void Planner::set_max_acceleration(const uint8_t axis, float targetValue) { #endif limit_and_warn(targetValue, axis, PSTR("Acceleration"), max_acc_edit_scaled); #endif - settings.max_acceleration_mm_per_s2[axis] = targetValue; - // Update mini-steps per s2 to agree with the units per s2 (since they are used in the planner) - refresh_acceleration_rates(); + auto new_settings = user_settings; + new_settings.max_acceleration_mm_per_s2[axis] = targetValue; + apply_settings(new_settings); } void Planner::set_max_feedrate(const uint8_t axis, float targetValue) { @@ -2318,7 +2366,10 @@ void Planner::set_max_feedrate(const uint8_t axis, float targetValue) { #endif limit_and_warn(targetValue, axis, PSTR("Feedrate"), max_fr_edit_scaled); #endif - settings.max_feedrate_mm_s[axis] = targetValue; + + auto new_settings = user_settings; + new_settings.max_feedrate_mm_s[axis] = targetValue; + apply_settings(new_settings); } void Planner::set_max_jerk(const AxisEnum axis, float targetValue) { @@ -2334,7 +2385,9 @@ void Planner::set_max_jerk(const AxisEnum axis, float targetValue) { ; limit_and_warn(targetValue, axis, PSTR("Jerk"), max_jerk_edit); #endif - max_jerk[axis] = targetValue; + auto s = user_settings; + s.max_jerk[axis] = targetValue; + apply_settings(s); #else UNUSED(axis); UNUSED(targetValue); #endif @@ -2372,31 +2425,33 @@ void Motion_Parameters::save() { mp.junction_deviation_mm = planner.junction_deviation_mm; #endif #if HAS_CLASSIC_JERK - mp.max_jerk = planner.max_jerk; + mp.max_jerk = planner.settings.max_jerk; #endif } void Motion_Parameters::load() const { + auto s = planner.user_settings; + for (int i = 0; i < XYZE_N; ++i) { - planner.settings.max_acceleration_mm_per_s2[i] = mp.max_acceleration_mm_per_s2[i]; - planner.settings.max_feedrate_mm_s[i] = mp.max_feedrate_mm_s[i]; + s.max_acceleration_mm_per_s2[i] = mp.max_acceleration_mm_per_s2[i]; + s.max_feedrate_mm_s[i] = mp.max_feedrate_mm_s[i]; } - planner.settings.min_segment_time_us = mp.min_segment_time_us; - planner.settings.acceleration = mp.acceleration; - planner.settings.retract_acceleration = mp.retract_acceleration; - planner.settings.travel_acceleration = mp.travel_acceleration; - planner.settings.min_feedrate_mm_s = mp.min_feedrate_mm_s; - planner.settings.min_travel_feedrate_mm_s = mp.min_travel_feedrate_mm_s; + s.min_segment_time_us = mp.min_segment_time_us; + s.acceleration = mp.acceleration; + s.retract_acceleration = mp.retract_acceleration; + s.travel_acceleration = mp.travel_acceleration; + s.min_feedrate_mm_s = mp.min_feedrate_mm_s; + s.min_travel_feedrate_mm_s = mp.min_travel_feedrate_mm_s; #if DISABLED(CLASSIC_JERK) planner.junction_deviation_mm = mp.junction_deviation_mm; #endif #if HAS_CLASSIC_JERK - planner.max_jerk = mp.max_jerk; + s.max_jerk = mp.max_jerk; #endif - planner.refresh_acceleration_rates(); + planner.apply_settings(s); } void Motion_Parameters::reset() { diff --git a/lib/Marlin/Marlin/src/module/planner.h b/lib/Marlin/Marlin/src/module/planner.h index e73f3071b2..a47659d970 100644 --- a/lib/Marlin/Marlin/src/module/planner.h +++ b/lib/Marlin/Marlin/src/module/planner.h @@ -175,8 +175,19 @@ typedef struct { travel_acceleration; // (mm/s^2) M204 T - Travel acceleration. DEFAULT ACCELERATION for all NON printing moves. feedRate_t min_feedrate_mm_s, // (mm/s) M205 S - Minimum linear feedrate min_travel_feedrate_mm_s; // (mm/s) M205 T - Minimum travel feedrate + + #if HAS_CLASSIC_JERK + #if HAS_LINEAR_E_JERK + xyz_pos_t max_jerk; // (mm/s^2) M205 XYZ - The largest speed change requiring no acceleration. + #else + xyze_pos_t max_jerk; // (mm/s^2) M205 XYZE - The largest speed change requiring no acceleration. + #endif + #endif } planner_settings_t; +/// Subclass to enforce that people are using user settings when applying settings +struct user_planner_settings_t : public planner_settings_t {}; + // Structure for saving/loading movement parameters typedef struct { uint32_t max_acceleration_mm_per_s2[XYZE_N], // (mm/s^2) M201 XYZE @@ -283,7 +294,18 @@ class Planner { // May be auto-adjusted by a filament width sensor #endif - static planner_settings_t settings; + /// Reference to working_settings - settings with applied limits + static const planner_settings_t &settings; + + /// Reference to user_settings - settings before limits are applied + static const user_planner_settings_t &user_settings; + + /// Sets new settings for the planner. + /// Writes the settings raw to user_settings, and with limits applied to settings/working_settings + /// !!! Always base your settings on user_settings, not on settings + static void apply_settings(const user_planner_settings_t &settings); + + static void set_stealth_mode(bool set); static uint32_t max_acceleration_msteps_per_s2[XYZE_N]; // (mini-steps/s^2) Derived from mm_per_s2 static float mm_per_step[XYZE_N]; // Millimeters per step @@ -294,14 +316,6 @@ class Planner { static float junction_deviation_mm; // (mm) M205 J #endif - #if HAS_CLASSIC_JERK - #if HAS_LINEAR_E_JERK - static xyz_pos_t max_jerk; // (mm/s^2) M205 XYZ - The largest speed change requiring no acceleration. - #else - static xyze_pos_t max_jerk; // (mm/s^2) M205 XYZE - The largest speed change requiring no acceleration. - #endif - #endif - #if HAS_LEVELING static bool leveling_active; // Flag that bed leveling is enabled #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) @@ -952,7 +966,15 @@ class Planner { #endif private: + /// Target planner settings, withOUT limits applied. + static user_planner_settings_t user_settings_; + /// Actual settings the planner is using, with limits applied + static planner_settings_t working_settings_; + + static bool stealth_mode_; + + private: /** * Get the index of the next / previous block in the ring buffer */ diff --git a/lib/Marlin/Marlin/src/module/probe.cpp b/lib/Marlin/Marlin/src/module/probe.cpp index 4ef0284044..51acb00ce2 100644 --- a/lib/Marlin/Marlin/src/module/probe.cpp +++ b/lib/Marlin/Marlin/src/module/probe.cpp @@ -866,8 +866,12 @@ void cleanup_probe(const xy_pos_t &rect_min, const xy_pos_t &rect_max) { auto loadcellPrecisionEnabler = Loadcell::HighPrecisionEnabler(loadcell); // set acceleration to known value - auto saved_acceleration = planner.settings.travel_acceleration; - planner.settings.travel_acceleration = PROBE_CLEANUP_TRAVEL_ACCELERATION; + auto saved_acceleration = planner.user_settings.travel_acceleration; + { + auto s = planner.user_settings; + s.travel_acceleration = PROBE_CLEANUP_TRAVEL_ACCELERATION; + planner.apply_settings(s); + } bool should_continue = true; for (float y = rect_min.y + radius; (y + radius) <= rect_max.y && should_continue; y += 2 * radius) { @@ -911,7 +915,11 @@ void cleanup_probe(const xy_pos_t &rect_min, const xy_pos_t &rect_max) { } // restore acceleration - planner.settings.travel_acceleration = saved_acceleration; + { + auto s = planner.user_settings; + s.travel_acceleration = saved_acceleration; + planner.apply_settings(s); + } if (probe_deployed) { STOW_PROBE(); 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 diff --git a/lib/Marlin/Marlin/src/module/prusa/homing_utils.cpp b/lib/Marlin/Marlin/src/module/prusa/homing_utils.cpp index c0e3f74061..4d0f9a1505 100644 --- a/lib/Marlin/Marlin/src/module/prusa/homing_utils.cpp +++ b/lib/Marlin/Marlin/src/module/prusa/homing_utils.cpp @@ -90,13 +90,16 @@ Motion_Parameters reset_acceleration_if(bool condition) { mp.reset(); #if ENABLED(IMPROVE_HOMING_RELIABILITY) - planner.settings.max_acceleration_mm_per_s2[X_AXIS] = XY_HOMING_ACCELERATION; - planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = XY_HOMING_ACCELERATION; + { + auto s = planner.user_settings; + s.max_acceleration_mm_per_s2[X_AXIS] = XY_HOMING_ACCELERATION; + s.max_acceleration_mm_per_s2[Y_AXIS] = XY_HOMING_ACCELERATION; #if HAS_CLASSIC_JERK - planner.max_jerk.set(XY_HOMING_JERK, XY_HOMING_JERK); + s.max_jerk.set(XY_HOMING_JERK, XY_HOMING_JERK); #endif + planner.apply_settings(s); + } #endif - planner.refresh_acceleration_rates(); remember_feedrate_scaling_off(); return mp; } diff --git a/lib/Marlin/Marlin/src/module/prusa/toolchanger.cpp b/lib/Marlin/Marlin/src/module/prusa/toolchanger.cpp index 6f7778f5fc..dcffe3d07d 100644 --- a/lib/Marlin/Marlin/src/module/prusa/toolchanger.cpp +++ b/lib/Marlin/Marlin/src/module/prusa/toolchanger.cpp @@ -651,7 +651,11 @@ bool PrusaToolChanger::park(Dwarf &dwarf) { stepperY.stall_sensitivity(PARKING_STALL_SENSITIVITY); move(info.dock_x + PARK_X_OFFSET_2, info.dock_y, SLOW_MOVE_MM_S); - planner.settings.travel_acceleration = SLOW_ACCELERATION_MM_S2; // low acceleration + { + auto s = planner.user_settings; + s.travel_acceleration = SLOW_ACCELERATION_MM_S2; + planner.apply_settings(s); + } move(info.dock_x + PARK_X_OFFSET_3, info.dock_y, SLOW_MOVE_MM_S); planner.synchronize(); conf_restorer.restore_acceleration(); // back to high acceleration @@ -766,7 +770,12 @@ bool PrusaToolChanger::pickup(Dwarf &dwarf) { move(info.dock_x, SAFE_Y_WITHOUT_TOOL, feedrate_mm_s); // go in front of the tool move(info.dock_x, info.dock_y + PICK_Y_OFFSET, feedrate_mm_s); // pre-insert fast the tool - planner.settings.travel_acceleration = SLOW_ACCELERATION_MM_S2; // low acceleration + + { + auto s = planner.user_settings; + s.travel_acceleration = SLOW_ACCELERATION_MM_S2; + planner.apply_settings(s); + } move(info.dock_x, info.dock_y, SLOW_MOVE_MM_S); // insert slowly the last mm to allow part fitting + soft touch between TCM and tool thanks to the gentle deceleration planner.synchronize(); diff --git a/lib/Marlin/Marlin/src/module/prusa/toolchanger_utils.cpp b/lib/Marlin/Marlin/src/module/prusa/toolchanger_utils.cpp index 1e61e09773..b1f812d754 100644 --- a/lib/Marlin/Marlin/src/module/prusa/toolchanger_utils.cpp +++ b/lib/Marlin/Marlin/src/module/prusa/toolchanger_utils.cpp @@ -461,7 +461,7 @@ void PrusaToolChangerUtils::ConfRestorer::sample() { if (sampled) { bsod("Double sampled planner configuration"); } - sampled_jerk = planner.max_jerk; + sampled_jerk = planner.settings.max_jerk; sampled_travel_acceleration = planner.settings.travel_acceleration; sampled_feedrate_mm_s = feedrate_mm_s; sampled_feedrate_percentage = feedrate_percentage; @@ -477,14 +477,20 @@ void PrusaToolChangerUtils::ConfRestorer::restore_jerk() { if (!sampled.load()) { bsod("Restoring not sampled jerk"); } - planner.max_jerk = sampled_jerk; + + auto s = planner.user_settings; + s.max_jerk = sampled_jerk; + planner.apply_settings(s); } void PrusaToolChangerUtils::ConfRestorer::restore_acceleration() { if (!sampled.load()) { bsod("Restoring not sampled acceleration"); } - planner.settings.travel_acceleration = sampled_travel_acceleration; + + auto s = planner.user_settings; + s.travel_acceleration = sampled_travel_acceleration; + planner.apply_settings(s); } void PrusaToolChangerUtils::ConfRestorer::restore_feedrate() { diff --git a/lib/Marlin/Marlin/src/module/prusa/toolchanger_utils.h b/lib/Marlin/Marlin/src/module/prusa/toolchanger_utils.h index 856c0e00a1..fafa917d3e 100644 --- a/lib/Marlin/Marlin/src/module/prusa/toolchanger_utils.h +++ b/lib/Marlin/Marlin/src/module/prusa/toolchanger_utils.h @@ -19,7 +19,7 @@ class PrusaToolChangerUtils { static constexpr auto PARKING_FINAL_MAX_SPEED = 300.f; ///< Maximum speed (mm/s) for parking static constexpr auto SLOW_ACCELERATION_MM_S2 = 400; ///< Acceleration for parking and picking static constexpr auto FORCE_MOVE_MM_S = 30; ///< Not used here, feedrate for locking and unlocking the toolchange clamps - static constexpr auto SLOW_MOVE_MM_S = 60; ///< Feedrate for tool picking and parking + static constexpr auto SLOW_MOVE_MM_S = 50; ///< Feedrate for tool picking and parking static constexpr auto Z_HOP_FEEDRATE_MM_S = 10.0f; ///< Feedrate for z hop static constexpr auto TRAVEL_MOVE_MM_S = 400.f; ///< Feedrate for moves around dock static constexpr uint32_t WAIT_TIME_TOOL_SELECT = 3000; ///< Max wait for puppytask tool switch [ms], needs a lot of time if there is a hiccup in puppy communication diff --git a/lib/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.c b/lib/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.c index 7f9fa3df13..8498d8777c 100644 --- a/lib/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.c +++ b/lib/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.c @@ -521,6 +521,7 @@ static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost) (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, 0U); #endif #endif + rw_mutex_writer_give(&phost->class_mutex); } else { @@ -535,9 +536,9 @@ static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost) (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, 0U); #endif #endif + rw_mutex_writer_give(&phost->class_mutex); phost->pUser(phost, HOST_USER_CLASS_ACTIVE); } - rw_mutex_writer_give(&phost->class_mutex); break; case MSC_IDLE: diff --git a/lib/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c b/lib/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c index 7072dfbb7a..7e927ae5ed 100644 --- a/lib/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c +++ b/lib/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c @@ -453,6 +453,11 @@ USBH_StatusTypeDef USBH_ReEnumerate(USBH_HandleTypeDef *phost) /* Stop Host */ (void)USBH_Stop(phost); + // This was formerly inside USBH_Start's USBH_LL_DriverVBUS, + // got to put it out because it was called from Tmr Svc, which does not allow blocking + // BFW-5213 + (void)USBH_Delay(200); + phost->device.is_disconnected = 1U; } @@ -818,6 +823,11 @@ USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost) /* Start the host and re-enable Vbus */ (void)USBH_Start(phost); + + // This was formerly inside USBH_Start's USBH_LL_DriverVBUS, + // got to put it out because it was called from Tmr Svc, which does not allow blocking + // BFW-5213 + (void)USBH_Delay(200); } else { diff --git a/lib/Prusa-Error-Codes/.gitignore b/lib/Prusa-Error-Codes/.gitignore index a62496a00a..ce16c9dc2f 100644 --- a/lib/Prusa-Error-Codes/.gitignore +++ b/lib/Prusa-Error-Codes/.gitignore @@ -3,3 +3,4 @@ __pycache__ .coverage *.egg-info build +venv diff --git a/lib/Prusa-Error-Codes/.gitrepo b/lib/Prusa-Error-Codes/.gitrepo index c8025603b7..5352b44b78 100644 --- a/lib/Prusa-Error-Codes/.gitrepo +++ b/lib/Prusa-Error-Codes/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = git@github.com:prusa3d/Prusa-Error-Codes.git branch = master - commit = 5081240e6e5f2bb86e8eb1d92a11d6ec81702e0f - parent = 29e4882159e05516f299ed61207ffc7d4f932f7b + commit = 895dd57050c91f2b7c2e36cf1e0ee41fdfd5ca8a + parent = 14b7d3048a2559d3f5f120789bad61b381afad01 method = merge - cmdver = 0.4.3 + cmdver = 0.4.6 diff --git a/lib/Prusa-Error-Codes/MANIFEST.in b/lib/Prusa-Error-Codes/MANIFEST.in index 8cf8cdfb5b..9980efd31c 100644 --- a/lib/Prusa-Error-Codes/MANIFEST.in +++ b/lib/Prusa-Error-Codes/MANIFEST.in @@ -1 +1,4 @@ include prusaerrors/sl1/errors.yaml +include prusaerrors/mmu/errors.yaml +include prusaerrors/buddy/errors.yaml + diff --git a/lib/Prusa-Error-Codes/README.md b/lib/Prusa-Error-Codes/README.md index ecfa9a317f..27b7691f8a 100644 --- a/lib/Prusa-Error-Codes/README.md +++ b/lib/Prusa-Error-Codes/README.md @@ -33,6 +33,7 @@ Example: 12201 dialogs to the server. If there's an error in one of the above categories, it is possible to reuse that error code directly, no need to create a duplicate one in this category. +9. Other More information about the error codes can be found at: [prusa.io/error-codes](https://prusa.io/error-codes) diff --git a/lib/Prusa-Error-Codes/generate_buddy_headers.py b/lib/Prusa-Error-Codes/generate_buddy_headers.py index 8e05d0b9e9..3a5e9eb662 100644 --- a/lib/Prusa-Error-Codes/generate_buddy_headers.py +++ b/lib/Prusa-Error-Codes/generate_buddy_headers.py @@ -164,7 +164,7 @@ def generate_header_file(yaml_file_name, header_file_name, printer_id, printer_c "id": err_id, "code": err_code, "title": err["title"], - "text": err["text"].replace("\n", "\\n"), + "text": err["text"].translate(str.maketrans({"\n": "\\n", "\"": "\\\""})), "extra_text": extra_text } diff --git a/lib/Prusa-Error-Codes/prusaerrors/buddy/errors.yaml b/lib/Prusa-Error-Codes/prusaerrors/buddy/errors.yaml new file mode 120000 index 0000000000..eacf640306 --- /dev/null +++ b/lib/Prusa-Error-Codes/prusaerrors/buddy/errors.yaml @@ -0,0 +1 @@ +../../yaml/buddy-error-codes.yaml \ No newline at end of file diff --git a/lib/Prusa-Error-Codes/prusaerrors/connect/__init__.py b/lib/Prusa-Error-Codes/prusaerrors/connect/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/Prusa-Error-Codes/prusaerrors/connect/codes.py b/lib/Prusa-Error-Codes/prusaerrors/connect/codes.py new file mode 100644 index 0000000000..afeaed5e51 --- /dev/null +++ b/lib/Prusa-Error-Codes/prusaerrors/connect/codes.py @@ -0,0 +1,122 @@ +# This file is part of the SL1 firmware +# Copyright (C) 2020 Prusa Research a.s. - www.prusa3d.com +# SPDX-License-Identifier: GPL-3.0-or-later + +""" +All printer type error/attention codes + +Warning: The codes might not have yet been officially approved. +""" +import re +from pathlib import Path +from typing import Optional + +import yaml + +from prusaerrors.shared.codes import unique_codes, Codes, Printer, Code, Category + + +BUDDY = ['MINI', 'MK4', 'IX', 'XL', 'MK35', 'MK39'] + + +class PrinterCode(Code): + """ + Code class holds error code information + + """ + + # pylint: disable = too-many-arguments + def __init__( + self, + printer: Printer, + category: Category, + error: int, + title: str, + message: str, + approved: bool, + id_: str, + ): + super().__init__(printer=printer, category=category, error=error, + title=title, message=message, approved=approved) + self.id = id_ + + @property + def code(self) -> str: + """ + Get error code + + :return: Error code + """ + return f"x{self.raw_code}" + + +def yaml_codes(src_path: Path): + """ + Add code definitions from YAML source + """ + + def decor(cls): + with src_path.open("r") as src_file: + data = yaml.safe_load(src_file) + assert "Errors" in data + + code_re = re.compile( + r"^(?P([0-9][0-9]|XX))" + r"(?P[0-9])" + r"(?P[0-9][0-9])$") + for entry in data["Errors"]: + code_parts = code_re.match(entry["code"]).groupdict() + category = Category(int(code_parts["category"])) + error = int(code_parts["error"]) + + # code is common for printers defined in printers attribute + if code_parts["printer"] == 'XX': + if printers := entry.get("printers"): + if 'MK4' in printers: + printers.append('MK39') + else: # if no printers specified code is valid for all buddy + printers = BUDDY + + for printer in printers: + printer = Printer[printer.upper().replace(".", "")] + code = PrinterCode( + printer, category, error, entry["title"], + entry["text"], entry.get("approved", False), + entry["id"]) + setattr(cls, str(code), code) + + # code contains printer number + else: + printer = Printer(int(code_parts["printer"])) + code = PrinterCode(printer, category, error, entry["title"], + entry["text"], entry.get("approved", False), + entry["id"]) + setattr(cls, str(code), code) + return cls + + return decor + + +@unique_codes +@yaml_codes(Path(__file__).parent.parent / "sl1" / "errors.yaml") +@yaml_codes(Path(__file__).parent.parent / "mmu" / "errors.yaml") +@yaml_codes(Path(__file__).parent.parent / "buddy" / "errors.yaml") +class PrinterCodes(Codes): + """ + Load all the printer type error, exception and warning identification codes + + Content is loaded by yaml_codes decorators. + """ + + @classmethod + def get(cls, code: str) -> Optional[PrinterCode]: + """ + Get Code by its number + + :param code: Code number as string + :return: Code instance + """ + try: + return super().get(f"x{code}") + except KeyError: + return None diff --git a/lib/Prusa-Error-Codes/prusaerrors/mmu/errors.yaml b/lib/Prusa-Error-Codes/prusaerrors/mmu/errors.yaml new file mode 120000 index 0000000000..8d18c9184d --- /dev/null +++ b/lib/Prusa-Error-Codes/prusaerrors/mmu/errors.yaml @@ -0,0 +1 @@ +../../yaml/mmu-error-codes.yaml \ No newline at end of file diff --git a/lib/Prusa-Error-Codes/prusaerrors/shared/codes.py b/lib/Prusa-Error-Codes/prusaerrors/shared/codes.py index 40fc5f4560..550bbf11ec 100644 --- a/lib/Prusa-Error-Codes/prusaerrors/shared/codes.py +++ b/lib/Prusa-Error-Codes/prusaerrors/shared/codes.py @@ -11,7 +11,7 @@ import re from enum import unique, IntEnum from pathlib import Path -from typing import Optional, TextIO, Dict +from typing import TextIO, Dict import yaml @@ -24,7 +24,14 @@ class Printer(IntEnum): """ UNKNOWN = 0 + MMU = 0x0004 SL1 = 0x000A + MINI = 0x000C + MK4 = 0x000D + IX = 0x0010 + XL = 0x0011 + MK35 = 0x0017 + MK39 = 0x0015 @unique @@ -42,6 +49,8 @@ class Category(IntEnum): SYSTEM = 5 # System - BSOD, ... BOOTLOADER = 6 # WARNINGS = 7 # Category-less warnings + DIALOGS = 8 # Remote Dialogs + UNKNOWN = 9 @functools.total_ordering @@ -56,8 +65,8 @@ def __init__( printer: Printer, category: Category, error: int, - title: Optional[str], - message: Optional[str], + title: str, + message: str, approved: bool, ): if printer.value < 0 or printer.value > 99: diff --git a/lib/Prusa-Error-Codes/tests/test_connect.py b/lib/Prusa-Error-Codes/tests/test_connect.py new file mode 100644 index 0000000000..5cc82844b0 --- /dev/null +++ b/lib/Prusa-Error-Codes/tests/test_connect.py @@ -0,0 +1,32 @@ +# This file is part of the SL1 firmware +# Copyright (C) 2020 Prusa Research a.s. - www.prusa3d.com +# SPDX-License-Identifier: GPL-3.0-or-later + +# pylint: disable = missing-function-docstring +# pylint: disable = missing-class-docstring +# pylint: disable = missing-module-docstring + +import unittest + +from prusaerrors.shared.codes import Printer, Category +from prusaerrors.connect.codes import PrinterCodes + + +class TestErrors(unittest.TestCase): + + def test_code_lookup(self): + code = PrinterCodes.get("17505") + assert code.printer == Printer(17) + assert code.category == Category(5) + assert code.error == 5 + assert code.title + assert code.message + assert code.id + + def test_unknown_code(self): + code = PrinterCodes.get("unknown_code") + assert code is None + + +if __name__ == "__main__": + unittest.main() diff --git a/lib/Prusa-Error-Codes/yaml/buddy-error-codes.yaml b/lib/Prusa-Error-Codes/yaml/buddy-error-codes.yaml index 3cf34173c6..363097d1af 100644 --- a/lib/Prusa-Error-Codes/yaml/buddy-error-codes.yaml +++ b/lib/Prusa-Error-Codes/yaml/buddy-error-codes.yaml @@ -786,213 +786,243 @@ Errors: - code: "XX702" printers: [MK4] title: "Cold Pull" - text: "Next steps require user cooperation, please read the link first." + text: "Welcome to the Cold Pull wizard. Prepare a 30cm piece of PLA filament and follow the instructions. For more details, visit:" id: "COLD_PULL_INTRO" approved: true - code: "XX801" - title: "" - text: "" + title: "Warning" + text: "Please complete Calibrations & Tests before using the printer." id: "PRINT_PREVIEW_UNFINISHED_SELFTEST" type: "CONNECT" - code: "XX802" - title: "" - text: "" + printers: [MINI] + title: "Warning" + text: "New FW available" + id: "PRINT_PREVIEW_NEW_FW" + type: "CONNECT" + + - code: "XX802" + printers: [MK4, XL, MK3.5, iX] + title: "Warning" + text: "New firmware available" id: "PRINT_PREVIEW_NEW_FW" type: "CONNECT" - code: "XX803" - title: "" - text: "" + title: "Warning" + text: "The G-code isn't fully compatible" id: "PRINT_PREVIEW_WRONG_PRINTER" type: "CONNECT" - code: "XX804" - title: "" - text: "" + title: "Warning" + text: "Filament not detected. Load filament now?\nSelect NO to cancel the print.\nSelect DISABLE FS to disable the filament sensor and continue print." id: "PRINT_PREVIEW_NO_FILAMENT" type: "CONNECT" - code: "XX805" - title: "" - text: "" + printers: [MINI] + title: "Warning" + text: "This G-code was set up for another filament type." + id: "PRINT_PREVIEW_WRONG_FILAMENT" + type: "CONNECT" + + - code: "XX805" + printers: [MK4, XL, MK3.5, iX] + title: "Warning" + text: "A filament specified in the G-code is either not loaded or wrong type." id: "PRINT_PREVIEW_WRONG_FILAMENT" type: "CONNECT" - code: "XX806" printers: [MK4, MK3.5] - title: "" - text: "" + title: "Warning" + text: "Filament detected. Unload filament now? Select NO to start the print with the currently loaded filament." id: "PRINT_PREVIEW_MMU_FILAMENT_INSERTED" type: "CONNECT" - code: "XX807" - title: "" - text: "" + title: "File error" + #TODO what about this one? It is dynamically generated. + text: "File error" id: "PRINT_PREVIEW_FILE_ERROR" type: "CONNECT" - code: "XX808" title: "" - text: "" + text: "The heatbed cooled down during the power outage, printed object might have detached. Inspect it before continuing." id: "POWER_PANIC_COLD_BED" type: "CONNECT" - code: "XX809" title: "" - text: "" - id: "CRASH_RECOVERY_AXIS_NOK" + text: "Length of an axis is too long.\nMotor current is too low, probably.\nRetry check, pause or resume the print?" + id: "CRASH_RECOVERY_AXIS_LONG" type: "CONNECT" - code: "XX810" title: "" - text: "" - id: "CRASH_RECOVERY_REPEATED_CRASH" + text: "Length of an axis is too short.\nThere's an obstacle or bearing issue.\nRetry check, pause or resume the print?" + id: "CRASH_RECOVERY_AXIS_SHORT" type: "CONNECT" - code: "XX811" title: "" - text: "" + text: "Repeated collision has been detected.\nDo you want to resume or pause the print?" + id: "CRASH_RECOVERY_REPEATED_CRASH" + type: "CONNECT" + + - code: "XX812" + title: "" + text: "Unable to home the printer.\nDo you want to try again?" id: "CRASH_RECOVERY_HOME_FAIL" type: "CONNECT" - - code: "XX812" + - code: "XX813" printers: [XL] title: "" - text: "" + text: "Toolchanger problem has been detected.\nPark all tools to docks\nand leave the carriage free." id: "CRASH_RECOVERY_TOOL_PICKUP" type: "CONNECT" - - code: "XX813" + - code: "XX814" printers: [MK4, XL, MK3.5] - title: "" - text: "" + title: "Tool mapping" + text: "Changes of mapping available only in the Printer UI. Select Print to start the print with defaults." id: "PRINT_PREVIEW_TOOLS_MAPPING" type: "CONNECT" - - code: "XX814" + - code: "XX815" printers: [MK4, MK3.5] title: "" - text: "" + text: "Waiting for user input" id: "MMU_LOAD_UNLOAD_ERROR" type: "CONNECT" - - code: "XX815" + - code: "XX816" title: "" - text: "" + text: "Print fan not spinning. Check it for possible debris, then inspect the wiring." id: "PRINT_FAN_ERROR" type: "CONNECT" - - code: "XX816" + - code: "XX817" title: "" - text: "" + text: "Heating disabled due to 30 minutes of inactivity." id: "HEATERS_TIMEOUT" type: "CONNECT" - - code: "XX817" + - code: "XX818" title: "" - text: "" + text: "Measured temperature is not matching expected value. Check the thermistor is in contact with hotend. In case of damage, replace it." id: "HOTEND_TEMP_DISCREPANCY" type: "CONNECT" - - code: "XX818" + - code: "XX819" title: "" - text: "" + text: "Heating disabled due to 30 minutes of inactivity." id: "NOZZLE_TIMEOUT" type: "CONNECT" - - code: "XX819" + - code: "XX820" title: "" - text: "" + text: "Steppers disabled due to inactivity." id: "STEPPERS_TIMEOUT" type: "CONNECT" - - code: "XX820" + - code: "XX821" title: "" - text: "" + text: "USB drive or file error, the print is now paused. Reconnect the drive." id: "USB_FLASH_DISK_ERROR" type: "CONNECT" - - code: "XX821" + - code: "XX822" title: "" - text: "" + text: "Heatbreak thermistor is disconnected. Inspect the wiring." id: "HEATBREAK_THERMISTOR_FAIL" type: "CONNECT" - - code: "XX822" + - code: "XX823" printers: [XL, MK3.5] title: "" - text: "" + text: "Nozzle doesn't seem to have round cross section. Make sure it is clean and perpendicular to the bed." id: "NOZZLE_DOES_NOT_HAVE_ROUND_SECTION" type: "CONNECT" - - code: "XX823" + - code: "XX824" title: "" - text: "" + text: "G-Code transfer running too slow. Check your network for issues or use different USB drive. Press Continue to resume printing." id: "NOT_DOWNLOADED" type: "CONNECT" - - code: "XX824" + - code: "XX825" title: "" - text: "" + text: "MCU in Buddy is overheated. Any higher will result in fatal error." id: "BUDDY_MCU_MAX_TEMP" type: "CONNECT" - - code: "XX825" + - code: "XX826" printers: [XL] title: "" - text: "" + text: "MCU in Dwarf is overheated. Any higher will result in fatal error." id: "DWARF_MCU_MAX_TEMP" type: "CONNECT" - - code: "XX826" + - code: "XX827" printers: [iX, XL] title: "" - text: "" + text: "MCU in Modular Bed is overheated. Any higher will result in fatal error." id: "MOD_BED_MCU_MAX_TEMP" type: "CONNECT" - - code: "XX827" + + - code: "XX828" title: "" - text: "" + text: "Hotend fan not spinning. Check it for possible debris, then inspect the wiring." id: "HOTEND_FAN_ERROR" type: "CONNECT" - - code: "XX828" - title: "" - text: "" + - code: "XX829" + title: "Filament runout" + text: "Filament runout during print, please insert new one." id: "FILAMENT_RUNOUT" type: "CONNECT" - - code: "XX829" + - code: "XX830" printers: [XL] title: "" - text: "" + text: "Enclosure fan not spinning. Check it for possible debris, then inspect the wiring." id: "ENCLOSURE_FAN_ERROR" type: "CONNECT" - - code: "XX830" + - code: "XX831" printers: [XL] title: "" - text: "" + text: "The HEPA filter is nearing the end of its life span (100 hours of printing time remaining). We recommend purchasing a new one. Visit prusa.io/xl-filter for more information." id: "ENCLOSURE_FILTER_EXPIRATION_WARNING" type: "CONNECT" - - code: "XX831" + - code: "XX832" printers: [XL] title: "" - text: "" + text: "The HEPA filter has expired. Change the HEPA filter before your next print. Visit prusa.io/xl-filter for more information." id: "ENCLOSURE_FILTER_EXPIRATION" type: "CONNECT" - - code: "XX832" + - code: "XX833" printers: [iX, MK4, MK3.5, MINI, XL] title: "" - text: "" + text: "Bed leveling failed. Try again?" id: "PROBING_FAILED" type: "CONNECT" - - code: "XX833" + - code: "XX834" printers: [iX, MK4, MK3.5, XL] title: "" - text: "" + text: "Nozzle cleaning failed." id: "NOZZLE_CLEANING_FAILED" type: "CONNECT" + - code: "XX835" + printers: [iX, MK4, MK3.5, MINI, XL] + title: "" + text: "Waiting for the user. Press \"Resume\" once the printer is ready." + id: "QUICK_PAUSE" + type: "CONNECT" diff --git a/lib/WUI/mdns/mdns.c b/lib/WUI/mdns/mdns.c index 6bfd49f90e..34fad90b46 100644 --- a/lib/WUI/mdns/mdns.c +++ b/lib/WUI/mdns/mdns.c @@ -2362,6 +2362,16 @@ err_t mdns_resp_remove_netif(struct netif *netif) { LWIP_ERROR("mdns_resp_remove_netif: Not an active netif", (mdns != NULL), return ERR_VAL); sys_untimeout(mdns_probe_and_announce, netif); + // Disable all other timers + // (does nothing if it doesn't exist) + sys_untimeout(mdns_send_unicast_msg_delayed_ipv4, netif); + sys_untimeout(mdns_send_multicast_msg_delayed_ipv4, netif); + sys_untimeout(mdns_multicast_timeout_reset_ipv4, netif); + sys_untimeout(mdns_multicast_probe_timeout_reset_ipv4, netif); + sys_untimeout(mdns_multicast_timeout_25ttl_reset_ipv4, netif); + // Note: There's possibly a timeout with a packet. We don't disable that one because: + // * The packet isn't a dangling pointer. + // * We don't have its address and we don't know it originated from this netif. #if 0 Abuse of the original code to hardcode the services. diff --git a/lib/WUI/nhttp/gcode_preview.h b/lib/WUI/nhttp/gcode_preview.h index 658edd36fe..ef4f79b2be 100644 --- a/lib/WUI/nhttp/gcode_preview.h +++ b/lib/WUI/nhttp/gcode_preview.h @@ -2,6 +2,7 @@ #include "step.h" #include +#include #include #include @@ -9,7 +10,6 @@ #include #include #include -#include "gcode_reader.hpp" namespace nhttp::printer { diff --git a/lib/WUI/nhttp/headers.cpp b/lib/WUI/nhttp/headers.cpp index 92c07c8d91..2ec8f26270 100644 --- a/lib/WUI/nhttp/headers.cpp +++ b/lib/WUI/nhttp/headers.cpp @@ -40,7 +40,7 @@ namespace { { Status::UnprocessableEntity, "Unprocessable Entity" }, { Status::TooManyRequests, "Too Many Requests" }, { Status::RequestHeaderFieldsTooLarge, "Request Header Fields Too Large" }, - { Status::InternalServerError, "Infernal Server Error" }, + { Status::InternalServerError, "Internal Server Error" }, { Status::NotImplemented, "Not Implemented" }, { Status::ServiceTemporarilyUnavailable, "Service Temporarily Unavailable" }, { Status::GatewayTimeout, "Gateway Timeout" }, diff --git a/lib/WUI/nhttp/server.h b/lib/WUI/nhttp/server.h index ff4969cad0..077b63c821 100644 --- a/lib/WUI/nhttp/server.h +++ b/lib/WUI/nhttp/server.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -110,7 +111,9 @@ class Server { * * It is assumed to be able to fail due to eg. inability to send a * FIN packet. This is not the case for a listening socket. */ + LOCK_TCPIP_CORE(); altcp_close(conn); + UNLOCK_TCPIP_CORE(); } }; diff --git a/lib/WUI/wui.cpp b/lib/WUI/wui.cpp index 43bdf855ad..6b2b3f8576 100644 --- a/lib/WUI/wui.cpp +++ b/lib/WUI/wui.cpp @@ -477,11 +477,30 @@ class NetworkState { #if MDNS() if (events & MdnsInitCheck) { - for (auto &iface : ifaces) { - if (!iface.mdns_initialized && netif_ip4_addr(&iface.dev)->addr != 0) { - iface.mdns_initialized = true; + // We can afford to have only one interface active for the responder. + // + // Doing a check through all the interfaces out of + // overabundance of caution - making sure we don't start the + // second MDNS instance in case the active netdev changes and + // we didn't _yet_ have time to call reconfigure and similar + // situations (that would introduce a risk of exhausting some + // resource - like the number of timeouts, where the code is + // not prepared for the callback not being run eventually, + // leading to some inconsistent internal state). + bool any_active = false; + for (const auto &iface : ifaces) { + if (iface.mdns_initialized) { + any_active = true; + break; + } + } + + if (!any_active) { + const uint32_t active = config_store().active_netdev.get(); + if (active < ifaces.size() && netif_ip4_addr(&ifaces[active].dev)->addr != 0) { // Wait with initialization until we get an IP address. - netifapi_netif_common(&iface.dev, mdns_netif_init, nullptr); + ifaces[active].mdns_initialized = true; + netifapi_netif_common(&ifaces[active].dev, mdns_netif_init, nullptr); } } } diff --git a/requirements.txt b/requirements.txt index 12e47fe378..171eee34f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,14 @@ -pip~=23.0 +aiohttp~=3.8 +click~=8.1.3 +easyocr~=1.7 ecdsa~=0.18 -polib~=1.2 -pyyaml~=6.0 littlefs-python==0.8 numpy~=1.26.4 pillow~=9.5 -qoi~=0.5.0 -click~=8.1.3 -pytest~=7.3.2 -pytest-asyncio~=0.21 -easyocr~=1.7 -aiohttp~=3.8 +pip~=23.0 +polib~=1.2 pre-commit +pytest-asyncio~=0.21 +pytest~=7.3.2 +pyyaml~=6.0 +qoi~=0.5.0 diff --git a/src/bootloader/bootloader_update.cpp b/src/bootloader/bootloader_update.cpp index 32b32b1aaf..3b159d35e8 100644 --- a/src/bootloader/bootloader_update.cpp +++ b/src/bootloader/bootloader_update.cpp @@ -10,8 +10,10 @@ #include #include "sys.h" #include - #include + +#include + #include "data_exchange.hpp" #include "resources/bootstrap.hpp" #include "resources/revision_bootloader.hpp" @@ -41,13 +43,6 @@ constexpr uintptr_t bootloader_sector_get_address(int sector) { return base_address; } -class FileDeleter { -public: - void operator()(FILE *file) { - fclose(file); - } -}; - static bool calculate_file_crc(FILE *fp, uint32_t length, uint32_t &crc) { uint8_t buffer[64]; while (length) { @@ -276,7 +271,7 @@ void buddy::bootloader::update(ProgressHook progress) { }); } - std::unique_ptr bootloader_bin(fopen("/internal/res/bootloader.bin", "rb")); + unique_file_ptr bootloader_bin(fopen("/internal/res/bootloader.bin", "rb")); if (bootloader_bin.get() == nullptr) { log_critical(Bootloader, "bootloader.bin failed to fopen() after its bootstrap"); fatal_error("bootloader.bin failed to open"); diff --git a/src/buddy/main.cpp b/src/buddy/main.cpp index 24f9a77c45..dc1e016028 100644 --- a/src/buddy/main.cpp +++ b/src/buddy/main.cpp @@ -16,7 +16,7 @@ #include #include #include "error_codes.hpp" -#include "bsod_gui.hpp" +#include #include "timer_defaults.h" #include "tick_timer_api.h" #include "thread_measurement.h" @@ -33,6 +33,7 @@ #include "filesystem.h" #include "adc.hpp" #include "logging.h" +#include #include