diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..f09f0becaf --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,30 @@ +name: Mark stale issues + +on: + schedule: + # 1:30 AM on MON/TUE/WED/THU + - cron: "30 1 * * 1,2,3,4" + +jobs: + stale: + + runs-on: ubuntu-latest + + steps: + - uses: actions/stale@v9 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + # Don't ever mark PRs as stale. + days-before-pr-stale: -1 + stale-issue-message: 'This issue has been flagged as stale because it has been open for 60 days with no activity. The issue will be closed in 7 days unless someone removes the "stale" label or adds a comment.' + close-issue-message: 'This issue has been closed due to lack of recent activity. Please consider opening a new one if needed.' + # Don't act on things assigned to a milestone or assigned to someone. + exempt-all-milestones: true + exempt-all-assignees: true + enable-statistics: true + # Disable this and change the operations per run back to 30 when this goes live. + debug-only: false + operations-per-run: 200 + stale-issue-label: 'stale-issue' + stale-pr-label: 'stale-pr' + ascending: true 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/device/stm32f4/device/peripherals.h b/include/device/stm32f4/device/peripherals.h index 3cce13369b..1f4b7f7368 100644 --- a/include/device/stm32f4/device/peripherals.h +++ b/include/device/stm32f4/device/peripherals.h @@ -237,6 +237,7 @@ extern TIM_HandleTypeDef htim14; #define i2c_eeprom 1 #define i2c_usbc -1 #define i2c_touch -1 + #define i2c_gcode 1 #define i2c_io_extender -1 #define spi_flash 3 #define spi_lcd 2 @@ -247,6 +248,7 @@ extern TIM_HandleTypeDef htim14; #elif BOARD_IS_XBUDDY #define i2c_eeprom 2 #define i2c_usbc 2 + #define i2c_gcode 2 #define i2c_io_extender -1 #define spi_flash 5 #define spi_lcd 6 @@ -266,6 +268,7 @@ extern TIM_HandleTypeDef htim14; #define i2c_eeprom 2 #define i2c_usbc 1 #define i2c_touch 3 + #define i2c_gcode 2 #define i2c_io_extender 2 #define spi_flash 5 #define spi_lcd 6 @@ -286,7 +289,7 @@ extern TIM_HandleTypeDef htim14; #define spi_led spi_extconn #endif -#define HAS_I2CN(n) ((n == i2c_eeprom) || (n == i2c_touch) || (n == i2c_usbc) || (n == i2c_io_extender)) +#define HAS_I2CN(n) ((n == i2c_eeprom) || (n == i2c_touch) || (n == i2c_usbc) || (n == i2c_gcode) || (n == i2c_io_extender)) // // Other 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_MINI_adv.h b/include/marlin/Configuration_MINI_adv.h index 3ac91b8dd3..c457c2a05e 100644 --- a/include/marlin/Configuration_MINI_adv.h +++ b/include/marlin/Configuration_MINI_adv.h @@ -2012,7 +2012,7 @@ // @section i2cbus -//#define EXPERIMENTAL_I2CBUS +#define EXPERIMENTAL_I2CBUS #define I2C_SLAVE_ADDRESS 0 // Set a value from 8 to 127 to act as a slave // @section extras 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..0fba88513f 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 /** @@ -2024,7 +2040,7 @@ // @section i2cbus -//#define EXPERIMENTAL_I2CBUS +#define EXPERIMENTAL_I2CBUS #define I2C_SLAVE_ADDRESS 0 // Set a value from 8 to 127 to act as a slave // @section extras 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_MK4_adv.h b/include/marlin/Configuration_MK4_adv.h index db42729c97..295a90a474 100644 --- a/include/marlin/Configuration_MK4_adv.h +++ b/include/marlin/Configuration_MK4_adv.h @@ -2048,7 +2048,7 @@ // @section i2cbus -//#define EXPERIMENTAL_I2CBUS +#define EXPERIMENTAL_I2CBUS #define I2C_SLAVE_ADDRESS 0 // Set a value from 8 to 127 to act as a slave // @section extras 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_XL_adv.h b/include/marlin/Configuration_XL_adv.h index 62e470a216..bf7cdacfbc 100644 --- a/include/marlin/Configuration_XL_adv.h +++ b/include/marlin/Configuration_XL_adv.h @@ -2044,7 +2044,7 @@ // @section i2cbus -//#define EXPERIMENTAL_I2CBUS +#define EXPERIMENTAL_I2CBUS #define I2C_SLAVE_ADDRESS 0 // Set a value from 8 to 127 to act as a slave // @section extras 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/AddMarlin.cmake b/lib/AddMarlin.cmake index 3379e2a575..b8d4b2f1b4 100644 --- a/lib/AddMarlin.cmake +++ b/lib/AddMarlin.cmake @@ -68,6 +68,7 @@ if(BOARD_IS_MASTER_BOARD) Marlin/Marlin/src/feature/runout.cpp Marlin/Marlin/src/feature/spindle_laser.cpp Marlin/Marlin/src/feature/touch/xpt2046.cpp + Marlin/Marlin/src/feature/twibus.cpp Marlin/Marlin/src/gcode/bedlevel/abl/G29.cpp Marlin/Marlin/src/gcode/bedlevel/abl/M421.cpp Marlin/Marlin/src/gcode/bedlevel/G26.cpp @@ -106,6 +107,7 @@ if(BOARD_IS_MASTER_BOARD) Marlin/Marlin/src/gcode/control/R.cpp Marlin/Marlin/src/gcode/eeprom/M500-M504.cpp Marlin/Marlin/src/gcode/feature/advance/M900.cpp + Marlin/Marlin/src/gcode/feature/i2c/M260_M261.cpp Marlin/Marlin/src/gcode/feature/input_shaper/M593.cpp Marlin/Marlin/src/gcode/feature/input_shaper/M74.cpp Marlin/Marlin/src/gcode/feature/modular_bed/M556.cpp diff --git a/lib/Marlin/Marlin/src/Marlin.cpp b/lib/Marlin/Marlin/src/Marlin.cpp index 09c0833129..a0329d67d9 100644 --- a/lib/Marlin/Marlin/src/Marlin.cpp +++ b/lib/Marlin/Marlin/src/Marlin.cpp @@ -121,11 +121,6 @@ #include "feature/dac/stepper_dac.h" #endif -#if ENABLED(EXPERIMENTAL_I2CBUS) - #include "feature/twibus.h" - TWIBus i2c; -#endif - #if ENABLED(I2C_POSITION_ENCODERS) #include "feature/I2CPositionEncoder.h" #endif @@ -258,18 +253,6 @@ void setup_powerhold() { void enableStepperDrivers() { SET_INPUT(STEPPER_RESET_PIN); } // Set to input, allowing pullups to pull the pin high #endif -#if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0 - - void i2c_on_receive(int bytes) { // just echo all bytes received to serial - i2c.receive(bytes); - } - - void i2c_on_request() { // just send dummy data for now - i2c.reply("Hello World!\n"); - } - -#endif - /** * Sensitive pin test for M42, M226 */ diff --git a/lib/Marlin/Marlin/src/Marlin.h b/lib/Marlin/Marlin/src/Marlin.h index 8c17f29acb..2ace567182 100644 --- a/lib/Marlin/Marlin/src/Marlin.h +++ b/lib/Marlin/Marlin/src/Marlin.h @@ -315,11 +315,6 @@ void manage_inactivity(const bool ignore_stepper_queue=false); #endif // !MIXING_EXTRUDER -#if ENABLED(EXPERIMENTAL_I2CBUS) - #include "feature/twibus.h" - extern TWIBus i2c; -#endif - #if ENABLED(G38_PROBE_TARGET) extern uint8_t G38_move; // Flag to tell the ISR that G38 is in progress, and the type extern bool G38_did_trigger; // Flag from the ISR to indicate the endstop changed 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/feature/twibus.cpp b/lib/Marlin/Marlin/src/feature/twibus.cpp index f4fe512cdf..4cc2eedb4d 100644 --- a/lib/Marlin/Marlin/src/feature/twibus.cpp +++ b/lib/Marlin/Marlin/src/feature/twibus.cpp @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -16,7 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . * */ @@ -26,174 +26,225 @@ #include "twibus.h" -#include +FORCE_INLINE char hex_nybble(const uint8_t n) { + return (n & 0xF) + ((n & 0xF) < 10 ? '0' : 'A' - 10); +} + +TWIBus twibus; TWIBus::TWIBus() { - #if I2C_SLAVE_ADDRESS == 0 - Wire.begin(); // No address joins the BUS as the master - #else - Wire.begin(I2C_SLAVE_ADDRESS); // Join the bus as a slave - #endif reset(); } void TWIBus::reset() { buffer_s = 0; buffer[0] = 0x00; + read_buffer_available = 0; + read_buffer_pos = 0; +} + +bool TWIBus::read_buffer_has_byte() { + return read_buffer_pos < read_buffer_available; } -void TWIBus::address(const uint8_t adr) { +uint8_t TWIBus::read_buffer_read_byte() { + if (!read_buffer_has_byte()) { + return 0; + } + return read_buffer[read_buffer_pos++]; +} + +bool TWIBus::address(const uint8_t adr) { if (!WITHIN(adr, 8, 127)) { SERIAL_ECHO_MSG("Bad I2C address (8-127)"); + return false; + } + + if (isRestrictedAddress(adr)) { + SERIAL_ECHO_MSG("Restricted I2C address."); + return false; } addr = adr; - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("address"), adr); - #endif + debug(F("address"), adr); + return true; +} + +bool TWIBus::isRestrictedAddress(uint8_t addr) { + switch (addr) { + case 0x53: + case 0x57: + // EEPROM + return true; + case 0x22: + case 0x23: + // USBC + return true; + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + // IO Extender + return true; + } + + return false; } void TWIBus::addbyte(const char c) { if (buffer_s >= COUNT(buffer)) return; buffer[buffer_s++] = c; - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("addbyte"), c); - #endif + debug(F("addbyte"), c); } void TWIBus::addbytes(char src[], uint8_t bytes) { - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("addbytes"), bytes); - #endif + debug(F("addbytes"), bytes); while (bytes--) addbyte(*src++); } void TWIBus::addstring(char str[]) { - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("addstring"), str); - #endif + debug(F("addstring"), str); while (char c = *str++) addbyte(c); } void TWIBus::send() { - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("send"), addr); - #endif - - Wire.beginTransmission(I2C_ADDRESS(addr)); - Wire.write(buffer, buffer_s); - Wire.endTransmission(); - + debug(F("send"), addr); + + i2c::Result ret = i2c::Transmit(I2C_HANDLE_FOR(gcode), addr << 1, buffer, buffer_s, 100); reset(); -} -// static -void TWIBus::echoprefix(uint8_t bytes, const char prefix[], uint8_t adr) { - SERIAL_ECHO_START(); - serialprintPGM(prefix); - SERIAL_ECHOPAIR(": from:", adr, " bytes:", bytes, " data:"); + check_hal_response(ret); } -// static -void TWIBus::echodata(uint8_t bytes, const char prefix[], uint8_t adr) { - echoprefix(bytes, prefix, adr); - while (bytes-- && Wire.available()) SERIAL_CHAR(Wire.read()); - SERIAL_EOL(); +bool TWIBus::check_hal_response(i2c::Result response) { + if (response == i2c::Result::ok) { + return true; + } + + switch (response) + { + case i2c::Result::error: + SERIAL_ERROR_MSG("TWIBus::send failed with: ERROR"); + break; + case i2c::Result::busy_after_retries: + SERIAL_ERROR_MSG("TWIBus::send failed with: BUSY"); + break; + case i2c::Result::timeout: + SERIAL_ERROR_MSG("TWIBus::send failed with: TIMEOUT"); + break; + default: + SERIAL_ERROR_MSG("TWIBus::send failed with: UNKNOWN"); + } + return false; } -void TWIBus::echobuffer(const char prefix[], uint8_t adr) { - echoprefix(buffer_s, prefix, adr); - for (uint8_t i = 0; i < buffer_s; i++) SERIAL_CHAR(buffer[i]); +void TWIBus::echodata(uint8_t bytes, FSTR_P const pref, uint8_t adr, const uint8_t style/*=0*/) { + union TwoBytesToInt16 { uint8_t bytes[2]; int16_t integervalue; }; + TwoBytesToInt16 ConversionUnion; + + while (bytes-- && read_buffer_has_byte()) { + int value = read_buffer_read_byte(); + switch (style) { + + // Style 1, HEX DUMP + case 1: + SERIAL_CHAR(hex_nybble((value & 0xF0) >> 4)); + SERIAL_CHAR(hex_nybble(value & 0x0F)); + if (bytes) SERIAL_CHAR(' '); + break; + + // Style 2, signed two byte integer (int16) + case 2: + if (bytes == 1) + ConversionUnion.bytes[1] = (uint8_t)value; + else if (bytes == 0) { + ConversionUnion.bytes[0] = (uint8_t)value; + // Output value in base 10 (standard decimal) + SERIAL_ECHO(ConversionUnion.integervalue); + } + break; + + // Style 3, unsigned byte, base 10 (uint8) + case 3: + SERIAL_ECHO(value); + if (bytes) SERIAL_CHAR(' '); + break; + + // Default style (zero), raw serial output + default: + // This can cause issues with some serial consoles, Pronterface is an example where things go wrong + SERIAL_CHAR(value); + break; + } + } + SERIAL_EOL(); } bool TWIBus::request(const uint8_t bytes) { if (!addr) return false; - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("request"), bytes); - #endif + debug(F("request"), bytes); + + if (bytes > TWIBUS_BUFFER_SIZE) { + SERIAL_ERROR_MSG("TWIBus::request Tried to read more than max buffer size."); - // requestFrom() is a blocking function - if (Wire.requestFrom(addr, bytes) == 0) { - #if ENABLED(DEBUG_TWIBUS) - debug("request fail", addr); - #endif return false; } + flush(); + + i2c::Result ret = i2c::Receive(I2C_HANDLE_FOR(gcode), addr << 1 | 0x1, read_buffer, bytes, 100); + + if (!check_hal_response(ret)) { + return false; + } + + read_buffer_available = bytes; return true; } -void TWIBus::relay(const uint8_t bytes) { - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("relay"), bytes); - #endif +void TWIBus::relay(const uint8_t bytes, const uint8_t style/*=0*/) { + debug(F("relay"), bytes); if (request(bytes)) - echodata(bytes, PSTR("i2c-reply"), addr); + echodata(bytes, F("i2c-reply"), addr, style); } uint8_t TWIBus::capture(char *dst, const uint8_t bytes) { reset(); uint8_t count = 0; - while (count < bytes && Wire.available()) - dst[count++] = Wire.read(); + while (count < bytes && read_buffer_has_byte()) + dst[count++] = read_buffer_read_byte(); - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("capture"), count); - #endif + debug(F("capture"), count); return count; } -// static void TWIBus::flush() { - while (Wire.available()) Wire.read(); + read_buffer_available = 0; + read_buffer_pos = 0; } -#if I2C_SLAVE_ADDRESS > 0 - - void TWIBus::receive(uint8_t bytes) { - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("receive"), bytes); - #endif - echodata(bytes, PSTR("i2c-receive"), 0); - } - - void TWIBus::reply(char str[]/*=nullptr*/) { - #if ENABLED(DEBUG_TWIBUS) - debug(PSTR("reply"), str); - #endif - - if (str) { - reset(); - addstring(str); - } - - Wire.write(buffer, buffer_s); - - reset(); - } - -#endif - #if ENABLED(DEBUG_TWIBUS) // static - void TWIBus::prefix(const char func[]) { - SERIAL_ECHOPGM("TWIBus::"); - serialprintPGM(func); - SERIAL_ECHOPGM(": "); + void TWIBus::prefix(FSTR_P const func) { + SERIAL_ECHOPGM("TWIBus::", func, ": "); } - void TWIBus::debug(const char func[], uint32_t adr) { + void TWIBus::debug(FSTR_P const func, uint32_t adr) { if (DEBUGGING(INFO)) { prefix(func); SERIAL_ECHOLN(adr); } } - void TWIBus::debug(const char func[], char c) { + void TWIBus::debug(FSTR_P const func, char c) { if (DEBUGGING(INFO)) { prefix(func); SERIAL_ECHOLN(c); } } - void TWIBus::debug(const char func[], char str[]) { + void TWIBus::debug(FSTR_P const func, char str[]) { if (DEBUGGING(INFO)) { prefix(func); SERIAL_ECHOLN(str); } } diff --git a/lib/Marlin/Marlin/src/feature/twibus.h b/lib/Marlin/Marlin/src/feature/twibus.h index cc40476374..980e20edac 100644 --- a/lib/Marlin/Marlin/src/feature/twibus.h +++ b/lib/Marlin/Marlin/src/feature/twibus.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -16,15 +16,19 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . * */ #pragma once #include "../core/macros.h" - +#include "i2c.hpp" #include +#ifndef I2C_ADDRESS + #define I2C_ADDRESS(A) uint8_t(A) +#endif + // Print debug messages with M111 S2 (Uses 236 bytes of PROGMEM) //#define DEBUG_TWIBUS @@ -46,9 +50,8 @@ typedef void (*twiRequestFunc_t)(); * for the host to interpret. * * For more information see - * - http://marlinfw.org/docs/gcode/M260.html - * - http://marlinfw.org/docs/gcode/M261.html - * + * - https://marlinfw.org/docs/gcode/M260.html + * - https://marlinfw.org/docs/gcode/M261.html */ class TWIBus { private: @@ -62,8 +65,33 @@ class TWIBus { * @brief Internal buffer * @details A fixed buffer. TWI commands can be no longer than this. */ - char buffer[TWIBUS_BUFFER_SIZE]; + uint8_t buffer[TWIBUS_BUFFER_SIZE]; + + /** + * @brief Number of bytes available on read buffer + * @description Number of bytes in the read buffer + */ + uint8_t read_buffer_available = 0; + + /** + * @brief Next position to be read from read buffer + * @description Next position to be read from read buffer + */ + uint8_t read_buffer_pos = 0; + + /** + * @brief Internal read buffer + * @details A fixed read buffer. + */ + uint8_t read_buffer[TWIBUS_BUFFER_SIZE]; + bool read_buffer_has_byte(); + + uint8_t read_buffer_read_byte(); + + bool check_hal_response(i2c::Result response); + + bool isRestrictedAddress(const uint8_t addr); public: /** @@ -123,16 +151,9 @@ class TWIBus { * @details The target slave address for sending the full packet * * @param adr 7-bit integer address + * @return status of the request: true=success, false=fail */ - void address(const uint8_t adr); - - /** - * @brief Prefix for echo to serial - * @details Echo a label, length, address, and "data:" - * - * @param bytes the number of bytes to request - */ - static void echoprefix(uint8_t bytes, const char prefix[], uint8_t adr); + bool address(const uint8_t adr); /** * @brief Echo data on the bus to serial @@ -140,17 +161,9 @@ class TWIBus { * to serial in a parser-friendly format. * * @param bytes the number of bytes to request + * @param style Output format for the bytes, 0 = Raw byte [default], 1 = Hex characters, 2 = uint16_t */ - static void echodata(uint8_t bytes, const char prefix[], uint8_t adr); - - /** - * @brief Echo data in the buffer to serial - * @details Echo the entire buffer to serial - * to serial in a parser-friendly format. - * - * @param bytes the number of bytes to request - */ - void echobuffer(const char prefix[], uint8_t adr); + void echodata(uint8_t bytes, FSTR_P const prefix, uint8_t adr, const uint8_t style=0); /** * @brief Request data from the slave device and wait. @@ -176,63 +189,33 @@ class TWIBus { * @brief Flush the i2c bus. * @details Get all bytes on the bus and throw them away. */ - static void flush(); + void flush(); /** * @brief Request data from the slave device, echo to serial. * @details Request a number of bytes from a slave device and output * the returned data to serial in a parser-friendly format. + * @style Output format for the bytes, 0 = raw byte [default], 1 = Hex characters, 2 = uint16_t * * @param bytes the number of bytes to request */ - void relay(const uint8_t bytes); - - #if I2C_SLAVE_ADDRESS > 0 - - /** - * @brief Register a slave receive handler - * @details Set a handler to receive data addressed to us - * - * @param handler A function to handle receiving bytes - */ - inline void onReceive(const twiReceiveFunc_t handler) { Wire.onReceive(handler); } - - /** - * @brief Register a slave request handler - * @details Set a handler to send data requested from us - * - * @param handler A function to handle receiving bytes - */ - inline void onRequest(const twiRequestFunc_t handler) { Wire.onRequest(handler); } - - /** - * @brief Default handler to receive - * @details Receive bytes sent to our slave address - * and simply echo them to serial. - */ - void receive(uint8_t bytes); - - /** - * @brief Send a reply to the bus - * @details Send the buffer and clear it. - * If a string is passed, write it into the buffer first. - */ - void reply(char str[]=nullptr); - inline void reply(const char str[]) { reply((char*)str); } - - #endif + void relay(const uint8_t bytes, const uint8_t style=0); #if ENABLED(DEBUG_TWIBUS) - /** * @brief Prints a debug message * @details Prints a simple debug message "TWIBus::function: value" */ - static void prefix(const char func[]); - static void debug(const char func[], uint32_t adr); - static void debug(const char func[], char c); - static void debug(const char func[], char adr[]); - static inline void debug(const char func[], uint8_t v) { debug(func, (uint32_t)v); } - + static void prefix(FSTR_P const func); + static void debug(FSTR_P const func, uint32_t adr); + static void debug(FSTR_P const func, char c); + static void debug(FSTR_P const func, char adr[]); + #else + static void debug(FSTR_P const, uint32_t) {} + static void debug(FSTR_P const, char) {} + static void debug(FSTR_P const, char[]) {} #endif + static void debug(FSTR_P const func, uint8_t v) { debug(func, (uint32_t)v); } }; + +extern TWIBus twibus; 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/i2c/M260_M261.cpp b/lib/Marlin/Marlin/src/gcode/feature/i2c/M260_M261.cpp index 48ab48959a..f56e6c1d65 100644 --- a/lib/Marlin/Marlin/src/gcode/feature/i2c/M260_M261.cpp +++ b/lib/Marlin/Marlin/src/gcode/feature/i2c/M260_M261.cpp @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -16,7 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . * */ @@ -26,12 +26,12 @@ #include "../../gcode.h" -#include "../../../Marlin.h" // for i2c +#include "../../../feature/twibus.h" /** * M260: Send data to a I2C slave device * - * This is a PoC, the formating and arguments for the GCODE will + * This is a PoC, the formatting and arguments for the GCODE will * change to be more compatible, the current proposal is: * * M260 A ; Sets the I2C slave address the data will be sent to @@ -42,34 +42,42 @@ * * M260 S1 ; Send the buffered data and reset the buffer * M260 R1 ; Reset the buffer without sending data - * */ void GcodeSuite::M260() { // Set the target address - if (parser.seen('A')) i2c.address(parser.value_byte()); + if (parser.seenval('A')) { + if (!twibus.address(parser.value_byte())) { + return; + } + } // Add a new byte to the buffer - if (parser.seen('B')) i2c.addbyte(parser.value_byte()); + if (parser.seenval('B')) twibus.addbyte(parser.value_byte()); // Flush the buffer to the bus - if (parser.seen('S')) i2c.send(); + if (parser.seen('S')) twibus.send(); // Reset and rewind the buffer - else if (parser.seen('R')) i2c.reset(); + else if (parser.seen('R')) twibus.reset(); } /** * M261: Request X bytes from I2C slave device * - * Usage: M261 A B + * Usage: M261 A B S