diff --git a/.github/contributing.md b/.github/contributing.md index 9455977528..bbf41ea1c8 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -121,7 +121,7 @@ Unsure where to begin contributing to Marlin? You can start by looking through t ### Pull Requests -Pull Requests should always be targeted to working branches (e.g., `bugfix-2.1.x` and/or `bugfix-1.1.x`) and never to release branches (e.g., `2.0.x` and/or `1.1.x`). If this is your first Pull Request, please read our [Guide to Pull Requests](https://marlinfw.org/docs/development/getting_started_pull_requests.html) and Github's [Pull Request](https://help.github.com/articles/creating-a-pull-request/) documentation. +Pull Requests should always be targeted to working branches (e.g., `bugfix-2.1.x` and/or `bugfix-1.1.x`) and never to release branches (e.g., `2.0.x` and/or `1.1.x`). If this is your first Pull Request, please read our [Guide to Pull Requests](https://marlinfw.org/docs/development/getting_started_pull_requests.html) and GitHub's [Pull Request](https://help.github.com/articles/creating-a-pull-request/) documentation. * Fill in [the required template](pull_request_template.md). * Don't include issue numbers in the PR title. diff --git a/Makefile b/Makefile index 68c522e5b6..f8a9ae3c4e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ SCRIPTS_DIR := buildroot/share/scripts +MAKESCRIPTS_DIR := buildroot/share/make CONTAINER_RT_BIN := docker CONTAINER_RT_OPTS := --rm -v $(PWD):/code -v platformio-cache:/root/.platformio CONTAINER_IMAGE := marlin-dev @@ -8,9 +9,8 @@ UNIT_TEST_CONFIG ?= default ifeq ($(OS),Windows_NT) # Windows: use `where` – fall back through the three common names PYTHON := $(shell which python 2>nul || which python3 2>nul || which py 2>nul) - # Windows: Use cmd tools to find pins files - PINS_RAW := $(shell cmd //c "dir /s /b Marlin\src\pins\*.h 2>nul | findstr /r ".*Marlin\\\\src\\\\pins\\\\.*\\\\pins_.*\.h"") - PINS := $(subst \,/,$(PINS_RAW)) + # Windows: Use Python script to find pins files + PINS := $(shell $(PYTHON) $(MAKESCRIPTS_DIR)/find.py Marlin/src/pins -mindepth 2 -name 'pins_*.h') else # POSIX: use `command -v` – prefer python3 over python PYTHON := $(shell command -v python3 2>/dev/null || command -v python 2>/dev/null) @@ -36,6 +36,7 @@ help: @echo "make validate-lines -j : Validate line endings, fails on trailing whitespace, etc." @echo "make validate-pins -j : Validate all pins files, fails if any require reformatting" @echo "make validate-boards -j : Validate boards.h and pins.h for standards compliance" + @echo "make validate-urls : Validate URLs in source files" @echo "make tests-single-ci : Run a single test from inside the CI" @echo "make tests-single-local : Run a single test locally" @echo "make tests-single-local-docker : Run a single test locally, using docker" @@ -88,7 +89,7 @@ tests-all-local: @$(PYTHON) -c "import yaml" 2>/dev/null || (echo 'pyyaml module is not installed. Install it with "$(PYTHON) -m pip install pyyaml"' && exit 1) export PATH="./buildroot/bin/:./buildroot/tests/:${PATH}" \ && export VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) \ - && for TEST_TARGET in $$($(PYTHON) $(SCRIPTS_DIR)/get_test_targets.py) ; do \ + && for TEST_TARGET in $$($(PYTHON) $(MAKESCRIPTS_DIR)/get_test_targets.py) ; do \ if [ "$$TEST_TARGET" = "linux_native" ] && [ "$$(uname)" = "Darwin" ]; then \ echo "Skipping tests for $$TEST_TARGET on macOS" ; \ continue ; \ @@ -151,7 +152,7 @@ validate-pins: format-pins @echo "Validating pins files" @git diff --exit-code || (git status && echo "\nError: Pins files are not formatted correctly. Run \"make format-pins\" to fix.\n" && exit 1) -.PHONY: format-lines validate-lines +.PHONY: format-lines validate-lines validate-urls format-lines: @echo "Formatting all sources" @@ -162,10 +163,14 @@ validate-lines: @echo "Validating text formatting" @npx prettier --check . --editorconfig --object-wrap preserve +validate-urls: + @echo "Checking URLs in source files" + @$(MAKESCRIPTS_DIR)/check-urls.sh + BOARDS_FILE := Marlin/src/core/boards.h .PHONY: validate-boards validate-boards: @echo "Validating boards.h file" - @$(PYTHON) $(SCRIPTS_DIR)/validate_boards.py $(BOARDS_FILE) || (echo "\nError: boards.h file is not valid. Please check and correct it.\n" && exit 1) + @$(PYTHON) $(MAKESCRIPTS_DIR)/validate_boards.py $(BOARDS_FILE) || (echo "\nError: boards.h file is not valid. Please check and correct it.\n" && exit 1) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index bd07add891..a443d4b302 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -61,7 +61,7 @@ // @section info // Author info of this build printed to the host during boot and M115 -#define STRING_CONFIG_H_AUTHOR "(none, default config)" // Original author or contributor. +#define STRING_CONFIG_H_AUTHOR "(MarlinFirmware)" // Original author or contributor. //#define CUSTOM_VERSION_FILE Version.h // Path from the root directory (no quotes) // @section machine @@ -468,7 +468,7 @@ //=========================================================================== //============================= Thermal Settings ============================ //=========================================================================== -// @section temperature +// @section temperature sensors /** * Temperature Sensors: @@ -500,7 +500,7 @@ * 10 : 100kΩ RS PRO 198-961 * 11 : 100kΩ Keenovo AC silicone mats, most Wanhao i3 machines - beta 3950, 1% * 12 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT (#8) - calibrated for Makibox hot bed - * 13 : 100kΩ Hisens up to 300°C - for "Simple ONE" & "All In ONE" hotend - beta 3950, 1% + * 13 : 100kΩ Hisense up to 300°C - for "Simple ONE" & "All In ONE" hotend - beta 3950, 1% * 14 : 100kΩ (R25), 4092K (beta25), 4.7kΩ pull-up, bed thermistor as used in Ender-5 S1 * 15 : 100kΩ Calibrated for JGAurora A5 hotend * 17 : 100kΩ Dagoma NTC white thermistor @@ -652,6 +652,8 @@ #define TEMP_SENSOR_REDUNDANT_MAX_DIFF 10 // (°C) Temperature difference that will trigger a print abort. #endif +// @section temperature + // Below this temperature the heater will be switched off // because it probably indicates a broken thermistor wire. #define HEATER_0_MINTEMP 5 @@ -1860,15 +1862,12 @@ //#define DISABLE_V //#define DISABLE_W -// Turn off the display blinking that warns about possible accuracy reduction -//#define DISABLE_REDUCED_ACCURACY_WARNING - // @section extruder //#define DISABLE_E // Disable the extruder when not stepping #define DISABLE_OTHER_EXTRUDERS // Keep only the active extruder enabled -// @section motion +// @section stepper drivers // Invert the stepper direction. Change (or reverse the motor connector) if an axis goes the wrong way. #define INVERT_X_DIR false @@ -1881,8 +1880,6 @@ //#define INVERT_V_DIR false //#define INVERT_W_DIR false -// @section extruder - // For direct drive extruder v9 set to true, for geared extruder set to false. #define INVERT_E0_DIR false #define INVERT_E1_DIR false @@ -2527,7 +2524,7 @@ // //#define TEMPERATURE_UNITS_SUPPORT -// @section temperature +// @section temperature presets // // Preheat Constants - Up to 10 are supported without changes diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index b8d7ed694d..e46a3af2de 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1526,6 +1526,9 @@ // @section lcd +// Turn off the display blinking that warns about possible accuracy reduction +//#define DISABLE_REDUCED_ACCURACY_WARNING + #if HAS_MANUAL_MOVE_MENU #define MANUAL_FEEDRATE { 50*60, 50*60, 4*60, 2*60 } // (mm/min) Feedrates for manual moves along X, Y, Z, E from panel #define FINE_MANUAL_MOVE 0.025 // (mm) Smallest manual move (< 0.1mm) applying to Z on most machines @@ -1887,17 +1890,21 @@ // SD Card Sorting options #if ENABLED(SDCARD_SORT_ALPHA) - #define SDSORT_REVERSE false // Default to sorting file names in reverse order. - #define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each. - #define SDSORT_FOLDERS -1 // -1=above 0=none 1=below - #define SDSORT_GCODE false // Enable G-code M34 to set sorting behaviors: M34 S<-1|0|1> F<-1|0|1> - #define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting. - #define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) - #define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option. - #define SDSORT_DYNAMIC_RAM false // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use! - #define SDSORT_CACHE_VFATS 2 // Maximum number of 13-byte VFAT entries to use for sorting. - // Note: Only affects SCROLL_LONG_FILENAMES with SDSORT_CACHE_NAMES but not SDSORT_DYNAMIC_RAM. - #define SDSORT_QUICK true // Use Quick Sort as a sorting algorithm. Otherwise use Bubble Sort. + #define SDSORT_QUICK true // Use Quick Sort as a sorting algorithm. Otherwise use Bubble Sort. + #define SDSORT_REVERSE false // Default to sorting file names in reverse order. + #define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each. + #define SDSORT_FOLDERS -1 // -1=above 0=none 1=below + #define SDSORT_GCODE false // Enable G-code M34 to set sorting behaviors: M34 S<-1|0|1> F<-1|0|1> + #define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) + #define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting. + #if ENABLED(SDSORT_USES_RAM) + #define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option. + #if ENABLED(SDSORT_CACHE_NAMES) + #define SDSORT_DYNAMIC_RAM false // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use! + #define SDSORT_CACHE_VFATS 2 // Maximum number of 13-byte VFAT entries to use for sorting. + // Note: Only affects SCROLL_LONG_FILENAMES with SDSORT_CACHE_NAMES but not SDSORT_DYNAMIC_RAM. + #endif + #endif #endif // Allow international symbols in long filenames. To display correctly, the @@ -2351,7 +2358,7 @@ //#define WATCHDOG_RESET_MANUAL #endif -// @section lcd +// @section baby-stepping /** * Babystepping enables movement of the axes by tiny increments without changing @@ -2604,13 +2611,15 @@ #endif #endif // PTC_PROBE || PTC_BED || PTC_HOTEND -// @section extras +// @section gcode // // G60/G61 Position Save and Return // //#define SAVED_POSITIONS 1 // Each saved position slot costs 12 bytes +// @section motion + // // G2/G3 Arc Support // @@ -2642,6 +2651,8 @@ */ //#define DIRECT_STEPPING +// @section calibrate + /** * G38 Probe Target * @@ -2848,7 +2859,7 @@ */ //#define EXTRA_FAN_SPEED -// @section gcode +// @section firmware retraction /** * Firmware-based and LCD-controlled retract @@ -3665,7 +3676,7 @@ //#define PHOTO_RETRACT_MM 6.5 // (mm) E retract/recover for the photo move (M240 R S) // Canon RC-1 or homebrew digital camera trigger - // Data from: https://www.doc-diy.net/photo/rc-1_hacked/ + // Data from: https://web.archive.org/web/20250327153953/www.doc-diy.net/photo/rc-1_hacked/ //#define PHOTOGRAPH_PIN 23 // Canon Hack Development Kit @@ -4302,7 +4313,7 @@ * Developed by Chris Barr at Aus3D. * * Wiki: https://wiki.aus3d.com.au/Magnetic_Encoder - * Github: https://github.com/Aus3D/MagneticEncoder + * GitHub: https://github.com/Aus3D/MagneticEncoder * * Supplier: https://aus3d.com.au/products/magnetic-encoder-module * Alternative Supplier: https://reliabuild3d.com/ diff --git a/Marlin/Version.h b/Marlin/Version.h index 926bddf13f..3ebdc70bf4 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2025-12-14" +//#define STRING_DISTRIBUTION_DATE "2025-12-25" /** * The protocol for communication to the host. Protocol indicates communication @@ -58,7 +58,7 @@ /** * The SOURCE_CODE_URL is the location where users will find the Marlin Source * Code which is installed on the device. In most cases —unless the manufacturer - * has a distinct Github fork— the Source Code URL should just be the main + * has a distinct GitHub fork— the Source Code URL should just be the main * Marlin repository. */ //#define SOURCE_CODE_URL "github.com/MarlinFirmware/Marlin" diff --git a/Marlin/src/HAL/AVR/HAL.cpp b/Marlin/src/HAL/AVR/HAL.cpp index 4fbab8941f..1fa7222711 100644 --- a/Marlin/src/HAL/AVR/HAL.cpp +++ b/Marlin/src/HAL/AVR/HAL.cpp @@ -96,7 +96,7 @@ void MarlinHAL::init() { // Might disable other peripherals using the pin; to circumvent that please undefine one of the above things! // The true culprit is the AVR ArduinoCore that enables peripherals redundantly. // (USART1 on the GeeeTech GT2560) - // https://www.youtube.com/watch?v=jMgCvRXkexk + // https://youtube.be/jMgCvRXkexk _ATmega_savePinAlternate(BEEPER_PIN); OUT_WRITE(BEEPER_PIN, LOW); diff --git a/Marlin/src/HAL/DUE/Tone.cpp b/Marlin/src/HAL/DUE/Tone.cpp index 4bc8142aba..743cae9d70 100644 --- a/Marlin/src/HAL/DUE/Tone.cpp +++ b/Marlin/src/HAL/DUE/Tone.cpp @@ -24,7 +24,7 @@ /** * Description: Tone function for Arduino Due and compatible (SAM3X8E) - * Derived from https://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012 + * Derived from https://forum.arduino.cc/t/arduino-due-and-tone/133302/13 */ #ifdef ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/ESP32/Tone.cpp b/Marlin/src/HAL/ESP32/Tone.cpp index 839c612b6a..1bb0840129 100644 --- a/Marlin/src/HAL/ESP32/Tone.cpp +++ b/Marlin/src/HAL/ESP32/Tone.cpp @@ -24,7 +24,7 @@ /** * Description: Tone function for ESP32 - * Derived from https://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012 + * Derived from https://forum.arduino.cc/t/arduino-due-and-tone/133302/13 */ #ifdef ARDUINO_ARCH_ESP32 diff --git a/Marlin/src/HAL/GD32_MFL/timers.cpp b/Marlin/src/HAL/GD32_MFL/timers.cpp index 13a5c166ef..3bcfdd464b 100644 --- a/Marlin/src/HAL/GD32_MFL/timers.cpp +++ b/Marlin/src/HAL/GD32_MFL/timers.cpp @@ -69,10 +69,6 @@ #endif #endif -#ifndef HAL_TIMER_RATE - #define HAL_TIMER_RATE GetStepperTimerClkFreq() -#endif - #ifndef STEP_TIMER #define STEP_TIMER MF_TIMER_STEP #endif diff --git a/Marlin/src/HAL/GD32_MFL/timers.h b/Marlin/src/HAL/GD32_MFL/timers.h index 1c69c0b468..8aff77aa96 100644 --- a/Marlin/src/HAL/GD32_MFL/timers.h +++ b/Marlin/src/HAL/GD32_MFL/timers.h @@ -37,15 +37,18 @@ typedef uint32_t hal_timer_t; #define HAL_TIMER_TYPE_MAX hal_timer_t(UINT16_MAX) -extern uint32_t GetStepperTimerClkFreq(); +#ifndef HAL_TIMER_RATE + extern uint32_t GetStepperTimerClkFreq(); + #define HAL_TIMER_RATE GetStepperTimerClkFreq() +#endif // Timer configuration constants #define STEPPER_TIMER_RATE 2000000 #define TEMP_TIMER_FREQUENCY 1000 // Timer prescaler calculations -#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / STEPPER_TIMER_RATE) // Prescaler = 30 -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs +#define STEPPER_TIMER_PRESCALE ((HAL_TIMER_RATE) / (STEPPER_TIMER_RATE)) // Prescaler = 30 +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs // Pulse Timer (counter) calculations #define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer diff --git a/Marlin/src/HAL/HC32/README.md b/Marlin/src/HAL/HC32/README.md index ed11c40035..1161e881f6 100644 --- a/Marlin/src/HAL/HC32/README.md +++ b/Marlin/src/HAL/HC32/README.md @@ -53,7 +53,7 @@ Just searching for `SCB->VTOR` should yield some results. From there, you just n > Some vendors publish incomplete source code. But they sometimes leave version control related files in the repo, which can contain previous version of files that were removed. Find these by including folders like `.git` or `.svn` in your search. > [!NOTE] -> The example is based on the [Voxelab-64/Aquila_X2](https://github.com/Voxelab-64/Aquila_X2/blob/d1f23adf96920996b979bc31023d1dce236d05db/firmware/Sources/.svn/pristine/ec/ec82bcb480b511906bc3e6658450e3a803ab9813.svn-base#L96) which actually includes deleted files in its repo. +> The example is based on the [Voxelab-64/Aquila_X2](https://github.com/Voxelab-64/Aquila_X2/blob/main/firmware/Sources/.svn/pristine/ec/ec82bcb480b511906bc3e6658450e3a803ab9813.svn-base#L96) which actually includes deleted files in its repo. 2. Using a linker script diff --git a/Marlin/src/HAL/LPC1768/HAL_SPI.cpp b/Marlin/src/HAL/LPC1768/HAL_SPI.cpp index 6ce7f75552..15ace81dc2 100644 --- a/Marlin/src/HAL/LPC1768/HAL_SPI.cpp +++ b/Marlin/src/HAL/LPC1768/HAL_SPI.cpp @@ -40,10 +40,6 @@ * SPI sharing pins. The SCK, MOSI & MISO pins can NOT be set/cleared with * WRITE nor digitalWrite when the hardware SPI module within the LPC17xx is * active. If any of these pins are shared then the software SPI must be used. - * - * A more sophisticated hardware SPI can be found at the following link. - * This implementation has not been fully debugged. - * https://github.com/MarlinFirmware/Marlin/tree/071c7a78f27078fd4aee9a3ef365fcf5e143531e */ #ifdef TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c b/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c index c489c16e5e..281c920b12 100644 --- a/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c +++ b/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c @@ -22,7 +22,7 @@ /** * digipot_mcp4451_I2C_routines.c - * Adapted from https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html + * Adapted from https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html */ #ifdef TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.h b/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.h index 9b6c62b052..4da863389a 100644 --- a/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.h +++ b/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.h @@ -23,7 +23,7 @@ /** * digipot_mcp4451_I2C_routines.h - * Adapted from https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html + * Adapted from https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html */ #ifdef __cplusplus diff --git a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp index 09603de972..3fc973e9f5 100644 --- a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp @@ -21,7 +21,7 @@ */ // adapted from I2C/master/master.c example -// https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html +// https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html #ifdef TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/upload_extra_script.py b/Marlin/src/HAL/LPC1768/upload_extra_script.py index f9be140592..6755245436 100755 --- a/Marlin/src/HAL/LPC1768/upload_extra_script.py +++ b/Marlin/src/HAL/LPC1768/upload_extra_script.py @@ -41,8 +41,8 @@ if pioutil.is_pio_build(): from ctypes import windll from pathlib import PureWindowsPath - # getting list of drives - # https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python + # Getting a list of drives + # https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-windows-drives drives = [] bitmask = windll.kernel32.GetLogicalDrives() for letter in string.ascii_uppercase: diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.cpp index 745454394a..8033b79e3d 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.cpp @@ -21,7 +21,7 @@ */ // adapted from I2C/master/master.c example -// https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html +// https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html #ifdef __PLAT_NATIVE_SIM__ diff --git a/Marlin/src/HAL/RP2040/HAL.cpp b/Marlin/src/HAL/RP2040/HAL.cpp index 9341480078..51f68648bc 100644 --- a/Marlin/src/HAL/RP2040/HAL.cpp +++ b/Marlin/src/HAL/RP2040/HAL.cpp @@ -28,6 +28,7 @@ #include "../../inc/MarlinConfig.h" #include "../shared/Delay.h" +#include "../../module/temperature.h" // For OVERSAMPLENR extern "C" { #include "pico/bootrom.h" @@ -41,50 +42,38 @@ extern "C" { #include "msc_sd.h" #endif -// Core 1 watchdog configuration -#define CORE1_MAX_RESETS 5 // Maximum number of Core 1 resets before halting system - // ------------------------ // Public Variables // ------------------------ volatile uint32_t adc_accumulators[5] = {0}; // Accumulators for oversampling (sum of readings) volatile uint8_t adc_counts[5] = {0}; // Count of readings accumulated per channel -volatile uint16_t adc_values[5] = {512, 512, 512, 512, 512}; // Final oversampled ADC values (averages) - initialized to mid-range +volatile uint16_t adc_values[5] = {4095, 4095, 4095, 4095, 4095}; // Averaged ADC values (single reading equivalent) - initialized to max (open circuit) -// Core 1 watchdog monitoring +// Core monitoring for watchdog +volatile uint32_t core0_last_heartbeat = 0; // Timestamp of Core 0's last activity volatile uint32_t core1_last_heartbeat = 0; // Timestamp of Core 1's last activity -volatile bool core1_watchdog_triggered = false; // Flag to indicate Core 1 reset -volatile uint8_t core1_reset_count = 0; // Count of Core 1 resets - halt system if >= CORE1_MAX_RESETS +#if ENABLED(MARLIN_DEV_MODE) + volatile bool core1_freeze_test = false; // Flag to freeze Core 1 for watchdog testing +#endif volatile uint8_t current_pin; volatile bool MarlinHAL::adc_has_result; volatile uint8_t adc_channels_enabled[5] = {false}; // Track which ADC channels are enabled -// Helper function for LED blinking patterns -void blink_led_pattern(uint8_t blink_count, uint32_t blink_duration_us = 100000) { - #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) - for (uint8_t i = 0; i < blink_count; i++) { - WRITE(LED_PIN, HIGH); - busy_wait_us(blink_duration_us); - WRITE(LED_PIN, LOW); - if (i < blink_count - 1) { // Don't delay after the last blink - busy_wait_us(blink_duration_us); - } - } - #endif -} - // Core 1 ADC reading task - dynamically reads all enabled channels with oversampling void core1_adc_task() { - static uint32_t last_led_toggle = 0; - const uint8_t OVERSAMPLENR = 16; // Standard Marlin oversampling count - - // Signal successful Core 1 startup/restart - SERIAL_ECHO_MSG("Core 1 ADC task started"); + static uint32_t last_temp_update = 0; while (true) { - // Update heartbeat timestamp at start of each scan cycle - core1_last_heartbeat = time_us_32(); + #if ENABLED(MARLIN_DEV_MODE) + // Check if we should freeze for watchdog test + if (core1_freeze_test) { + // Stop updating heartbeat and spin forever + while (core1_freeze_test) { + busy_wait_us(100000); // 100ms delay + } + } + #endif // Scan all enabled ADC channels for (uint8_t channel = 0; channel < 5; channel++) { @@ -114,11 +103,9 @@ void core1_adc_task() { adc_accumulators[channel] += reading; adc_counts[channel]++; - // Update the averaged value with current accumulation (provides immediate valid data) - adc_values[channel] = adc_accumulators[channel] / adc_counts[channel]; - - // When we reach the full oversampling count, reset accumulator for next cycle + // When we reach the full oversampling count, calculate averaged value (Marlin ISR does its own oversampling) if (adc_counts[channel] >= OVERSAMPLENR) { + adc_values[channel] = adc_accumulators[channel] / OVERSAMPLENR; // Return single-reading equivalent adc_accumulators[channel] = 0; adc_counts[channel] = 0; } @@ -129,17 +116,19 @@ void core1_adc_task() { } } - // Core 1 LED indicator: Double blink every 2 seconds to show Core 1 is active + // Core 1 just provides ADC readings - don't trigger temperature updates from here + // Let Marlin's main temperature ISR on Core 0 handle the timing and updates uint32_t now = time_us_32(); - if (now - last_led_toggle >= 2000000) { // 2 seconds - last_led_toggle = now; - #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) - // Triple blink pattern if watchdog was triggered (shows Core 1 was reset) - if (core1_watchdog_triggered) { - core1_watchdog_triggered = false; // Clear flag - blink_led_pattern(3); // Triple blink for watchdog reset - } else { - blink_led_pattern(2); // Normal double blink + if (now - last_temp_update >= 100000) { // 100ms = 100000 microseconds + last_temp_update = now; + #if ENABLED(USE_WATCHDOG) + // Refresh watchdog here like AVR ISR does indirectly via temperature updates + // Use 2 second delay to allow watchdog_init to be called during boot + static uint32_t core1_start_time = 0; + if (core1_start_time == 0) core1_start_time = time_us_32(); + + if (time_us_32() - core1_start_time > 2000000) { + hal.watchdog_refresh(1); // Refresh from Core 1 } #endif } @@ -219,37 +208,42 @@ void MarlinHAL::reboot() { watchdog_reboot(0, 0, 1); } void MarlinHAL::watchdog_init() { #if DISABLED(DISABLE_WATCHDOG_INIT) static_assert(WDT_TIMEOUT_US > 1000, "WDT Timeout is too small, aborting"); + // Initialize Core 0 heartbeat + core0_last_heartbeat = time_us_32(); watchdog_enable(WDT_TIMEOUT_US/1000, true); #endif } - void MarlinHAL::watchdog_refresh() { - // If Core 1 has reset CORE1_MAX_RESETS+ times, stop updating watchdog to halt system - if (core1_reset_count >= CORE1_MAX_RESETS) { - SERIAL_ECHO_MSG("Core 1 reset limit exceeded (", core1_reset_count, " resets) - halting system for safety"); - return; // Don't update watchdog - system will halt + void MarlinHAL::watchdog_refresh(const uint8_t core/*=0*/) { + if (core == 0) { + // Update Core 0 heartbeat + core0_last_heartbeat = time_us_32(); + + // Check if Core 1 is alive (2 second timeout) + if (time_us_32() - core1_last_heartbeat < 2000000) { + watchdog_update(); // Only refresh if Core 1 is responding + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + TOGGLE(LED_PIN); // Heartbeat indicator + #endif + } + // If Core 1 is stuck, don't refresh - let watchdog reset the system } + else { + // Update Core 1 heartbeat + core1_last_heartbeat = time_us_32(); - watchdog_update(); - - // Check Core 1 watchdog (15 second timeout) - uint32_t now = time_us_32(); - if (now - core1_last_heartbeat > 15000000) { // 15 seconds - // Core 1 appears stuck - reset it - multicore_reset_core1(); - multicore_launch_core1(core1_adc_task); - core1_watchdog_triggered = true; // Signal for LED indicator - core1_reset_count++; // Increment reset counter - SERIAL_ECHO_MSG("Core 1 ADC watchdog triggered - resetting Core 1 (attempt ", core1_reset_count, ")"); + // Check if Core 0 is alive (2 second timeout) + if (time_us_32() - core0_last_heartbeat < 2000000) { + watchdog_update(); // Only refresh if Core 0 is responding + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + TOGGLE(LED_PIN); // Heartbeat indicator + #endif + } + // If Core 0 is stuck, don't refresh - let watchdog reset the system } - - #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) - // Core 0 LED indicator: Single toggle every watchdog refresh (shows Core 0 activity) - TOGGLE(LED_PIN); - #endif } -#endif +#endif // USE_WATCHDOG // ------------------------ // ADC @@ -290,13 +284,15 @@ void flashFirmware(const int16_t) { hal.reboot(); } extern "C" { void * _sbrk(int incr); - extern unsigned int __bss_end__; // end of bss section + extern unsigned int __StackLimit; // Lowest address the stack can grow to } -// Return free memory between end of heap (or end bss) and whatever is current +// Return free memory between end of heap and start of stack int freeMemory() { - int free_memory, heap_end = (int)_sbrk(0); - return (int)&free_memory - (heap_end ?: (int)&__bss_end__); + void* heap_end = _sbrk(0); + // Use the linker-provided stack limit instead of a local variable + // __StackLimit is the lowest address the stack can grow to + return (char*)&__StackLimit - (char*)heap_end; } #endif // __PLAT_RP2040__ diff --git a/Marlin/src/HAL/RP2040/HAL.h b/Marlin/src/HAL/RP2040/HAL.h index a1305bd135..a49b343899 100644 --- a/Marlin/src/HAL/RP2040/HAL.h +++ b/Marlin/src/HAL/RP2040/HAL.h @@ -51,6 +51,28 @@ #include "MarlinSerial.h" +#if !WITHIN(SERIAL_PORT, -1, 1) + #error "SERIAL_PORT must be from -1 to 1." +#endif + +#ifdef SERIAL_PORT_2 + #if !WITHIN(SERIAL_PORT_2, -1, 1) + #error "SERIAL_PORT_2 must be from -1 to 1." + #endif +#endif + +#ifdef SERIAL_PORT_3 + #if !WITHIN(SERIAL_PORT_3, -1, 1) + #error "SERIAL_PORT_3 must be from -1 to 1." + #endif +#endif + +#ifdef LCD_SERIAL_PORT + #if !WITHIN(LCD_SERIAL_PORT, -1, 1) + #error "LCD_SERIAL_PORT must be from -1 to 1." + #endif +#endif + // ------------------------ // Defines // ------------------------ @@ -131,7 +153,7 @@ public: // Watchdog static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); - static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh(const uint8_t=0) IF_DISABLED(USE_WATCHDOG, {}); static void init(); // Called early in setup() static void init_board() {} // Called less early in setup() diff --git a/Marlin/src/HAL/RP2040/MarlinSerial.cpp b/Marlin/src/HAL/RP2040/MarlinSerial.cpp index dd01edd830..5e3bf0c148 100644 --- a/Marlin/src/HAL/RP2040/MarlinSerial.cpp +++ b/Marlin/src/HAL/RP2040/MarlinSerial.cpp @@ -30,10 +30,40 @@ #include "../../feature/e_parser.h" #endif -#define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) -#define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) - IMPLEMENT_SERIAL(SERIAL_PORT); +#include + +// Marlin uses: -1=USB, 0=UART0, 1=UART1 +// Arduino uses: Serial=USB, Serial1=UART0, Serial2=UART1 +// +// To remap Arduino's numbering to Marlin's convention, we create MarlinSerial0/MarlinSerial1 +// as new UART instances with custom pins. +// +// We use distinct names (MarlinSerial0/MarlinSerial1) to avoid symbol conflicts with +// the Arduino framework's pre-defined Serial1/Serial2 objects, which use the same +// underlying hardware (_UART0_ and _UART1_). + +// Create Serial0 as UART0 with custom or default pins +arduino::UART MarlinSerial0( + #if PINS_EXIST(SERIAL0_TX, SERIAL0_RX) + SERIAL0_TX_PIN, SERIAL0_RX_PIN // Custom pins for UART0 (Marlin Serial0) + #else + 0, 1 // Default UART0 pins (GP0/GP1) + #endif +); + +// Not using PINS_EXIST(SERIAL1_TX, SERIAL1_RX) because SERIAL1_TX and SERIAL1_RX +// are defined in framework-arduino-mbed/variants/RASPBERRY_PI_PICO/pins_arduino.h + +// Create Serial1 as UART1 with custom or default pins +#if defined(SERIAL1_TX_PIN) && defined(SERIAL1_RX_PIN) + arduino::UART MarlinSerial1(SERIAL1_TX_PIN, SERIAL1_RX_PIN); // Custom pins for UART1 (Marlin Serial1) #endif +// Wrap the serial ports for Marlin +DefaultSerial0 MSerial0(false, MarlinSerial0); // Marlin Serial0 = UART0 +#if defined(SERIAL1_TX_PIN) && defined(SERIAL1_RX_PIN) + DefaultSerial1 MSerial1(false, MarlinSerial1); // Marlin Serial1 = UART1 +#endif +DefaultSerial2 MSerial2(false, Serial); // Marlin Serial2 = USB (-1) + #endif // __PLAT_RP2040__ diff --git a/Marlin/src/HAL/RP2040/MarlinSerial.h b/Marlin/src/HAL/RP2040/MarlinSerial.h index b0db3167fa..f407a838df 100644 --- a/Marlin/src/HAL/RP2040/MarlinSerial.h +++ b/Marlin/src/HAL/RP2040/MarlinSerial.h @@ -29,20 +29,50 @@ #include "../../core/serial_hook.h" -typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; -extern DefaultSerial1 MSerial0; +/** + * Serial Port Configuration for RP2040 (Raspberry Pi Pico) + * + * Arduino-Pico Core Serial Objects: + * - Serial: USB Serial (CDC ACM) + * - Serial1: Hardware UART0 + * - Serial2: Hardware UART1 + * - SerialUSB: Alias for Serial (USB) + * + * Marlin Serial Wrappers: + * - MSerial0: Wrapper for MarlinSerial0 (UART0), used as Serial0 + * - MSerial1: Wrapper for MarlinSerial1 (UART1), declared dynamically if used + * - MSerial2: Wrapper for Serial (USB) + * - USBSerial: Wrapper for SerialUSB (USB) + * + * How it all joins together: + * - Configuration defines SERIAL_PORT, SERIAL_PORT_2, etc. (-1 to 1 range) + * - shared/serial_ports.h maps these to MYSERIAL1, MYSERIAL2, etc. + * - MYSERIAL1 uses MSerialX based on the port index + * - USB ports (-1) use USB_SERIAL_PORT (MSerial2) + */ + +// Forward declare our custom Serial objects (defined in MarlinSerial.cpp) +namespace arduino { class UART; } +extern arduino::UART MarlinSerial0; // Always declared +extern arduino::UART MarlinSerial1; // Custom Marlin Serial1 to avoid conflict + +typedef ForwardSerial1Class< decltype(MarlinSerial0) > DefaultSerial0; +extern DefaultSerial0 MSerial0; +typedef ForwardSerial1Class< decltype(MarlinSerial1) > DefaultSerial1; +extern DefaultSerial1 MSerial1; +typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial2; +extern DefaultSerial2 MSerial2; typedef ForwardSerial1Class USBSerialType; extern USBSerialType USBSerial; -#define Serial0 Serial #define _DECLARE_SERIAL(X) \ - typedef ForwardSerial1Class DefaultSerial##X; \ + typedef ForwardSerial1Class DefaultSerial##X; \ extern DefaultSerial##X MSerial##X #define DECLARE_SERIAL(X) _DECLARE_SERIAL(X) #define SERIAL_INDEX_MIN 0 -#define SERIAL_INDEX_MAX 6 -#define USB_SERIAL_PORT(...) MSerial0 +#define SERIAL_INDEX_MAX 1 +#define USB_SERIAL_PORT(...) MSerial2 #include "../shared/serial_ports.h" #if defined(LCD_SERIAL_PORT) && ANY(HAS_DGUS_LCD, EXTENSIBLE_UI) diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp index 41da7c10fc..7cbedd84fc 100644 --- a/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp @@ -25,7 +25,7 @@ * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) */ // adapted from I2C/master/master.c example -// https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html +// https://www-users.york.ac.uk/~pcc1/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html #ifdef __SAMD21__ diff --git a/Marlin/src/HAL/STM32/timers.cpp b/Marlin/src/HAL/STM32/timers.cpp index b4271d3a58..5b58a915f0 100644 --- a/Marlin/src/HAL/STM32/timers.cpp +++ b/Marlin/src/HAL/STM32/timers.cpp @@ -81,10 +81,6 @@ #define MCU_TEMP_TIMER 14 // TIM7 is consumed by Software Serial if used. #endif -#ifndef HAL_TIMER_RATE - #define HAL_TIMER_RATE GetStepperTimerClkFreq() -#endif - #ifndef STEP_TIMER #define STEP_TIMER MCU_STEP_TIMER #endif diff --git a/Marlin/src/HAL/STM32/timers.h b/Marlin/src/HAL/STM32/timers.h index 7b55f8a52d..a6c9204a77 100644 --- a/Marlin/src/HAL/STM32/timers.h +++ b/Marlin/src/HAL/STM32/timers.h @@ -48,13 +48,18 @@ #define TIMER_INDEX_(T) TIMER##T##_INDEX // TIMER#_INDEX enums (timer_index_t) depend on TIM#_BASE defines. #define TIMER_INDEX(T) TIMER_INDEX_(T) // Convert Timer ID to HardwareTimer_Handle index. -#define TEMP_TIMER_FREQUENCY 1000 // Temperature::isr() is expected to be called at around 1kHz +#ifndef HAL_TIMER_RATE + extern uint32_t GetStepperTimerClkFreq(); + #define HAL_TIMER_RATE GetStepperTimerClkFreq() +#endif -// TODO: get rid of manual rate/prescale/ticks/cycles taken for procedures in stepper.cpp -#define STEPPER_TIMER_RATE 2'000'000 // 2 Mhz -extern uint32_t GetStepperTimerClkFreq(); -#define STEPPER_TIMER_PRESCALE (GetStepperTimerClkFreq() / (STEPPER_TIMER_RATE)) -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (MHz) Stepper Timer ticks per µs +// Timer configuration constants +#define STEPPER_TIMER_RATE 2000000 +#define TEMP_TIMER_FREQUENCY 1000 // Temperature::isr() should run at ~1kHz + +// Timer prescaler calculations +#define STEPPER_TIMER_PRESCALE ((HAL_TIMER_RATE) / (STEPPER_TIMER_RATE)) +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000UL) // (ticks/μs) Stepper Timer ticks per µs // Pulse Timer (counter) calculations #define PULSE_TIMER_RATE STEPPER_TIMER_RATE // (Hz) Frequency of Pulse Timer diff --git a/Marlin/src/HAL/shared/Delay.cpp b/Marlin/src/HAL/shared/Delay.cpp index bfcf6bcc42..5aa3a235fd 100644 --- a/Marlin/src/HAL/shared/Delay.cpp +++ b/Marlin/src/HAL/shared/Delay.cpp @@ -85,7 +85,7 @@ } else { // Enable DWT counter - // From https://stackoverflow.com/a/41188674/1469714 + // From https://stackoverflow.com/questions/36378280/stm32-how-to-enable-dwt-cycle-counter/41188674#41188674 HW_REG(_DEM_CR) = HW_REG(_DEM_CR) | 0x01000000; // Enable trace #if __CORTEX_M == 7 HW_REG(_LAR) = 0xC5ACCE55; // Unlock access to DWT registers, see https://developer.arm.com/documentation/ihi0029/e/ section B2.3.10 diff --git a/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp b/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp index f4435c733e..43a086589b 100644 --- a/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp +++ b/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp @@ -66,7 +66,7 @@ void * hook_get_usagefault_vector_address(unsigned vtor) { return (void*)(vtor + void * hook_get_reserved_vector_address(unsigned vtor) { return (void*)(vtor + 0x07); } // Common exception frame for ARM, should work for all ARM CPU -// Described here (modified for convenience): https://interrupt.memfault.com/blog/cortex-m-fault-debug +// Described here (modified for convenience): https://interrupt.memfault.com/blog/cortex-m-hardfault-debug struct __attribute__((packed)) ContextStateFrame { uint32_t r0; uint32_t r1; diff --git a/Marlin/src/core/mstring.h b/Marlin/src/core/mstring.h index 1e540a5a5a..3ed21950de 100644 --- a/Marlin/src/core/mstring.h +++ b/Marlin/src/core/mstring.h @@ -158,16 +158,16 @@ public: MString& append_P(PGM_P const s) { int sz = length(); if (sz < SIZE) strlcpy_P(str + sz, s, SIZE - sz + 1); debug(F("pstring")); return *this; } MString& append(FSTR_P const f) { return append_P(FTOP(f)); } MString& append(const bool &b) { return append(b ? F("true") : F("false")); } - MString& append(const char c) { int sz = length(); if (sz < SIZE) { str[sz] = c; if (sz < SIZE - 1) str[sz + 1] = '\0'; } return *this; } + MString& append(const char c) { int sz = length(); if (sz < SIZE) { str[sz] = c; if (sz < SIZE - 1) str[sz + 1] = '\0'; } debug(F("char")); return *this; } #if ENABLED(FASTER_APPEND) - MString& append(const int8_t &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; } - MString& append(const short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; } - MString& append(const int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); return *this; } - MString& append(const long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%ld", l); return *this; } - MString& append(const unsigned char &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; } - MString& append(const unsigned short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; } - MString& append(const unsigned int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); return *this; } - MString& append(const unsigned long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%lu", l); return *this; } + MString& append(const int8_t &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); debug(F("int8_t")); return *this; } + MString& append(const short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); debug(F("short")); return *this; } + MString& append(const int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%d", i); debug(F("int")); return *this; } + MString& append(const long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%ld", l); debug(F("long")); return *this; } + MString& append(const unsigned char &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); debug(F("uchar")); return *this; } + MString& append(const unsigned short &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); debug(F("ushort")); return *this; } + MString& append(const unsigned int &i) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%u", i); debug(F("uint")); return *this; } + MString& append(const unsigned long &l) { int sz = length(); SNPRINTF(&str[sz], SIZE - sz, "%lu", l); debug(F("ulong")); return *this; } #else MString& append(const int8_t &i) { char buf[ 5]; sprintf(buf, "%d", i); return append(buf); } MString& append(const short &i) { char buf[12]; sprintf(buf, "%d", i); return append(buf); } diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index 7008d04c53..b4d7705ffd 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -557,7 +557,7 @@ struct XYval { #endif // Length reduced to one dimension - FI constexpr T magnitude() const { return (T)sqrtf(x*x + y*y); } + FI constexpr T magnitude() const { return (T)SQRT(x*x + y*y); } // Pointer to the data as a simple array explicit FI operator T* () { return pos; } // If any element is true then it's true @@ -734,7 +734,7 @@ struct XYZval { #endif // Length reduced to one dimension - FI constexpr T magnitude() const { return (T)TERN(HAS_X_AXIS, sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)), 0); } + FI constexpr T magnitude() const { return (T)TERN(HAS_X_AXIS, SQRT(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)), 0); } // Pointer to the data as a simple array explicit FI operator T* () { return pos; } // If any element is true then it's true @@ -905,7 +905,7 @@ struct XYZEval { #endif // Length reduced to one dimension - FI constexpr T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } + FI constexpr T magnitude() const { return (T)SQRT(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } // Pointer to the data as a simple array explicit FI operator T* () { return pos; } // If any element is true then it's true diff --git a/Marlin/src/feature/mmu3/mmu3.cpp b/Marlin/src/feature/mmu3/mmu3.cpp index 9727c07829..dd06126724 100644 --- a/Marlin/src/feature/mmu3/mmu3.cpp +++ b/Marlin/src/feature/mmu3/mmu3.cpp @@ -38,7 +38,6 @@ #include "mmu3_progress_converter.h" #include "mmu3_reporting.h" -#include "strlen_cx.h" #include "SpoolJoin.h" #include "../../inc/MarlinConfig.h" diff --git a/Marlin/src/feature/mmu3/mmu3_power.cpp b/Marlin/src/feature/mmu3/mmu3_power.cpp index da905c6e29..1782cb49fc 100644 --- a/Marlin/src/feature/mmu3/mmu3_power.cpp +++ b/Marlin/src/feature/mmu3/mmu3_power.cpp @@ -39,26 +39,26 @@ namespace MMU3 { -// On MK3 we cannot do actual power cycle on HW. Instead trigger a hardware reset. -void power_on() { - #if PIN_EXISTS(MMU_RST) - OUT_WRITE(MMU_RST_PIN, HIGH); - #endif - power_reset(); -} + // On MK3 we cannot do actual power cycle on HW. Instead trigger a hardware reset. + void power_on() { + #if PIN_EXISTS(MMU_RST) + OUT_WRITE(MMU_RST_PIN, HIGH); + #endif + power_reset(); + } -void power_off() {} + void power_off() {} -void power_reset() { - #if PIN_EXISTS(MMU_RST) // HW - pulse reset pin - WRITE(MMU_RST_PIN, LOW); - safe_delay(100); - WRITE(MMU_RST_PIN, HIGH); - #else - mmu3.reset(MMU3::Software); // TODO: Needs redesign. This power implementation shouldn't know anything about the MMU itself - #endif - // otherwise HW reset is not available -} + void power_reset() { + #if PIN_EXISTS(MMU_RST) // HW - pulse reset pin + WRITE(MMU_RST_PIN, LOW); + safe_delay(100); + WRITE(MMU_RST_PIN, HIGH); + #else + mmu3.reset(MMU3::Software); // TODO: Needs redesign. This power implementation shouldn't know anything about the MMU itself + #endif + // otherwise HW reset is not available + } } // MMU3 diff --git a/Marlin/src/feature/mmu3/mmu3_power.h b/Marlin/src/feature/mmu3/mmu3_power.h index 4f6b94f01e..77259073a1 100644 --- a/Marlin/src/feature/mmu3/mmu3_power.h +++ b/Marlin/src/feature/mmu3/mmu3_power.h @@ -26,11 +26,7 @@ */ namespace MMU3 { - -void power_on(); - -void power_off(); - -void power_reset(); - -} // MMU3 + void power_on(); + void power_off(); + void power_reset(); +} diff --git a/Marlin/src/feature/mmu3/mmu3_reporting.cpp b/Marlin/src/feature/mmu3/mmu3_reporting.cpp index b0527937ea..c9b9dbe554 100644 --- a/Marlin/src/feature/mmu3/mmu3_reporting.cpp +++ b/Marlin/src/feature/mmu3/mmu3_reporting.cpp @@ -353,17 +353,18 @@ namespace MMU3 { // Render the choices //if (two_choices) { // lcd_show_choices_prompt_P( - // LCD_LEFT_BUTTON_CHOICE, - // PrusaErrorButtonTitle(button_op_middle), - // GET_TEXT(MSG_BTN_MORE), - // 18, nullptr + // LCD_LEFT_BUTTON_CHOICE, + // PrusaErrorButtonTitle(button_op_middle), + // GET_TEXT(MSG_BTN_MORE), + // 18, nullptr // ); //} //else { - // lcd_show_choices_prompt_P(LCD_MIDDLE_BUTTON_CHOICE, - // PrusaErrorButtonTitle(button_op_middle), - // PrusaErrorButtonTitle(button_op_right), - // 9, GET_TEXT(MSG_BTN_MORE) + // lcd_show_choices_prompt_P( + // LCD_MIDDLE_BUTTON_CHOICE, + // PrusaErrorButtonTitle(button_op_middle), + // PrusaErrorButtonTitle(button_op_right), + // 9, GET_TEXT(MSG_BTN_MORE) // ); //} @@ -526,7 +527,7 @@ namespace MMU3 { #if HAS_WIRED_LCD // Set the cursor position each time in case some other // part of the firmware changes the cursor position - lcd_insert_char_into_status(col, sensorState ? LCD_STR_SOLID_BLOCK[0] : '-'); + lcd_replace_status_char(col, sensorState ? LCD_STR_SOLID_BLOCK[0] : '-'); if (ui.lcdDrawUpdate == LCDViewAction::LCDVIEW_NONE) ui.draw_status_message(false); #endif @@ -535,7 +536,7 @@ namespace MMU3 { void TryLoadUnloadReporter::Progress(bool sensorState) { // Always round up, you can only have 'whole' pixels. (floor is also an option) dpixel1 = ceil((stepper_get_machine_position_E_mm() - planner_get_current_position_E()) * pixel_per_mm); - if (dpixel1 - dpixel0) { + if (dpixel1 != dpixel0) { dpixel0 = dpixel1; if (lcd_cursor_col > (LCD_WIDTH - 1)) lcd_cursor_col = LCD_WIDTH - 1; Render(lcd_cursor_col++, sensorState); diff --git a/Marlin/src/feature/mmu3/mmu_hw/errors_list.h b/Marlin/src/feature/mmu3/mmu_hw/errors_list.h index 7fb93b0771..9cfdba2283 100644 --- a/Marlin/src/feature/mmu3/mmu_hw/errors_list.h +++ b/Marlin/src/feature/mmu3/mmu_hw/errors_list.h @@ -37,7 +37,6 @@ #include #endif #include "buttons.h" -#include "../strlen_cx.h" #include "../ultralcd.h" namespace MMU3 { diff --git a/Marlin/src/feature/mmu3/strlen_cx.h b/Marlin/src/feature/mmu3/strlen_cx.h deleted file mode 100644 index 6ac2a84b42..0000000000 --- a/Marlin/src/feature/mmu3/strlen_cx.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * 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 . - * - */ -#pragma once - -/** - * strlen_cx.h - */ - -constexpr inline int strlen_constexpr(const char *str) { - return *str ? 1 + strlen_constexpr(str + 1) : 0; -} diff --git a/Marlin/src/feature/mmu3/ultralcd.cpp b/Marlin/src/feature/mmu3/ultralcd.cpp index 3b8f52beb3..d3cd3d371e 100644 --- a/Marlin/src/feature/mmu3/ultralcd.cpp +++ b/Marlin/src/feature/mmu3/ultralcd.cpp @@ -37,181 +37,175 @@ #include "../../gcode/gcode.h" #include "../../lcd/marlinui.h" - //! @brief Show a two-choice prompt on the last line of the LCD - //! @param selected Show first choice as selected if true, the second otherwise - //! @param first_choice text caption of first possible choice - //! @param second_choice text caption of second possible choice - //! @param second_col column on LCD where second choice is rendered. - //! @param third_choice text caption of third, optional, choice. - void lcd_show_choices_prompt_P(uint8_t selected, const char *first_choice, const char *second_choice, uint8_t second_col, const char *third_choice) { - lcd_put_lchar(0, 3, selected == LCD_LEFT_BUTTON_CHOICE ? '>' : ' '); - lcd_put_u8str(first_choice); - lcd_put_lchar(second_col, 3, selected == LCD_MIDDLE_BUTTON_CHOICE ? '>' : ' '); - lcd_put_u8str(second_choice); - if (third_choice) { - lcd_put_lchar(18, 3, selected == LCD_RIGHT_BUTTON_CHOICE ? '>' : ' '); - lcd_put_u8str(third_choice); +//! @brief Show a two-choice prompt on the last line of the LCD +//! @param selected Show first choice as selected if true, the second otherwise +//! @param first_choice text caption of first possible choice +//! @param second_choice text caption of second possible choice +//! @param second_col column on LCD where second choice is rendered. +//! @param third_choice text caption of third, optional, choice. +void lcd_show_choices_prompt_P(uint8_t selected, const char *first_choice, const char *second_choice, uint8_t second_col, const char *third_choice) { + lcd_put_lchar(0, 3, selected == LCD_LEFT_BUTTON_CHOICE ? '>' : ' '); + lcd_put_u8str(first_choice); + lcd_put_lchar(second_col, 3, selected == LCD_MIDDLE_BUTTON_CHOICE ? '>' : ' '); + lcd_put_u8str(second_choice); + if (third_choice) { + lcd_put_lchar(18, 3, selected == LCD_RIGHT_BUTTON_CHOICE ? '>' : ' '); + lcd_put_u8str(third_choice); + } +} + +void lcd_space(uint8_t n) { + while (n--) lcd_put_lchar(' '); +} + +// Print extruder status (5 chars total) +// Scenario 1: "F?" +// There is no filament loaded and no tool change is in progress +// Scenario 2: "F[nr.]" +// [nr.] ranges from 1 to 5. +// Shows which filament is loaded. No tool change is in progress +// Scenario 3: "?>[nr.]" +// [nr.] ranges from 1 to 5. +// There is no filament currently loaded, but [nr.] is currently being loaded via tool change +// Scenario 4: "[nr.]>?" +// [nr.] ranges from 1 to 5. +// This scenario indicates a bug in the firmware if ? is on the right side +// Scenario 5: "[nr1.]>[nr2.]" +// [nr1.] ranges from 1 to 5. +// [nr2.] ranges from 1 to 5. +// Filament [nr1.] was loaded, but [nr2.] is currently being loaded via tool change +// Scenario 6: "?>?" +// This scenario should not be possible and indicates a bug in the firmware +uint8_t lcdui_print_extruder(void) { + uint8_t chars = 1; + lcd_space(1); + if (mmu3.get_current_tool() == mmu3.get_tool_change_tool()) { + lcd_put_lchar('F'); + lcd_put_lchar(mmu3.get_current_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_current_tool() + '1'); + chars += 2; + } + else { + lcd_put_lchar(mmu3.get_current_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_current_tool() + '1'); + lcd_put_lchar('>'); + lcd_put_lchar(mmu3.get_tool_change_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_tool_change_tool() + '1'); + chars += 3; + } + return chars; +} + +bool is_whitespace_P(const char *c_addr) { + const char c = pgm_read_byte(c_addr); + return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +} + +bool is_punctuation_P(const char *c_addr) { + const char c = pgm_read_byte(c_addr); + return c == '.' || c == ',' || c == ':' || c == ';' || c == '?' || c == '!' || c == '/'; +} + +/** + * @brief show full screen message + * + * This function is non-blocking + * @param msg message to be displayed from PROGMEM + * @return rest of the text (to be displayed on next page) + */ +static FSTR_P const lcd_display_message_fullscreen_async(FSTR_P const fmsg) { + PGM_P msg = FTOP(fmsg); + PGM_P msgend = msg; + //bool multi_screen = false; + for (uint8_t row = 0; row < LCD_HEIGHT; ++row) { + if (pgm_read_byte(msgend) == 0) break; + SETCURSOR(0, row); + + // Previous row ended with a complete word, so the first character in the + // next row is a whitespace. We can skip the whitespace on a new line. + if (is_whitespace_P(msg) && ++msg == nullptr) break; // End of the message. + + uint8_t linelen = (strlen_P(msg) > LCD_WIDTH) ? LCD_WIDTH : strlen_P(msg); + PGM_P const msgend2 = msg + linelen; + msgend = msgend2; + if (row == 3 && linelen == LCD_WIDTH) { + // Last line of the display, full line should be displayed. + // Find out, whether this message will be split into multiple screens. + //multi_screen = pgm_read_byte(msgend) != 0; + // We do not need this... + //if (multi_screen) msgend = (msgend2 -= 2); } - } - - void lcd_space(uint8_t n) { - while (n--) lcd_put_lchar(' '); - } - - // Print extruder status (5 chars total) - // Scenario 1: "F?" - // There is no filament loaded and no tool change is in progress - // Scenario 2: "F[nr.]" - // [nr.] ranges from 1 to 5. - // Shows which filament is loaded. No tool change is in progress - // Scenario 3: "?>[nr.]" - // [nr.] ranges from 1 to 5. - // There is no filament currently loaded, but [nr.] is currently being loaded via tool change - // Scenario 4: "[nr.]>?" - // [nr.] ranges from 1 to 5. - // This scenario indicates a bug in the firmware if ? is on the right side - // Scenario 5: "[nr1.]>[nr2.]" - // [nr1.] ranges from 1 to 5. - // [nr2.] ranges from 1 to 5. - // Filament [nr1.] was loaded, but [nr2.] is currently being loaded via tool change - // Scenario 6: "?>?" - // This scenario should not be possible and indicates a bug in the firmware - uint8_t lcdui_print_extruder(void) { - uint8_t chars = 1; - lcd_space(1); - if (mmu3.get_current_tool() == mmu3.get_tool_change_tool()) { - lcd_put_lchar('F'); - lcd_put_lchar(mmu3.get_current_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_current_tool() + '1'); - chars += 2; + if (pgm_read_byte(msgend) != 0 && !is_whitespace_P(msgend) && !is_punctuation_P(msgend)) { + // Splitting a word. Find the start of the current word. + while (msgend > msg && !is_whitespace_P(msgend - 1)) --msgend; + if (msgend == msg) msgend = msgend2; // Found a single long word, which cannot be split. Just cut it. } - else { - lcd_put_lchar(mmu3.get_current_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_current_tool() + '1'); - lcd_put_lchar('>'); - lcd_put_lchar(mmu3.get_tool_change_tool() == (uint8_t)MMU3::FILAMENT_UNKNOWN ? '?' : mmu3.get_tool_change_tool() + '1'); - chars += 3; - } - return chars; - } - - bool pgm_is_whitespace(const char *c_addr) { - const char c = pgm_read_byte(c_addr); - return c == ' ' || c == '\t' || c == '\r' || c == '\n'; - } - - bool pgm_is_interpunction(const char *c_addr) { - const char c = pgm_read_byte(c_addr); - return c == '.' || c == ',' || c == ':' || c == ';' || c == '?' || c == '!' || c == '/'; - } - - /** - * @brief show full screen message - * - * This function is non-blocking - * @param msg message to be displayed from PROGMEM - * @return rest of the text (to be displayed on next page) - */ - static FSTR_P const lcd_display_message_fullscreen_nonBlocking(FSTR_P const fmsg) { - PGM_P msg = FTOP(fmsg); - PGM_P msgend = msg; - //bool multi_screen = false; - for (uint8_t row = 0; row < LCD_HEIGHT; ++row) { - if (pgm_read_byte(msgend) == 0) break; - SETCURSOR(0, row); - - // Previous row ended with a complete word, so the first character in the - // next row is a whitespace. We can skip the whitespace on a new line. - if (pgm_is_whitespace(msg) && ++msg == nullptr) break; // End of the message. - - uint8_t linelen = (strlen_P(msg) > LCD_WIDTH) ? LCD_WIDTH : strlen_P(msg); - PGM_P const msgend2 = msg + linelen; - msgend = msgend2; - if (row == 3 && linelen == LCD_WIDTH) { - // Last line of the display, full line should be displayed. - // Find out, whether this message will be split into multiple screens. - //multi_screen = pgm_read_byte(msgend) != 0; - // We do not need this... - //if (multi_screen) msgend = (msgend2 -= 2); + for (; msg < msgend; ++msg) { + const char c = char(pgm_read_byte(msg)); + if (c == '\n') { + // Abort early if '\n' is encountered. + // This character is used to force the following words to be printed on the next line. + break; } - if (pgm_read_byte(msgend) != 0 && !pgm_is_whitespace(msgend) && !pgm_is_interpunction(msgend)) { - // Splitting a word. Find the start of the current word. - while (msgend > msg && !pgm_is_whitespace(msgend - 1)) --msgend; - if (msgend == msg) msgend = msgend2; // Found a single long word, which cannot be split. Just cut it. - } - for (; msg < msgend; ++msg) { - const char c = char(pgm_read_byte(msg)); - if (c == '\n') { - // Abort early if '\n' is encountered. - // This character is used to force the following words to be printed on the next line. - break; + lcd_put_lchar(c); + } + } + return FPSTR(msgend); +} + +FSTR_P const lcd_display_message_fullscreen(FSTR_P const fmsg) { + // Disable update of the screen by the usual lcd_update(0) routine. + #if HAS_WIRED_LCD + //ui.lcdDrawUpdate = LCDViewAction::LCDVIEW_NONE; + ui.clear_lcd(); + return lcd_display_message_fullscreen_async(fmsg); + #else + return fmsg + #endif +} + +/** + * @brief show full screen message and wait + * + * This function is blocking. + * @param msg message to be displayed from PROGMEM + */ +void lcd_show_fullscreen_message_and_wait(FSTR_P const fmsg) { + LcdUpdateDisabler lcdUpdateDisabler; + FSTR_P fmsg_next = lcd_display_message_fullscreen(fmsg); + const bool multi_screen = fmsg_next != nullptr; + ui.use_click(); + KEEPALIVE_STATE(PAUSED_FOR_USER); + // Until confirmed by a button click. + for (;;) { + if (fmsg_next == nullptr) { + // Display the confirm char. + //lcd_put_lchar(LCD_WIDTH - 2, LCD_HEIGHT - 2, LCD_STR_CONFIRM[0]); + } + // Wait for 5 seconds before displaying the next text. + for (uint8_t i = 0; i < 100; ++i) { + marlin.idle(true); + safe_delay(50); + if (ui.use_click()) { + if (fmsg_next == nullptr) { + KEEPALIVE_STATE(IN_HANDLER); + return ui.go_back(); } - lcd_put_lchar(c); + if (!multi_screen) break; + if (fmsg_next == nullptr) fmsg_next = fmsg; + fmsg_next = lcd_display_message_fullscreen(fmsg_next); } } - // We do not need this part... //if (multi_screen) { - // // Display the double down arrow. - // lcd_put_lchar(LCD_WIDTH - 2, LCD_HEIGHT - 2, LCD_STR_ARROW_2_DOWN[0]); + // if (fmsg_next == nullptr) fmsg_next = fmsg; + // fmsg_next = lcd_display_message_fullscreen(fmsg_next); //} - //return multi_screen ? msgend : nullptr; - return FPSTR(msgend); } +} - FSTR_P const lcd_display_message_fullscreen(FSTR_P const fmsg) { - // Disable update of the screen by the usual lcd_update(0) routine. - #if HAS_WIRED_LCD - //ui.lcdDrawUpdate = LCDViewAction::LCDVIEW_NONE; - ui.clear_lcd(); - return lcd_display_message_fullscreen_nonBlocking(fmsg); - #else - return fmsg - #endif - } - - /** - * @brief show full screen message and wait - * - * This function is blocking. - * @param msg message to be displayed from PROGMEM - */ - void lcd_show_fullscreen_message_and_wait(FSTR_P const fmsg) { - LcdUpdateDisabler lcdUpdateDisabler; - FSTR_P fmsg_next = lcd_display_message_fullscreen(fmsg); - const bool multi_screen = fmsg_next != nullptr; - ui.use_click(); - KEEPALIVE_STATE(PAUSED_FOR_USER); - // Until confirmed by a button click. - for (;;) { - if (fmsg_next == nullptr) { - // Display the confirm char. - //lcd_put_lchar(LCD_WIDTH - 2, LCD_HEIGHT - 2, LCD_STR_CONFIRM[0]); - } - // Wait for 5 seconds before displaying the next text. - for (uint8_t i = 0; i < 100; ++i) { - marlin.idle(true); - safe_delay(50); - if (ui.use_click()) { - if (fmsg_next == nullptr) { - KEEPALIVE_STATE(IN_HANDLER); - return ui.go_back(); - } - if (!multi_screen) break; - if (fmsg_next == nullptr) fmsg_next = fmsg; - fmsg_next = lcd_display_message_fullscreen(fmsg_next); - } - } - //if (multi_screen) { - // if (fmsg_next == nullptr) fmsg_next = fmsg; - // fmsg_next = lcd_display_message_fullscreen(fmsg_next); - //} - } - } - - void lcd_insert_char_into_status(uint8_t position, const char message) { - if (position >= LCD_WIDTH) return; - //int size = ui.status_message.length(); - char *str = ui.status_message.buffer(); - str[position] = message; - ui.refresh(LCDVIEW_REDRAW_NOW); // force redraw - } +void lcd_replace_status_char(const uint8_t position, const char message) { + if (position >= MAX_MESSAGE_SIZE) return; + //int size = ui.status_message.length(); + char *str = ui.status_message.buffer(); + str[position] = message; + ui.refresh(LCDVIEW_REDRAW_NOW); // force redraw +} #endif // HAS_PRUSA_MMU3 diff --git a/Marlin/src/feature/mmu3/ultralcd.h b/Marlin/src/feature/mmu3/ultralcd.h index 2f17b61d0a..e7f06dfb1f 100644 --- a/Marlin/src/feature/mmu3/ultralcd.h +++ b/Marlin/src/feature/mmu3/ultralcd.h @@ -48,11 +48,11 @@ class LcdUpdateDisabler { public: LcdUpdateDisabler() : m_updateEnabled(ui.lcdDrawUpdate) { - TERN_(HAS_WIRED_LCD, ui.lcdDrawUpdate = LCDViewAction::LCDVIEW_NONE); + TERN_(HAS_WIRED_LCD, ui.refresh(LCDViewAction::LCDVIEW_NONE)); } ~LcdUpdateDisabler() { #if HAS_WIRED_LCD - ui.lcdDrawUpdate = m_updateEnabled; + ui.refresh(m_updateEnabled); ui.clear_lcd(); ui.update(); #endif @@ -62,11 +62,11 @@ class LcdUpdateDisabler { LCDViewAction m_updateEnabled; }; -bool pgm_is_whitespace(const char *c_addr); -bool pgm_is_interpunction(const char *c_addr); +bool is_whitespace_P(const char *c_addr); +bool is_punctuation_P(const char *c_addr); FSTR_P const lcd_display_message_fullscreen(FSTR_P const pmsg); void lcd_show_choices_prompt_P(uint8_t selected, const char *first_choice, const char *second_choice, uint8_t second_col, const char *third_choice=nullptr); void lcd_show_fullscreen_message_and_wait(FSTR_P const fmsg); uint8_t lcdui_print_extruder(void); void lcd_space(uint8_t n); -void lcd_insert_char_into_status(uint8_t position, const char message); +void lcd_replace_status_char(uint8_t position, const char message); diff --git a/Marlin/src/gcode/feature/camera/M240.cpp b/Marlin/src/gcode/feature/camera/M240.cpp index 8bf0f5d539..191a827ff4 100644 --- a/Marlin/src/gcode/feature/camera/M240.cpp +++ b/Marlin/src/gcode/feature/camera/M240.cpp @@ -96,9 +96,9 @@ * M240: Trigger a camera by... * * - CHDK : Emulate a Canon RC-1 with a configurable ON duration. - * https://captain-slow.dk/2014/03/09/3d-printing-timelapses/ + * https://youtube.be/UqZ8Um5MZEA * - PHOTOGRAPH_PIN : Pulse a digital pin 16 times. - * See https://www.doc-diy.net/photo/rc-1_hacked/ + * See https://web.archive.org/web/20250327153953/www.doc-diy.net/photo/rc-1_hacked/ * - PHOTO_SWITCH_POSITION : Bump a physical switch with the X-carriage using a * configured position, delay, and retract length. * diff --git a/Marlin/src/gcode/feature/ft_motion/M493.cpp b/Marlin/src/gcode/feature/ft_motion/M493.cpp index 85e2fc9d3b..272c3d7ab3 100644 --- a/Marlin/src/gcode/feature/ft_motion/M493.cpp +++ b/Marlin/src/gcode/feature/ft_motion/M493.cpp @@ -27,20 +27,21 @@ #include "../../gcode.h" #include "../../../module/ft_motion.h" #include "../../../module/stepper.h" +#include "../../../lcd/marlinui.h" void say_shaper_type(const AxisEnum a, bool &sep, const char axis_name) { if (sep) SERIAL_ECHOPGM(" ; "); SERIAL_CHAR(axis_name, '='); switch (ftMotion.cfg.shaper[a]) { default: break; - case ftMotionShaper_ZV: SERIAL_ECHOPGM("ZV"); break; - case ftMotionShaper_ZVD: SERIAL_ECHOPGM("ZVD"); break; - case ftMotionShaper_ZVDD: SERIAL_ECHOPGM("ZVDD"); break; - case ftMotionShaper_ZVDDD: SERIAL_ECHOPGM("ZVDDD"); break; - case ftMotionShaper_EI: SERIAL_ECHOPGM("EI"); break; - case ftMotionShaper_2HEI: SERIAL_ECHOPGM("2 Hump EI"); break; - case ftMotionShaper_3HEI: SERIAL_ECHOPGM("3 Hump EI"); break; - case ftMotionShaper_MZV: SERIAL_ECHOPGM("MZV"); break; + TERN_(FTM_SHAPER_ZV, case ftMotionShaper_ZV: SERIAL_ECHOPGM("ZV"); break); + TERN_(FTM_SHAPER_ZVD, case ftMotionShaper_ZVD: SERIAL_ECHOPGM("ZVD"); break); + TERN_(FTM_SHAPER_ZVDD, case ftMotionShaper_ZVDD: SERIAL_ECHOPGM("ZVDD"); break); + TERN_(FTM_SHAPER_ZVDDD, case ftMotionShaper_ZVDDD: SERIAL_ECHOPGM("ZVDDD"); break); + TERN_(FTM_SHAPER_EI, case ftMotionShaper_EI: SERIAL_ECHOPGM("EI"); break); + TERN_(FTM_SHAPER_2HEI, case ftMotionShaper_2HEI: SERIAL_ECHOPGM("2 Hump EI"); break); + TERN_(FTM_SHAPER_3HEI, case ftMotionShaper_3HEI: SERIAL_ECHOPGM("3 Hump EI"); break); + TERN_(FTM_SHAPER_MZV, case ftMotionShaper_MZV: SERIAL_ECHOPGM("MZV"); break); } sep = true; } @@ -87,7 +88,7 @@ void say_shaping() { #if HAS_X_AXIS SERIAL_CHAR(STEPPER_A_NAME); SERIAL_ECHO_TERNARY(dynamic, " ", "base dynamic", "static", " shaper frequency: "); - SERIAL_ECHO(p_float_t(c.baseFreq.x, 2), F("Hz")); + SERIAL_ECHO(p_float_t(c.baseFreq.x, 2), F(" Hz")); #if HAS_DYNAMIC_FREQ if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(c.dynFreqK.x, 2), F("Hz/"), z_based ? F("mm") : F("g")); #endif @@ -113,6 +114,16 @@ void say_shaping() { #endif SERIAL_EOL(); #endif + + #if ENABLED(FTM_SHAPER_E) + SERIAL_CHAR('E'); + SERIAL_ECHO_TERNARY(dynamic, " ", "base dynamic", "static", " shaper frequency: "); + SERIAL_ECHO(p_float_t(c.baseFreq.e, 2), F(" Hz")); + #if HAS_DYNAMIC_FREQ + if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(c.dynFreqK.e, 2), F("Hz/"), z_based ? F("mm") : F("g")); + #endif + SERIAL_EOL(); + #endif } } @@ -236,10 +247,8 @@ void GcodeSuite::M493() { return; } auto set_shaper = [&](const AxisEnum axis, ftMotionShaper_t newsh) { - if (newsh != c.shaper[axis]) { - c.shaper[axis] = newsh; + if (c.setShaper(axis, newsh)) flag.update = flag.report = true; - } }; if (seenC) { #define _SET_SHAPER(A) set_shaper(_AXIS(A), shaperVal); @@ -248,14 +257,9 @@ void GcodeSuite::M493() { #endif // NUM_AXES_SHAPED > 0 - // Parse 'H' Axis Synchronization parameter. - if (parser.seenval('H')) { - const bool enabled = parser.value_bool(); - if (enabled != c.axis_sync_enabled) { - c.axis_sync_enabled = enabled; - flag.report = true; - } - } + // Parse bool 'H' Axis Synchronization parameter. + if (parser.seen('H') && c.setAxisSync(parser.value_bool())) + flag.report = true; #if HAS_DYNAMIC_FREQ @@ -296,7 +300,7 @@ void GcodeSuite::M493() { const float zetaVal = seenI ? parser.value_float() : 0.0f; const bool goodZeta = seenI && c.goodZeta(zetaVal); if (seenI && !goodZeta) - SERIAL_ECHOLN(F("?Invalid "), F("(I) Zeta value. (0.01-1.0)")); // Zeta out of range + SERIAL_ECHOLN(F("?Invalid "), F("(I) Zeta value. (0.01-" STRINGIFY(FTM_MAX_DAMPENING) ")")); // Zeta out of range #if HAS_FTM_EI_SHAPING // Vibration Tolerance parameter @@ -317,10 +321,8 @@ void GcodeSuite::M493() { if (seenA) { if (AXIS_IS_SHAPING(X)) { // TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct. - if (goodBaseFreq) { - c.baseFreq.x = baseFreqVal; + if (goodBaseFreq && c.setBaseFreq(X_AXIS, baseFreqVal)) flag.update = flag.report = true; - } } else // Mode doesn't use frequency. SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (A) frequency."); @@ -328,19 +330,15 @@ void GcodeSuite::M493() { #if HAS_DYNAMIC_FREQ // Parse X frequency scaling parameter - if (seenF && modeUsesDynFreq) { - c.dynFreqK.x = baseDynFreqVal; + if (seenF && c.setDynFreqK(X_AXIS, baseDynFreqVal)) flag.report = true; - } #endif // Parse X zeta parameter if (seenI) { if (AXIS_IS_SHAPING(X)) { - if (goodZeta) { - c.zeta.x = zetaVal; + if (goodZeta && c.setZeta(X_AXIS, zetaVal)) flag.update = true; - } } else SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (I) zeta parameter."); @@ -350,10 +348,8 @@ void GcodeSuite::M493() { // Parse X vtol parameter if (seenQ) { if (AXIS_IS_EISHAPING(X)) { - if (goodVtol) { - c.vtol.x = vtolVal; + if (goodVtol && c.setVtol(X_AXIS, vtolVal)) flag.update = true; - } } else SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (Q) vtol parameter."); @@ -370,10 +366,8 @@ void GcodeSuite::M493() { // Parse Y frequency parameter if (seenA) { if (AXIS_IS_SHAPING(Y)) { - if (goodBaseFreq) { - c.baseFreq.y = baseFreqVal; + if (goodBaseFreq && c.setBaseFreq(Y_AXIS, baseFreqVal)) flag.update = flag.report = true; - } } else // Mode doesn't use frequency. SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (A) frequency."); @@ -381,32 +375,26 @@ void GcodeSuite::M493() { #if HAS_DYNAMIC_FREQ // Parse Y frequency scaling parameter - if (seenF && modeUsesDynFreq) { - c.dynFreqK.y = baseDynFreqVal; + if (seenF && c.setDynFreqK(Y_AXIS, baseDynFreqVal)) flag.report = true; - } #endif // Parse Y zeta parameter if (seenI) { if (AXIS_IS_SHAPING(Y)) { - if (goodZeta) { - c.zeta.y = zetaVal; + if (goodZeta && c.setZeta(Y_AXIS, zetaVal)) flag.update = true; - } } else SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (I) zeta parameter."); } - // Parse Y vtol parameter #if HAS_FTM_EI_SHAPING + // Parse Y vtol parameter if (seenQ) { if (AXIS_IS_EISHAPING(Y)) { - if (goodVtol) { - c.vtol.y = vtolVal; + if (goodVtol && c.setVtol(Y_AXIS, vtolVal)) flag.update = true; - } } else SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (Q) vtol parameter."); @@ -423,10 +411,8 @@ void GcodeSuite::M493() { // Parse Z frequency parameter if (seenA) { if (AXIS_IS_SHAPING(Z)) { - if (goodBaseFreq) { - c.baseFreq.z = baseFreqVal; + if (goodBaseFreq && c.setBaseFreq(Z_AXIS, baseFreqVal)) flag.update = flag.report = true; - } } else // Mode doesn't use frequency. SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (A) frequency."); @@ -434,32 +420,26 @@ void GcodeSuite::M493() { #if HAS_DYNAMIC_FREQ // Parse Z frequency scaling parameter - if (seenF && modeUsesDynFreq) { - c.dynFreqK.z = baseDynFreqVal; + if (seenF && c.setDynFreqK(Z_AXIS, baseDynFreqVal)) flag.report = true; - } #endif // Parse Z zeta parameter if (seenI) { if (AXIS_IS_SHAPING(Z)) { - if (goodZeta) { - c.zeta.z = zetaVal; + if (goodZeta && c.setZeta(Z_AXIS, zetaVal)) flag.update = true; - } } else SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (I) zeta parameter."); } - // Parse Z vtol parameter #if HAS_FTM_EI_SHAPING + // Parse Z vtol parameter if (seenQ) { if (AXIS_IS_EISHAPING(Z)) { - if (goodVtol) { - c.vtol.z = vtolVal; + if (goodVtol && c.setVtol(Z_AXIS, vtolVal)) flag.update = true; - } } else SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (Q) vtol parameter."); @@ -476,10 +456,8 @@ void GcodeSuite::M493() { // Parse E frequency parameter if (seenA) { if (AXIS_IS_SHAPING(E)) { - if (goodBaseFreq) { - c.baseFreq.e = baseFreqVal; + if (goodBaseFreq && c.setBaseFreq(E_AXIS, baseFreqVal)) flag.update = flag.report = true; - } } else // Mode doesn't use frequency. SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (A) frequency."); @@ -487,32 +465,26 @@ void GcodeSuite::M493() { #if HAS_DYNAMIC_FREQ // Parse E frequency scaling parameter - if (seenF && modeUsesDynFreq) { - c.dynFreqK.e = baseDynFreqVal; + if (seenF && c.setDynFreqK(E_AXIS, baseDynFreqVal)) flag.report = true; - } #endif // Parse E zeta parameter if (seenI) { if (AXIS_IS_SHAPING(E)) { - if (goodZeta) { - c.zeta.e = zetaVal; + if (goodZeta && c.setZeta(E_AXIS, zetaVal)) flag.update = true; - } } else SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (I) zeta parameter."); } - // Parse E vtol parameter #if HAS_FTM_EI_SHAPING + // Parse E vtol parameter if (seenQ) { if (AXIS_IS_EISHAPING(E)) { - if (goodVtol) { - c.vtol.e = vtolVal; + if (goodVtol && c.setVtol(E_AXIS, vtolVal)) flag.update = true; - } } else SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (Q) vtol parameter."); @@ -522,7 +494,8 @@ void GcodeSuite::M493() { #endif // FTM_SHAPER_E - if (flag.update) ftMotion.update_shaping_params(); + if (flag.update || flag.report) + ui.refresh(); if (flag.report) say_shaping(); } diff --git a/Marlin/src/gcode/feature/ft_motion/M494.cpp b/Marlin/src/gcode/feature/ft_motion/M494.cpp index 212a69c0a2..d6161a9574 100644 --- a/Marlin/src/gcode/feature/ft_motion/M494.cpp +++ b/Marlin/src/gcode/feature/ft_motion/M494.cpp @@ -27,6 +27,7 @@ #include "../../../module/ft_motion.h" #include "../../../module/stepper.h" #include "../../../module/planner.h" +#include "../../../lcd/marlinui.h" void say_ftm_settings() { #if ANY(FTM_POLYS, FTM_SMOOTHING) @@ -48,11 +49,13 @@ void say_ftm_settings() { void GcodeSuite::M494_report(const bool forReplay/*=true*/) { TERN_(MARLIN_SMALL_BUILD, return); - const ft_config_t &c = ftMotion.cfg; - report_heading_etc(forReplay, F("FT Motion")); SERIAL_ECHOPGM(" M494 T", (uint8_t)ftMotion.getTrajectoryType()); + #if ANY(FTM_POLYS, FTM_SMOOTHING) + const ft_config_t &c = ftMotion.cfg; + #endif + #if ENABLED(FTM_SMOOTHING) SERIAL_ECHOPGM(CARTES_PAIRED_LIST( " X", c.smoothingTime.X, @@ -109,14 +112,17 @@ void GcodeSuite::M494() { #if ENABLED(FTM_SMOOTHING) - #define SMOOTH_SET(A,N) \ - if (parser.seenval(CHARIFY(A))) { \ - if (ftMotion.set_smoothing_time(_AXIS(A), parser.value_float())) \ - report = true; \ - else \ - SERIAL_ECHOLNPGM("?Invalid ", C(N), " smoothing time (", C(CHARIFY(A)), ") value."); \ + auto smooth_set = [](AxisEnum axis, char axis_name) { + if (parser.seenval(IAXIS_CHAR(axis))) { + if (ftMotion.set_smoothing_time(axis, parser.value_float())) + return true; + else + SERIAL_ECHOLNPGM("?Invalid ", C(axis_name), " smoothing time (", C(IAXIS_CHAR(axis)), ") value."); } + return false; + }; + #define SMOOTH_SET(A,N) report |= smooth_set(_AXIS(A), N); CARTES_GANG( SMOOTH_SET(X, STEPPER_A_NAME), SMOOTH_SET(Y, STEPPER_B_NAME), SMOOTH_SET(Z, STEPPER_C_NAME), SMOOTH_SET(E, 'E') @@ -124,7 +130,10 @@ void GcodeSuite::M494() { #endif // FTM_SMOOTHING - if (report) say_ftm_settings(); + if (report) { + ui.refresh(); + say_ftm_settings(); + } } #endif // FT_MOTION diff --git a/Marlin/src/gcode/gcode_d.cpp b/Marlin/src/gcode/gcode_d.cpp index 1e472e0f6e..b6852aba6a 100644 --- a/Marlin/src/gcode/gcode_d.cpp +++ b/Marlin/src/gcode/gcode_d.cpp @@ -179,17 +179,43 @@ void GcodeSuite::D(const int16_t dcode) { break; case 100: { // D100 Disable heaters and attempt a hard hang (Watchdog Test) + + #ifdef __PLAT_RP2040__ + const uint8_t core = parser.byteval('C', 0); // C parameter: which core to freeze (0=Core 0, 1=Core 1) + #else + constexpr uint8_t core = 0; + #endif + SERIAL_ECHOLNPGM("Disabling heaters and attempting to trigger Watchdog"); SERIAL_ECHOLNPGM("(USE_WATCHDOG " TERN(USE_WATCHDOG, "ENABLED", "DISABLED") ")"); + #ifdef __PLAT_RP2040__ + SERIAL_ECHOLNPGM("Freezing Core ", core); + #endif + thermalManager.disable_all_heaters(); delay(1000); // Allow time to print - hal.isr_off(); - // Use a low-level delay that does not rely on interrupts to function - // Do not spin forever, to avoid thermal risks if heaters are enabled and - // watchdog does not work. - for (int i = 10000; i--;) DELAY_US(1000UL); - hal.isr_on(); + + if (core == 1) { + #ifdef __PLAT_RP2040__ + // Freeze Core 1 by setting a flag it will check + extern volatile bool core1_freeze_test; + core1_freeze_test = true; + delay(10000); // Wait 10 seconds for watchdog to trigger + core1_freeze_test = false; + #endif + } + else { + // Freeze Core 0 (original behavior) + hal.isr_off(); + // Use a low-level delay that does not rely on interrupts to function + // Do not spin forever, to avoid thermal risks if heaters are enabled and + // watchdog does not work. + for (int i = 10000; i--;) DELAY_US(1000UL); + hal.isr_on(); + } + SERIAL_ECHOLNPGM("FAILURE: Watchdog did not trigger board reset."); + } break; #if HAS_MEDIA diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index 99738461de..b692c818aa 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -188,7 +188,7 @@ void GCodeParser::parse(char *p) { // Bail if there's no command code number if (!TERN(SIGNED_CODENUM, NUMERIC_SIGNED(*p), NUMERIC(*p))) { - if (TERN0(HAS_MULTI_EXTRUDER, letter == 'T')) { + if (E_TERN0(letter == 'T')) { p[0] = '*'; p[1] = '\0'; string_arg = p; // Convert 'T' alone into 'T*' command_letter = letter; } diff --git a/Marlin/src/gcode/sd/M34.cpp b/Marlin/src/gcode/sd/M34.cpp index d393fe5ceb..aa4724550f 100644 --- a/Marlin/src/gcode/sd/M34.cpp +++ b/Marlin/src/gcode/sd/M34.cpp @@ -26,6 +26,7 @@ #include "../gcode.h" #include "../../sd/cardreader.h" +#include "../../lcd/marlinui.h" /** * M34: Media Sorting @@ -33,7 +34,7 @@ * Set Media Sorting Options * * Parameters: - * S Sorting Order: + * S Sorting Order: * S Default sorting (i.e., SDSORT_REVERSE) * S-1 Reverse alpha sorting * S0 FID Order (not always newest) @@ -46,11 +47,16 @@ * F1 Folders after files */ void GcodeSuite::M34() { - if (parser.seen('S')) card.setSortOn(SortFlag(parser.ushortval('S', TERN(SDSORT_REVERSE, AS_REV, AS_FWD)))); + if (parser.seen('S')) + card.setSortOn(SortFlag(parser.ushortval('S', TERN(SDSORT_REVERSE, AS_REV, AS_FWD)))); + if (parser.seenval('F')) { const int v = parser.value_long(); card.setSortFolders(v < 0 ? -1 : v > 0 ? 1 : 0); } + + ui.refresh(); + //if (parser.seen('R')) card.setSortReverse(parser.value_bool()); } diff --git a/Marlin/src/gcode/temp/M306.cpp b/Marlin/src/gcode/temp/M306.cpp index b3f5b6b97b..7e79581f2b 100644 --- a/Marlin/src/gcode/temp/M306.cpp +++ b/Marlin/src/gcode/temp/M306.cpp @@ -49,7 +49,7 @@ */ void GcodeSuite::M306() { - const uint8_t e = TERN0(HAS_MULTI_EXTRUDER, parser.intval('E', active_extruder)); + const uint8_t e = E_TERN0(parser.intval('E', active_extruder)); if (e >= (EXTRUDERS)) { SERIAL_ECHOLNPGM("?(E)xtruder index out of range (0-", (EXTRUDERS) - 1, ")."); return; diff --git a/Marlin/src/inc/Conditionals-4-adv.h b/Marlin/src/inc/Conditionals-4-adv.h index 7e94c617c1..75c4efa743 100644 --- a/Marlin/src/inc/Conditionals-4-adv.h +++ b/Marlin/src/inc/Conditionals-4-adv.h @@ -373,8 +373,6 @@ #undef INPUT_SHAPING_Y #undef INPUT_SHAPING_Z #undef INPUT_SHAPING_E_SYNC - #undef MULTISTEPPING_LIMIT - #define MULTISTEPPING_LIMIT 1 #endif // Linear advance uses Jerk since E is an isolated axis diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index 0fa53dbf3e..024eb42f51 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -3612,6 +3612,14 @@ #endif #endif +#if ALL(SDCARD_SORT_ALPHA, SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM) + #if SDSORT_CACHE_VFATS > VFAT_ENTRIES_LIMIT + #undef SDSORT_CACHE_VFATS + #define SDSORT_CACHE_VFATS VFAT_ENTRIES_LIMIT + #define SDSORT_CACHE_VFATS_WARNING 1 + #endif +#endif + // Fallback SPI Speed for SD #if HAS_MEDIA && !defined(SD_SPI_SPEED) #define SD_SPI_SPEED SPI_FULL_SPEED @@ -3687,27 +3695,14 @@ // Fixed-Time Motion #if ENABLED(FT_MOTION) - #define FTM_TS (1.0f / FTM_FS) // (s) Time step for trajectory generation. (Reciprocal of FTM_FS) - #define FTM_RATIO (FTM_FS / FTM_MIN_SHAPE_FREQ) // Factor for use in FTM_ZMAX. DON'T CHANGE. - #define FTM_SMOOTH_MAX_I uint32_t(TERN0(FTM_SMOOTHING, CEIL(FTM_FS * FTM_MAX_SMOOTHING_TIME))) // Max delays for smoothing - - // Maximum delays for shaping functions (even numbers only!) - #define FTM_ZMAX (TERN(HAS_FTM_EI_SHAPING, 2, 1) * FTM_RATIO + FTM_SMOOTH_MAX_I) - + #define FTM_TS (1.0f / FTM_FS) // (s) Time step for trajectory generation. (Reciprocal of FTM_FS) #define FTM_SMOOTHING_ORDER 5 // 3 to 5 is closest to Gaussian - // Calculate as: - // ZV : FTM_RATIO / 2 - // ZVD, MZV : FTM_RATIO - // 2HEI : FTM_RATIO * 3 / 2 - // 3HEI : FTM_RATIO * 2 #ifndef FTM_BUFFER_SIZE #define FTM_BUFFER_SIZE 128 #endif - #define FTM_BUFFER_MASK (FTM_BUFFER_SIZE - 1u) - #if ANY(BIQU_MICROPROBE_V1, BIQU_MICROPROBE_V2) - #ifndef PROBE_WAKEUP_TIME_MS - #define PROBE_WAKEUP_TIME_MS 30 - #define PROBE_WAKEUP_TIME_WARNING 1 - #endif + + #if ANY(BIQU_MICROPROBE_V1, BIQU_MICROPROBE_V2) && !defined(PROBE_WAKEUP_TIME_MS) + #define PROBE_WAKEUP_TIME_MS 30 + #define PROBE_WAKEUP_TIME_WARNING 1 #endif #endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 694f88f3ee..5856723c77 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -429,14 +429,8 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "SDSORT_DYNAMIC_RAM requires SDSORT_CACHE_NAMES." #endif - #if ENABLED(SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM) - #if SDSORT_CACHE_VFATS < 2 - #error "SDSORT_CACHE_VFATS must be 2 or greater!" - #elif SDSORT_CACHE_VFATS > VFAT_ENTRIES_LIMIT - #undef SDSORT_CACHE_VFATS - #define SDSORT_CACHE_VFATS VFAT_ENTRIES_LIMIT - #define SDSORT_CACHE_VFATS_WARNING 1 - #endif + #if ENABLED(SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM) && SDSORT_CACHE_VFATS < 2 + #error "SDSORT_CACHE_VFATS must be 2 or greater!" #endif #endif @@ -4478,7 +4472,7 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." * Fixed-Time Motion limitations */ #if ENABLED(FT_MOTION) - static_assert(FTM_BUFFER_SIZE >= 4 && (FTM_BUFFER_SIZE & FTM_BUFFER_MASK) == 0, "FTM_BUFFER_SIZE must be a power of two (128, 256, 512, ...)."); + static_assert(FTM_BUFFER_SIZE >= 4 && (FTM_BUFFER_SIZE & (FTM_BUFFER_SIZE - 1u)) == 0, "FTM_BUFFER_SIZE must be a power of two (128, 256, 512, ...)."); #if ENABLED(MIXING_EXTRUDER) #error "FT_MOTION does not currently support MIXING_EXTRUDER." #endif diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 7584030113..d73463086b 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2025-12-14" + #define STRING_DISTRIBUTION_DATE "2025-12-25" #endif /** diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index 7f0bc58ea5..9c4eabaf6e 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -799,7 +799,7 @@ #if ANY(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0) && DISABLED(RGB_LED) #warning "Your FYSETC Mini Panel works best with RGB_LED." -#elif ANY(FYSETC_MINI_12864_2_0, FYSETC_MINI_12864_2_1) && DISABLED(LED_USER_PRESET_STARTUP) +#elif ENABLED(FYSETC_MINI_12864_2_0) && DISABLED(LED_USER_PRESET_STARTUP) #warning "Your FYSETC/MKS/BTT/BEEZ Mini Panel works best with LED_USER_PRESET_STARTUP." #endif diff --git a/Marlin/src/lcd/dwin/jyersui/dwin.cpp b/Marlin/src/lcd/dwin/jyersui/dwin.cpp index 1e8cdb1a55..d451526540 100644 --- a/Marlin/src/lcd/dwin/jyersui/dwin.cpp +++ b/Marlin/src/lcd/dwin/jyersui/dwin.cpp @@ -365,7 +365,7 @@ private: const auto end_x_px = start_x_px + cell_width_px - 1 - gridline_width; const auto start_y_px = padding_y_top + (GRID_MAX_POINTS_Y - y - 1) * cell_height_px; const auto end_y_px = start_y_px + cell_height_px - 1 - gridline_width; - dwinDrawRectangle(1, // RGB565 colors: http://www.barth-dev.de/online/rgb565-color-picker/ + dwinDrawRectangle(1, // RGB565 colors: https://barth-dev.de/online/rgb565-color-picker/ isnan(bedlevel.z_values[x][y]) ? COLOR_GREY : ( // gray if undefined (bedlevel.z_values[x][y] < 0 ? (uint16_t)LROUND(0x1F * -bedlevel.z_values[x][y] / (!viewer_asymmetric_range ? rmax : v_min)) << 11 : // red if mesh point value is negative diff --git a/Marlin/src/lcd/extui/anycubic/Tunes.h b/Marlin/src/lcd/extui/anycubic/Tunes.h index 73483a9bdd..eff9c939a8 100644 --- a/Marlin/src/lcd/extui/anycubic/Tunes.h +++ b/Marlin/src/lcd/extui/anycubic/Tunes.h @@ -65,7 +65,7 @@ namespace Anycubic { // Only uncomment the tunes you are using to save memory // This will help you write tunes! - // https://www.apronus.com/music/flashpiano.htm + // https://virtualpiano.online/ const uint16_t SOS[] = { 250, diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp index d39c3079be..bd774f7523 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp @@ -1088,7 +1088,7 @@ void DGUSScreenHandlerMKS::filamentUnload(DGUS_VP_Variable &var, void *val_ptr) if (filament_data.action == 0) { // Go back to utility screen TERN_(HAS_EXTRUDERS, thermalManager.setTargetHotend(e_temp, 0)); - TERN_(HAS_MULTI_EXTRUDER, thermalManager.setTargetHotend(e_temp, 1)); + E_TERN_(thermalManager.setTargetHotend(e_temp, 1)); gotoScreen(DGUS_SCREEN_UTILITY); return; } diff --git a/Marlin/src/lcd/extui/dgus_e3s1pro/definition/DGUS_VPList.cpp b/Marlin/src/lcd/extui/dgus_e3s1pro/definition/DGUS_VPList.cpp index dddc6f889e..4127192203 100644 --- a/Marlin/src/lcd/extui/dgus_e3s1pro/definition/DGUS_VPList.cpp +++ b/Marlin/src/lcd/extui/dgus_e3s1pro/definition/DGUS_VPList.cpp @@ -38,7 +38,7 @@ const char DGUS_MACHINENAME[] PROGMEM = MACHINE_NAME; const char DGUS_MARLINVERSION[] PROGMEM = SHORT_BUILD_VERSION; const char DGUS_BOARD[] PROGMEM = BOARD_INFO_NAME; const char DGUS_BEDSIZE[] PROGMEM = DGUS_BED_SIZE_STR; -const char DGUS_WEBSITE[] PROGMEM = "http://marlinfw.org"; +const char DGUS_WEBSITE[] PROGMEM = "https://marlinfw.org"; const uint16_t DGUS_ZERO = 0; #define VP_HELPER(ADDR, SIZE, FLAGS, EXTRA, RXHANDLER, TXHANDLER) \ diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt index e60008693e..f288702d2f 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt @@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. +. diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h index b219bd88e1..82a7a78cd8 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h @@ -64,7 +64,7 @@ /** * Settings for the Haoyu Electronics, 4.3" Graphical LCD Touchscreen, 480x272, SPI, FT800 (FT800CB-HY43B) * and 5" Graphical LCD Touchscreen, 480x272, SPI, FT800 (FT800CB-HY50B) - * http://www.hotmcu.com/43-graphical-lcd-touchscreen-480x272-spi-ft800-p-111.html?cPath=6_16 + * https://www.hotmcu.com/43-graphical-lcd-touchscreen-480x272-spi-ft800-p-111.html?cPath=6_16 * http://www.hotmcu.com/5-graphical-lcd-touchscreen-480x272-spi-ft800-p-124.html?cPath=6_16 * Datasheet: * https://www.hantronix.com/files/data/1278363262430-3.pdf @@ -90,7 +90,7 @@ /** * Settings for the Haoyu Electronics, 5" Graphical LCD Touchscreen, 800x480, SPI, FT810 - * http://www.hotmcu.com/5-graphical-lcd-touchscreen-800x480-spi-ft810-p-286.html + * https://www.hotmcu.com/5-graphical-lcd-touchscreen-800x480-spi-ft810-p-286.html * Datasheet: * https://www.haoyuelectronics.com/Attachment/HY5-LCD-HD/KD50G21-40NT-A1.pdf */ @@ -115,7 +115,7 @@ * Settings for the 4D Systems, 4.3" Embedded SPI Display 480x272, SPI, FT800 (4DLCD-FT843) * https://4dsystems.com.au/4dlcd-ft843 * Datasheet: - * https://4dsystems.com.au/mwdownloads/download/link/id/52/ + * https://resources.4dsystems.com.au/datasheets/ft8xx/4DLCD-FT843/4DLCD-FT843_Datasheet_R_1_3.pdf */ #elif defined(LCD_4DSYSTEMS_4DLCD_FT843) #if !HAS_RESOLUTION @@ -159,7 +159,7 @@ * FYSETC Color LCD * https://www.aliexpress.com/item/4000627651757.html * Product information: - * https://github.com/FYSETC/TFT81050 + * https://github.com/FYSETC/FYSETC-TFT81050 */ #elif defined(LCD_FYSETC_TFT81050) #if !HAS_RESOLUTION diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg index 25893f5276..8b14629997 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg @@ -1,13 +1,13 @@ - + = epps); + if (encoderPastThreshold && TERN1(IS_TFTGLCD_PANEL, !external_control)) { int32_t encoder_multiplier = 1; @@ -1103,16 +1109,22 @@ void MarlinUI::init() { } } + // Has the wheel advanced by a step or the encoder done a click? if (encoderPastThreshold || lcd_clicked) { + + // Retain the current screen reset_status_timeout(ms); + // Keep the lights on #if HAS_BACKLIGHT_TIMEOUT refresh_backlight_timeout(); #elif HAS_DISPLAY_SLEEP refresh_screen_timeout(); #endif + // Make sure the display is updated in response refresh(LCDVIEW_REDRAW_NOW); + // This will cause paged displays to go to "first page" TERN_(HAS_MARLINUI_U8GLIB, drawing_screen = false); #if MARLINUI_SCROLL_NAME filename_scroll_max = 0; @@ -1170,6 +1182,7 @@ void MarlinUI::init() { TERN_(HAS_ADC_BUTTONS, keypad_buttons = 0); #if HAS_MARLINUI_U8GLIB + #if ENABLED(LIGHTWEIGHT_UI) const bool in_status = on_status_screen(), do_u8g_loop = !in_status; @@ -1198,11 +1211,14 @@ void MarlinUI::init() { return; } } - #else + + #else // !HAS_MARLINUI_U8GLIB + run_current_screen(); // Apply all DWIN drawing after processing TERN_(IS_DWIN_MARLINUI, dwinUpdateLCD()); + #endif TERN_(HAS_MARLINUI_MENU, lcd_clicked = false); diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index a3a3ae28f0..8ec25ab5c6 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -667,6 +667,11 @@ public: static void preheat_all(const uint8_t m, const uint8_t e=active_extruder) { apply_preheat(m, PT_ALL, e); } #endif + /** + * The current screen will time out unless 'defer_return_to_status' is true, + * and the display will go back to the Status Screen. + * Call this method whenever the user interacts to reset the timeout. + */ static void reset_status_timeout(const millis_t ms) { TERN(HAS_SCREEN_TIMEOUT, return_to_status_ms = ms + LCD_TIMEOUT_TO_STATUS, UNUSED(ms)); } diff --git a/Marlin/src/lcd/menu/menu_bed_tramming.cpp b/Marlin/src/lcd/menu/menu_bed_tramming.cpp index 01de15f800..b96dd5b07d 100644 --- a/Marlin/src/lcd/menu/menu_bed_tramming.cpp +++ b/Marlin/src/lcd/menu/menu_bed_tramming.cpp @@ -274,7 +274,7 @@ static void _lcd_goto_next_corner() { } TERN_(BLTOUCH, if (!bltouch.high_speed_mode) bltouch.stow()); ui.goto_screen(_lcd_draw_probing); - return (probe_triggered); + return probe_triggered; } void _lcd_test_corners() { diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index f89aa5f741..e4d814f30b 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -349,6 +349,7 @@ void menu_main() { SUBMENU(MSG_MEDIA_MENU_SD, MEDIA_MENU_GATEWAY); else if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isSDCardInserted())) SUBMENU(MSG_MEDIA_MENU_SD, MEDIA_MENU_GATEWAY_SD); + if (card.isFlashDriveMounted()) SUBMENU(MSG_MEDIA_MENU_USB, MEDIA_MENU_GATEWAY); else if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isFlashDriveInserted())) diff --git a/Marlin/src/lcd/menu/menu_media.cpp b/Marlin/src/lcd/menu/menu_media.cpp index f4c409c4a3..c1ecd30fd0 100644 --- a/Marlin/src/lcd/menu/menu_media.cpp +++ b/Marlin/src/lcd/menu/menu_media.cpp @@ -101,7 +101,10 @@ class MenuItem_sdfolder : public MenuItem_sdbase { } }; +// // Shortcut menu items to go directly to inserted — not necessarily mounted — drives +// + void menu_file_selector_sd() { if (!card.isSDCardSelected()) { card.release(); @@ -111,7 +114,6 @@ void menu_file_selector_sd() { ui.goto_screen(menu_file_selector); } -// Shortcut menu items to go directly to inserted — not necessarily mounted — drives void menu_file_selector_usb() { if (!card.isFlashDriveSelected()) { card.release(); @@ -121,7 +123,6 @@ void menu_file_selector_usb() { ui.goto_screen(menu_file_selector); } -// Shortcut menu items to go directly to inserted — not necessarily mounted — drives void menu_file_selector() { ui.encoder_direction_menus(); diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index 106646430c..a9261dc922 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -315,15 +315,31 @@ void menu_move() { FSTR_P get_shaper_name(const AxisEnum axis) { switch (ftMotion.cfg.shaper[axis]) { default: return nullptr; - case ftMotionShaper_NONE: return GET_TEXT_F(MSG_LCD_OFF); - case ftMotionShaper_ZV: return GET_TEXT_F(MSG_FTM_ZV); - case ftMotionShaper_ZVD: return GET_TEXT_F(MSG_FTM_ZVD); - case ftMotionShaper_ZVDD: return GET_TEXT_F(MSG_FTM_ZVDD); - case ftMotionShaper_ZVDDD: return GET_TEXT_F(MSG_FTM_ZVDDD); - case ftMotionShaper_EI: return GET_TEXT_F(MSG_FTM_EI); - case ftMotionShaper_2HEI: return GET_TEXT_F(MSG_FTM_2HEI); - case ftMotionShaper_3HEI: return GET_TEXT_F(MSG_FTM_3HEI); - case ftMotionShaper_MZV: return GET_TEXT_F(MSG_FTM_MZV); + case ftMotionShaper_NONE: return GET_TEXT_F(MSG_LCD_OFF); + #if ENABLED(FTM_SHAPER_ZV) + case ftMotionShaper_ZV: return GET_TEXT_F(MSG_FTM_ZV); + #endif + #if ENABLED(FTM_SHAPER_ZVD) + case ftMotionShaper_ZVD: return GET_TEXT_F(MSG_FTM_ZVD); + #endif + #if ENABLED(FTM_SHAPER_ZVDD) + case ftMotionShaper_ZVDD: return GET_TEXT_F(MSG_FTM_ZVDD); + #endif + #if ENABLED(FTM_SHAPER_ZVDDD) + case ftMotionShaper_ZVDDD: return GET_TEXT_F(MSG_FTM_ZVDDD); + #endif + #if ENABLED(FTM_SHAPER_EI) + case ftMotionShaper_EI: return GET_TEXT_F(MSG_FTM_EI); + #endif + #if ENABLED(FTM_SHAPER_2HEI) + case ftMotionShaper_2HEI: return GET_TEXT_F(MSG_FTM_2HEI); + #endif + #if ENABLED(FTM_SHAPER_3HEI) + case ftMotionShaper_3HEI: return GET_TEXT_F(MSG_FTM_3HEI); + #endif + #if ENABLED(FTM_SHAPER_MZV) + case ftMotionShaper_MZV: return GET_TEXT_F(MSG_FTM_MZV); + #endif } } @@ -343,8 +359,7 @@ void menu_move() { #endif void ftm_menu_set_shaper(const ftMotionShaper_t s) { - ftMotion.cfg.shaper[MenuItemBase::itemIndex] = s; - ftMotion.update_shaping_params(); + queue.inject(TS(F("M493"), IAXIS_CHAR(MenuItemBase::itemIndex), 'C', int(s))); ui.go_back(); } @@ -355,15 +370,15 @@ void menu_move() { START_MENU(); BACK_ITEM_N(axis, MSG_FTM_CONFIGURE_AXIS_N); - if (shaper != ftMotionShaper_NONE) ACTION_ITEM_N(axis, MSG_LCD_OFF, []{ ftm_menu_set_shaper(ftMotionShaper_NONE) ; }); - if (shaper != ftMotionShaper_ZV) ACTION_ITEM_N(axis, MSG_FTM_ZV, []{ ftm_menu_set_shaper(ftMotionShaper_ZV) ; }); - if (shaper != ftMotionShaper_ZVD) ACTION_ITEM_N(axis, MSG_FTM_ZVD, []{ ftm_menu_set_shaper(ftMotionShaper_ZVD) ; }); - if (shaper != ftMotionShaper_ZVDD) ACTION_ITEM_N(axis, MSG_FTM_ZVDD, []{ ftm_menu_set_shaper(ftMotionShaper_ZVDD) ; }); - if (shaper != ftMotionShaper_ZVDDD) ACTION_ITEM_N(axis, MSG_FTM_ZVDDD,[]{ ftm_menu_set_shaper(ftMotionShaper_ZVDDD) ; }); - if (shaper != ftMotionShaper_EI) ACTION_ITEM_N(axis, MSG_FTM_EI, []{ ftm_menu_set_shaper(ftMotionShaper_EI) ; }); - if (shaper != ftMotionShaper_2HEI) ACTION_ITEM_N(axis, MSG_FTM_2HEI, []{ ftm_menu_set_shaper(ftMotionShaper_2HEI) ; }); - if (shaper != ftMotionShaper_3HEI) ACTION_ITEM_N(axis, MSG_FTM_3HEI, []{ ftm_menu_set_shaper(ftMotionShaper_3HEI) ; }); - if (shaper != ftMotionShaper_MZV) ACTION_ITEM_N(axis, MSG_FTM_MZV, []{ ftm_menu_set_shaper(ftMotionShaper_MZV) ; }); + if (shaper != ftMotionShaper_NONE) ACTION_ITEM_N(axis, MSG_LCD_OFF, []{ ftm_menu_set_shaper(ftMotionShaper_NONE) ; }); + TERN_(FTM_SHAPER_ZV, if (shaper != ftMotionShaper_ZV) ACTION_ITEM_N(axis, MSG_FTM_ZV, []{ ftm_menu_set_shaper(ftMotionShaper_ZV) ; })); + TERN_(FTM_SHAPER_ZVD, if (shaper != ftMotionShaper_ZVD) ACTION_ITEM_N(axis, MSG_FTM_ZVD, []{ ftm_menu_set_shaper(ftMotionShaper_ZVD) ; })); + TERN_(FTM_SHAPER_ZVDD, if (shaper != ftMotionShaper_ZVDD) ACTION_ITEM_N(axis, MSG_FTM_ZVDD, []{ ftm_menu_set_shaper(ftMotionShaper_ZVDD) ; })); + TERN_(FTM_SHAPER_ZVDDD, if (shaper != ftMotionShaper_ZVDDD) ACTION_ITEM_N(axis, MSG_FTM_ZVDDD,[]{ ftm_menu_set_shaper(ftMotionShaper_ZVDDD) ; })); + TERN_(FTM_SHAPER_EI, if (shaper != ftMotionShaper_EI) ACTION_ITEM_N(axis, MSG_FTM_EI, []{ ftm_menu_set_shaper(ftMotionShaper_EI) ; })); + TERN_(FTM_SHAPER_2HEI, if (shaper != ftMotionShaper_2HEI) ACTION_ITEM_N(axis, MSG_FTM_2HEI, []{ ftm_menu_set_shaper(ftMotionShaper_2HEI) ; })); + TERN_(FTM_SHAPER_3HEI, if (shaper != ftMotionShaper_3HEI) ACTION_ITEM_N(axis, MSG_FTM_3HEI, []{ ftm_menu_set_shaper(ftMotionShaper_3HEI) ; })); + TERN_(FTM_SHAPER_MZV, if (shaper != ftMotionShaper_MZV) ACTION_ITEM_N(axis, MSG_FTM_MZV, []{ ftm_menu_set_shaper(ftMotionShaper_MZV) ; })); END_MENU(); } @@ -375,9 +390,15 @@ void menu_move() { START_MENU(); BACK_ITEM(MSG_FIXED_TIME_MOTION); - if (traj_type != TrajectoryType::TRAPEZOIDAL) ACTION_ITEM(MSG_FTM_TRAPEZOIDAL, []{ ftMotion.updateTrajectoryType(TrajectoryType::TRAPEZOIDAL); ui.go_back(); }); - if (traj_type != TrajectoryType::POLY5) ACTION_ITEM(MSG_FTM_POLY5, []{ ftMotion.updateTrajectoryType(TrajectoryType::POLY5); ui.go_back(); }); - if (traj_type != TrajectoryType::POLY6) ACTION_ITEM(MSG_FTM_POLY6, []{ ftMotion.updateTrajectoryType(TrajectoryType::POLY6); ui.go_back(); }); + if (traj_type != TrajectoryType::TRAPEZOIDAL) ACTION_ITEM(MSG_FTM_TRAPEZOIDAL, []{ + queue.inject(TS(F("M494"), 'T', int(TrajectoryType::TRAPEZOIDAL))); ui.go_back(); + }); + if (traj_type != TrajectoryType::POLY5) ACTION_ITEM(MSG_FTM_POLY5, []{ + queue.inject(TS(F("M494"), 'T', int(TrajectoryType::POLY5))); ui.go_back(); + }); + if (traj_type != TrajectoryType::POLY6) ACTION_ITEM(MSG_FTM_POLY6, []{ + queue.inject(TS(F("M494"), 'T', int(TrajectoryType::POLY6))); ui.go_back(); + }); END_MENU(); } @@ -425,12 +446,18 @@ void menu_move() { START_MENU(); BACK_ITEM_N(MenuItemBase::itemIndex, MSG_FTM_CONFIGURE_AXIS_N); - if (dmode != dynFreqMode_DISABLED) ACTION_ITEM(MSG_LCD_OFF, []{ (void)ftMotion.cfg.setDynFreqMode(dynFreqMode_DISABLED); ui.go_back(); }); + if (dmode != dynFreqMode_DISABLED) ACTION_ITEM(MSG_LCD_OFF, []{ + queue.inject(TS(F("M493D"), int(dynFreqMode_DISABLED))); ui.go_back(); + }); #if HAS_DYNAMIC_FREQ_MM - if (dmode != dynFreqMode_Z_BASED) ACTION_ITEM(MSG_FTM_Z_BASED, []{ (void)ftMotion.cfg.setDynFreqMode(dynFreqMode_Z_BASED); ui.go_back(); }); + if (dmode != dynFreqMode_Z_BASED) ACTION_ITEM(MSG_FTM_Z_BASED, []{ + queue.inject(TS(F("M493D"), int(dynFreqMode_Z_BASED))); ui.go_back(); + }); #endif #if HAS_DYNAMIC_FREQ_G - if (dmode != dynFreqMode_MASS_BASED) ACTION_ITEM(MSG_FTM_MASS_BASED, []{ (void)ftMotion.cfg.setDynFreqMode(dynFreqMode_MASS_BASED); ui.go_back(); }); + if (dmode != dynFreqMode_MASS_BASED) ACTION_ITEM(MSG_FTM_MASS_BASED, []{ + queue.inject(TS(F("M493D"), int(dynFreqMode_MASS_BASED))); ui.go_back(); + }); #endif END_MENU(); @@ -444,33 +471,45 @@ void menu_move() { START_MENU(); BACK_ITEM(MSG_FIXED_TIME_MOTION); - #if HAS_FTM_EI_SHAPING - #define EISHAPER_MENU_ITEM(A) \ - if (AXIS_IS_EISHAPING(A)) \ - EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_VTOL_N, &c.vtol[axis], 0.0f, 1.0f, ftMotion.update_shaping_params); - #else - #define EISHAPER_MENU_ITEM(A) NOOP - #endif - if (false SHAPED_GANG(|| axis == X_AXIS, || axis == Y_AXIS, || axis == Z_AXIS, || axis == E_AXIS)) { + SUBMENU_N_S(axis, get_shaper_name(axis), MSG_FTM_CMPN_MODE, menu_ftm_shaper); - if (AXIS_IS_SHAPING(axis)) { - EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_BASE_FREQ_N, &c.baseFreq[axis], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params); - EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_ZETA_N, &c.zeta[axis], 0.0f, 1.0f, ftMotion.update_shaping_params); - EISHAPER_MENU_ITEM(axis); + if (IS_SHAPING(c.shaper[axis])) { + editable.decimal = c.baseFreq[axis]; + EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_BASE_FREQ_N, &editable.decimal, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, []{ + queue.inject(TS(F("M493"), IAXIS_CHAR(MenuItemBase::itemIndex), 'A', p_float_t(editable.decimal, 3))); + }); + editable.decimal = c.zeta[axis]; + EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_ZETA_N, &editable.decimal, 0.0f, FTM_MAX_DAMPENING, []{ + queue.inject(TS(F("M493"), IAXIS_CHAR(MenuItemBase::itemIndex), 'I', p_float_t(editable.decimal, 3))); + }); + #if HAS_FTM_EI_SHAPING + if (IS_EISHAPING(c.shaper[axis])) { + editable.decimal = c.vtol[axis]; + EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_VTOL_N, &editable.decimal, 0.0f, 1.0f, []{ + queue.inject(TS(F("M493"), IAXIS_CHAR(MenuItemBase::itemIndex), 'Q', p_float_t(editable.decimal, 3))); + }); + } + #endif } } #if ENABLED(FTM_SMOOTHING) editable.decimal = c.smoothingTime[axis]; - EDIT_ITEM_FAST_N(float43, axis, MSG_FTM_SMOOTH_TIME_N, &editable.decimal, 0.0f, FTM_MAX_SMOOTHING_TIME, []{ (void)ftMotion.set_smoothing_time(AxisEnum(MenuItemBase::itemIndex), editable.decimal); }); + EDIT_ITEM_FAST_N(float43, axis, MSG_FTM_SMOOTH_TIME_N, &editable.decimal, 0.0f, FTM_MAX_SMOOTHING_TIME, []{ + queue.inject(TS(F("M494"), IAXIS_CHAR(MenuItemBase::itemIndex), p_float_t(editable.decimal, 4))); + }); #endif #if HAS_DYNAMIC_FREQ if (axis == X_AXIS || axis == Y_AXIS) { SUBMENU_N_S(axis, get_dyn_freq_mode_name(), MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); - if (c.dynFreqMode != dynFreqMode_DISABLED) - EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_DFREQ_K_N, &c.dynFreqK[axis], 0.0f, 20.0f); + if (c.dynFreqMode != dynFreqMode_DISABLED) { + editable.decimal = c.dynFreqK[axis]; + EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_DFREQ_K_N, &editable.decimal, 0.0f, 20.0f, []{ + queue.inject(TS(F("M493"), IAXIS_CHAR(MenuItemBase::itemIndex), 'F', p_float_t(editable.decimal, 3))); + }); + } } #endif @@ -486,8 +525,12 @@ void menu_move() { BACK_ITEM(MSG_MOTION); #if HAS_STANDARD_MOTION - bool show_state = c.active; - EDIT_ITEM(bool, MSG_FIXED_TIME_MOTION, &show_state, []{ (void)ftMotion.toggle(); }); + // Because this uses G-code the display of the actual state will be delayed by an unknown period of time. + // To fix this G-codes M493/M494 could refresh the UI when they are done. + editable.state = c.active; + EDIT_ITEM(bool, MSG_FIXED_TIME_MOTION, &editable.state, []{ + queue.inject(TS(F("M493"), 'S', int(editable.state))); + }); #endif // Show only when FT Motion is active (or optionally always show) @@ -495,13 +538,20 @@ void menu_move() { #if ENABLED(FTM_POLYS) SUBMENU_S(ftMotion.getTrajectoryName(), MSG_FTM_TRAJECTORY, menu_ftm_trajectory_generator); - if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6) - EDIT_ITEM(float42_52, MSG_FTM_POLY6_OVERSHOOT, &c.poly6_acceleration_overshoot, 1.25f, 1.875f); + if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6) { + editable.decimal = c.poly6_acceleration_overshoot; + EDIT_ITEM(float42_52, MSG_FTM_POLY6_OVERSHOOT, &editable.decimal, 1.25f, 1.875f, []{ + queue.inject(TS(F("M494"), 'O', editable.decimal)); + }); + } #endif CARTES_MAP(_FTM_AXIS_SUBMENU); - EDIT_ITEM(bool, MSG_FTM_AXIS_SYNC, &c.axis_sync_enabled); + editable.state = c.axis_sync_enabled; + EDIT_ITEM(bool, MSG_FTM_AXIS_SYNC, &editable.state, []{ + queue.inject(TS(F("M493"), IAXIS_CHAR(MenuItemBase::itemIndex), 'T', int(editable.state))); + }); #if ENABLED(FTM_RESONANCE_TEST) SUBMENU(MSG_FTM_RESONANCE_TEST, menu_ftm_resonance_test); @@ -513,9 +563,6 @@ void menu_move() { void menu_tune_ft_motion() { - // Define stuff ahead of the menu loop - ft_config_t &c = ftMotion.cfg; - #ifdef __AVR__ // Copy Flash strings to RAM for C-string substitution @@ -548,8 +595,12 @@ void menu_move() { #if ENABLED(FTM_POLYS) SUBMENU_S(_traj_name(), MSG_FTM_TRAJECTORY, menu_ftm_trajectory_generator); - if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6) - EDIT_ITEM(float42_52, MSG_FTM_POLY6_OVERSHOOT, &c.poly6_acceleration_overshoot, 1.25f, 1.875f); + if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6) { + editable.decimal = ftMotion.cfg.poly6_acceleration_overshoot; + EDIT_ITEM(float42_52, MSG_FTM_POLY6_OVERSHOOT, &editable.decimal, 1.25f, 1.875f, []{ + queue.inject(TS(F("M494"), 'O', editable.decimal)); + }); + } #endif SHAPED_MAP(_FTM_AXIS_SUBMENU); diff --git a/Marlin/src/lcd/tft/bitmaps/time_elapsed.svg b/Marlin/src/lcd/tft/bitmaps/time_elapsed.svg index da2d37b56b..655ae7bf23 100644 --- a/Marlin/src/lcd/tft/bitmaps/time_elapsed.svg +++ b/Marlin/src/lcd/tft/bitmaps/time_elapsed.svg @@ -1,5 +1,5 @@ - + - + direction_bits.hz; #endif - // Cache the extruder index for this block - TERN_(DISTINCT_E_FACTORS, block_extruder_axis = E_AXIS_N(current_block->extruder)); + // Cache the extruder index / axis for this block + #if ANY(HAS_MULTI_EXTRUDER, MIXING_EXTRUDER) + stepper.stepper_extruder = current_block->extruder; + #endif + #if ENABLED(DISTINCT_E_FACTORS) + block_extruder_axis = E_AXIS_N(current_block->extruder); + #endif const float totalLength = current_block->millimeters; @@ -409,38 +424,41 @@ bool FTMotion::plan_next_block() { } } -/** - * Ensure extruder position stays within floating point precision bounds. - * Float32 numbers have 23 bits of precision, so the minimum increment ("resolution") around a value x is: - * resolution = 2^(floor(log2(|x|)) - 23) - * By resetting at ±1'000mm (1 meter), we get a minimum resolution of ~ 0.00006mm, enough for smoothing to work well. - */ -void FTMotion::ensure_float_precision() { - constexpr float FTM_POSITION_WRAP_THRESHOLD = 1'000.0f; // (mm) Reset when position exceeds this to prevent floating point precision loss - #if HAS_EXTRUDERS - if (fabs(endPos_prevBlock.E) >= FTM_POSITION_WRAP_THRESHOLD) { - const float offset = -endPos_prevBlock.E; - endPos_prevBlock.E += offset; +#if HAS_EXTRUDERS - // Offset extruder shaping buffer - #if ALL(HAS_FTM_SHAPING, FTM_SHAPER_E) - for (uint32_t i = 0; i < FTM_ZMAX; ++i) shaping.E.d_zi[i] += offset; - #endif + /** + * Ensure extruder position stays within floating point precision bounds. + * Float32 numbers have 23 bits of precision, so the minimum increment ("resolution") around a value x is: + * resolution = 2^(floor(log2(|x|)) - 23) + * By resetting at ±1'000mm (1 meter), we get a minimum resolution of ~ 0.00006mm, enough for smoothing to work well. + */ + void FTMotion::ensure_float_precision() { + constexpr float FTM_POSITION_WRAP_THRESHOLD = 1000; // (mm) Reset when position exceeds this to prevent floating point precision loss + if (ABS(endPos_prevBlock.E) < FTM_POSITION_WRAP_THRESHOLD) return; - // Offset extruder smoothing buffer - #if ENABLED(FTM_SMOOTHING) - for (uint8_t i = 0; i < FTM_SMOOTHING_ORDER; ++i) smoothing.E.smoothing_pass[i] += offset; - #endif + const float offset = -endPos_prevBlock.E; - // Offset linear advance previous position - prev_traj_e += offset; + endPos_prevBlock.E = 0; - // Offset stepper current position - const int64_t delta_steps_q48_16 = offset * planner.settings.axis_steps_per_mm[block_extruder_axis] * (1ULL << 16); - stepping.curr_steps_q48_16.E += delta_steps_q48_16; - }; - #endif -} + // Offset extruder shaping buffer + #if ALL(HAS_FTM_SHAPING, FTM_SHAPER_E) + for (uint32_t i = 0; i < ftm_zmax; ++i) shaping.E.d_zi[i] += offset; + #endif + + // Offset extruder smoothing buffer + #if ENABLED(FTM_SMOOTHING) + for (uint8_t i = 0; i < FTM_SMOOTHING_ORDER; ++i) smoothing.E.smoothing_pass[i] += offset; + #endif + + // Offset linear advance previous position + prev_traj_e += offset; + + // Offset stepper current position + const int64_t delta_steps_q48_16 = offset * planner.settings.axis_steps_per_mm[block_extruder_axis] * (1ULL << 16); + stepping.curr_steps_q48_16.E += delta_steps_q48_16; + } + +#endif // HAS_EXTRUDERS xyze_float_t FTMotion::calc_traj_point(const float dist) { xyze_float_t traj_coords; @@ -504,17 +522,20 @@ xyze_float_t FTMotion::calc_traj_point(const float dist) { #if ENABLED(FTM_SMOOTHING) - #define _SMOOTHEN(A) /* Approximate gaussian smoothing via chained EMAs */ \ - if (smoothing.A.alpha > 0.0f) { \ - float smooth_val = traj_coords.A; \ - for (uint8_t _i = 0; _i < FTM_SMOOTHING_ORDER; ++_i) { \ - smoothing.A.smoothing_pass[_i] += (smooth_val - smoothing.A.smoothing_pass[_i]) * smoothing.A.alpha; \ - smooth_val = smoothing.A.smoothing_pass[_i]; \ - } \ - traj_coords.A = smooth_val; \ + // Approximate Gaussian smoothing via chained EMAs + auto _smoothen = [&](const AxisEnum axis, axis_smoothing_t &smoo) { + if (smoo.alpha <= 0.0f) return; + float smooth_val = traj_coords[axis]; + for (uint8_t _i = 0; _i < FTM_SMOOTHING_ORDER; ++_i) { + smoo.smoothing_pass[_i] += (smooth_val - smoo.smoothing_pass[_i]) * smoo.alpha; + smooth_val = smoo.smoothing_pass[_i]; } + traj_coords[axis] = smooth_val; + }; + #define _SMOOTHEN(A) _smoothen(_AXIS(A), smoothing.A); CARTES_MAP(_SMOOTHEN); + max_total_delay += smoothing.largest_delay_samples; #endif // FTM_SMOOTHING @@ -525,27 +546,29 @@ xyze_float_t FTMotion::calc_traj_point(const float dist) { max_total_delay += shaping.largest_delay_samples; // Apply shaping if active on each axis - #define _SHAPE(A) \ - do { \ - const uint32_t group_delay = ftMotion.cfg.axis_sync_enabled \ - ? max_total_delay - TERN0(FTM_SMOOTHING, smoothing.A.delay_samples) \ - : -shaping.A.Ni[0]; \ - /* α=1−exp(−(dt / (τ / order))) */ \ - shaping.A.d_zi[shaping.zi_idx] = traj_coords.A; \ - traj_coords.A = 0; \ - for (uint32_t i = 0; i <= shaping.A.max_i; i++) { \ - /* echo_delay is always positive since Ni[i] = echo_relative_delay - group_delay + max_total_delay */ \ - /* where echo_relative_delay > 0 and group_delay ≤ max_total_delay */ \ - const uint32_t echo_delay = group_delay + shaping.A.Ni[i]; \ - int32_t udiff = shaping.zi_idx - echo_delay; \ - if (udiff < 0) udiff += FTM_ZMAX; \ - traj_coords.A += shaping.A.Ai[i] * shaping.A.d_zi[udiff]; \ - } \ - } while (0); + auto _shape = [&](const AxisEnum axis, axis_shaping_t &shap OPTARG(FTM_SMOOTHING, const axis_smoothing_t &smoo)) { + const uint32_t group_delay = ftMotion.cfg.axis_sync_enabled + ? max_total_delay - TERN0(FTM_SMOOTHING, smoo.delay_samples) + : -shap.Ni[0]; + // + // α = 1 − exp(−(dt / (τ / order))) + // + shap.d_zi[shaping.zi_idx] = traj_coords[axis]; + traj_coords[axis] = 0; + for (uint32_t i = 0; i <= shap.max_i; i++) { + // echo_delay is always positive since Ni[i] = echo_relative_delay - group_delay + max_total_delay + // where echo_relative_delay > 0 and group_delay ≤ max_total_delay + const uint32_t echo_delay = group_delay + shap.Ni[i]; + int32_t udiff = shaping.zi_idx - echo_delay; + if (udiff < 0) udiff += ftm_zmax; + traj_coords[axis] += shap.Ai[i] * shap.d_zi[udiff]; + } + }; + #define _SHAPE(A) _shape(_AXIS(A), shaping.A OPTARG(FTM_SMOOTHING, smoothing.A)); SHAPED_MAP(_SHAPE); - if (++shaping.zi_idx == (FTM_ZMAX)) shaping.zi_idx = 0; + if (++shaping.zi_idx == ftm_zmax) shaping.zi_idx = 0; #endif // HAS_FTM_SHAPING @@ -581,10 +604,16 @@ void FTMotion::fill_stepper_plan_buffer() { // Get distance from trajectory generator xyze_float_t traj_coords = calc_traj_point(currentGenerator->getDistanceAtTime(tau)); - - // Calculate and store stepper plan in buffer - stepping_enqueue(traj_coords); - + if (fastForwardUntilMotion && traj_coords == startPos) { + // Axis synchronization delays all axes. When coming from a reset, there is a ramp up time filling all buffers. + // If the slowest axis doesn't move and it isn't smoothened, this time can be skipped. + // It eliminates idle time when changing smoothing time or shapers and speeds up homing and bed leveling. + } + else { + fastForwardUntilMotion = false; + // Calculate and store stepper plan in buffer + stepping_enqueue(traj_coords); + } } } diff --git a/Marlin/src/module/ft_motion.h b/Marlin/src/module/ft_motion.h index bf6a38a88f..42dab9951d 100644 --- a/Marlin/src/module/ft_motion.h +++ b/Marlin/src/module/ft_motion.h @@ -98,19 +98,63 @@ typedef struct FTConfig { static constexpr TrajectoryType trajectory_type = TrajectoryType::TRAPEZOIDAL; #endif + static void prep_for_shaper_change(); + static void update_shaping_params(); + #if HAS_STANDARD_MOTION bool setActive(const bool a) { if (a == active) return false; stepper.ftMotion_syncPosition(); + prep_for_shaper_change(); active = a; + update_shaping_params(); return true; } #endif + bool setAxisSync(const bool ena) { + if (ena == axis_sync_enabled) return false; + prep_for_shaper_change(); + axis_sync_enabled = ena; + update_shaping_params(); + return true; + } + #if HAS_FTM_SHAPING - constexpr bool goodZeta(const float z) { return WITHIN(z, 0.01f, 1.0f); } - constexpr bool goodVtol(const float v) { return WITHIN(v, 0.00f, 1.0f); } + bool setShaper(const AxisEnum a, const ftMotionShaper_t s) { + if (s == shaper[a]) return false; + prep_for_shaper_change(); + shaper[a] = s; + update_shaping_params(); + return true; + } + + constexpr bool goodZeta(const float z) { return WITHIN(z, 0.00f, ftm_max_dampening); } + + bool setZeta(const AxisEnum a, float z) { + if (z == zeta[a]) return false; + LIMIT(z, 0.00f, ftm_max_dampening); + prep_for_shaper_change(); + zeta[a] = z; + update_shaping_params(); + return true; + } + + #if HAS_FTM_EI_SHAPING + + constexpr bool goodVtol(const float v) { return WITHIN(v, 0.00f, 1.0f); } + + bool setVtol(const AxisEnum a, float v) { + if (v == vtol[a]) return false; + LIMIT(v, 0.00f, 1.0f); + prep_for_shaper_change(); + vtol[a] = v; + update_shaping_params(); + return true; + } + + #endif #if HAS_DYNAMIC_FREQ @@ -121,10 +165,11 @@ typedef struct FTConfig { TERN_(HAS_DYNAMIC_FREQ_MM, case dynFreqMode_Z_BASED:) TERN_(HAS_DYNAMIC_FREQ_G, case dynFreqMode_MASS_BASED:) case dynFreqMode_DISABLED: - planner.synchronize(); + prep_for_shaper_change(); dynFreqMode = dynFreqMode_t(m); break; } + update_shaping_params(); return 1; } @@ -133,12 +178,30 @@ typedef struct FTConfig { || TERN0(HAS_DYNAMIC_FREQ_G, dynFreqMode == dynFreqMode_MASS_BASED)); } + bool setDynFreqK(const AxisEnum a, const float k) { + if (!modeUsesDynFreq()) return false; + if (k == dynFreqK[a]) return false; + prep_for_shaper_change(); + dynFreqK[a] = k; + update_shaping_params(); + return true; + } + #endif // HAS_DYNAMIC_FREQ #endif // HAS_FTM_SHAPING constexpr bool goodBaseFreq(const float f) { return WITHIN(f, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2); } + bool setBaseFreq(const AxisEnum a, float f) { + if (f == baseFreq[a]) return false; + LIMIT(f, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2); + prep_for_shaper_change(); + baseFreq[a] = f; + update_shaping_params(); + return true; + } + void set_defaults() { #if HAS_STANDARD_MOTION active = ENABLED(FTM_IS_DEFAULT_MOTION); @@ -164,6 +227,8 @@ typedef struct FTConfig { #endif // HAS_FTM_SHAPING TERN_(FTM_POLYS, poly6_acceleration_overshoot = FTM_POLY6_ACCELERATION_OVERSHOOT); + + update_shaping_params(); } } ft_config_t; @@ -186,8 +251,6 @@ class FTMotion { static void set_defaults() { cfg.set_defaults(); - TERN_(HAS_FTM_SHAPING, update_shaping_params()); - #if ENABLED(FTM_SMOOTHING) #define _RESET_SMOOTH(A) (void)set_smoothing_time(_AXIS(A), FTM_SMOOTHING_TIME_##A); CARTES_MAP(_RESET_SMOOTH); @@ -210,11 +273,6 @@ class FTMotion { static ResonanceGenerator rtg; // Resonance trajectory generator instance #endif - #if HAS_FTM_SHAPING - // Refresh gains and indices used by shaping functions. - static void update_shaping_params(); - #endif - #if ENABLED(FTM_SMOOTHING) // Refresh alpha and delay samples used by smoothing functions. static void update_smoothing_params(); @@ -271,6 +329,7 @@ class FTMotion { endPos_prevBlock; // (mm) End position of previous block static xyze_float_t ratio; // (ratio) Axis move ratio of block static float tau; // (s) Time since start of block + static bool fastForwardUntilMotion; // Fast forward time if there is no motion // Trajectory generators static TrapezoidalTrajectoryGenerator trapezoidalGenerator; @@ -307,6 +366,19 @@ class FTMotion { static float prev_traj_e; #endif + #if HAS_FTM_SHAPING + // Refresh gains and indices used by shaping functions. + friend void ft_config_t::update_shaping_params(); + static void update_shaping_params(); + #endif + + // Synchronize and reset motion prior to parameter changes + friend void ft_config_t::prep_for_shaper_change(); + static void prep_for_shaper_change() { + planner.synchronize(); + reset(); + } + // Buffers static void discard_planner_block_protected(); static uint32_t calc_runout_samples(); @@ -314,7 +386,7 @@ class FTMotion { static void fill_stepper_plan_buffer(); static xyze_float_t calc_traj_point(const float dist); static bool plan_next_block(); - static void ensure_float_precision(); + static void ensure_float_precision() IF_DISABLED(HAS_EXTRUDERS, {}); }; // class FTMotion diff --git a/Marlin/src/module/ft_motion/shaping.cpp b/Marlin/src/module/ft_motion/shaping.cpp index f4f00a8589..bfefe77ae7 100644 --- a/Marlin/src/module/ft_motion/shaping.cpp +++ b/Marlin/src/module/ft_motion/shaping.cpp @@ -90,7 +90,7 @@ void AxisShaping::set_axis_shaping_A( } break; #endif - #if ENABLED(FTM_SHAPER_H2EI) + #if ENABLED(FTM_SHAPER_2HEI) case ftMotionShaper_2HEI: { max_i = 3U; const float vtolx2 = sq(vtol); @@ -130,61 +130,65 @@ void AxisShaping::set_axis_shaping_A( break; #endif + default: case ftMotionShaper_NONE: max_i = 0; Ai[0] = 1.0f; // No echoes so the whole impulse is applied in the first tap break; } -} +} // set_axis_shaping_A // Refresh the indices used by shaping functions. // Ai[] must be precomputed (if zeta or vtol change, call set_axis_shaping_A first) void AxisShaping::set_axis_shaping_N(const ftMotionShaper_t shaper, const float f, const float zeta) { // Note that protections are omitted for DBZ and for index exceeding array length. - const float df = sqrt ( 1.f - sq(zeta) ); + const float df = SQRT(1.f - sq(zeta)); + + float base = 0.0f; + switch (shaper) { - case ftMotionShaper_ZV: - Ni[1] = LROUND((0.5f / f / df) * (FTM_FS)); - break; - case ftMotionShaper_ZVD: - case ftMotionShaper_EI: - Ni[1] = LROUND((0.5f / f / df) * (FTM_FS)); - Ni[2] = Ni[1] + Ni[1]; - break; - case ftMotionShaper_ZVDD: - case ftMotionShaper_2HEI: - Ni[1] = LROUND((0.5f / f / df) * (FTM_FS)); - Ni[2] = Ni[1] + Ni[1]; - Ni[3] = Ni[2] + Ni[1]; - break; - case ftMotionShaper_ZVDDD: - case ftMotionShaper_3HEI: - Ni[1] = LROUND((0.5f / f / df) * (FTM_FS)); - Ni[2] = Ni[1] + Ni[1]; - Ni[3] = Ni[2] + Ni[1]; - Ni[4] = Ni[3] + Ni[1]; - break; - case ftMotionShaper_MZV: - Ni[1] = LROUND((0.375f / f / df) * (FTM_FS)); - Ni[2] = Ni[1] + Ni[1]; - break; + + #if ANY(FTM_SHAPER_ZV, FTM_SHAPER_ZVD, FTM_SHAPER_EI, FTM_SHAPER_ZVDD, FTM_SHAPER_2HEI, FTM_SHAPER_ZVDDD, FTM_SHAPER_3HEI) + TERN_(FTM_SHAPER_ZV, case ftMotionShaper_ZV: ) + TERN_(FTM_SHAPER_ZVD, case ftMotionShaper_ZVD: ) + TERN_(FTM_SHAPER_EI, case ftMotionShaper_EI: ) + TERN_(FTM_SHAPER_ZVDD, case ftMotionShaper_ZVDD: ) + TERN_(FTM_SHAPER_2HEI, case ftMotionShaper_2HEI: ) + TERN_(FTM_SHAPER_ZVDDD, case ftMotionShaper_ZVDDD: ) + TERN_(FTM_SHAPER_3HEI, case ftMotionShaper_3HEI: ) + base = 0.5f; + break; + #endif + + #if ENABLED(FTM_SHAPER_MZV) + case ftMotionShaper_MZV: base = 0.375f; break; + #endif + case ftMotionShaper_NONE: - // No echoes. - // max_i is set to 0 by set_axis_shaping_A, so delay centroid (Ni[0]) will also correctly be 0 + default: + // No echoes. max_i already set to 0 by set_axis_shaping_A break; } - // Group delay in samples (i.e., Axis delay caused by shaping): sum(Ai * Ni[i]). - // Skipping i=0 since the uncompensated delay of the first impulse is always zero, so Ai[0] * Ni[0] == 0 - float centroid = 0.0f; - for (uint8_t i = 1; i <= max_i; ++i) centroid -= Ai[i] * Ni[i]; + #if HAS_FTM_SHAPING - Ni[0] = LROUND(centroid); + // Compute echo indices + Ni[1] = LROUND((base / f / df) * FTM_FS); + for (uint8_t i = 2; i <= max_i; ++i) Ni[i] = Ni[i - 1] + Ni[1]; - // The resulting echo index can be negative, this is ok because it will be offset - // by the max delay of all axes before it is used. - for (uint8_t i = 1; i <= max_i; ++i) Ni[i] += Ni[0]; -} + // Group delay in samples (i.e., Axis delay caused by shaping): sum(Ai * Ni[i]). + // Skipping i=0 since the uncompensated delay of the first impulse is always zero, + // so Ai[0] * Ni[0] == 0 + float centroid = 0.0f; + for (uint8_t i = 1; i <= max_i; ++i) centroid -= Ai[i] * Ni[i]; + Ni[0] = LROUND(centroid); + + // The resulting echo index can be negative, this is ok because it will be offset + // by the max delay of all axes before it is used. + for (uint8_t i = 1; i <= max_i; ++i) Ni[i] += Ni[0]; + + #endif +} // set_axis_shaping_N #endif // FT_MOTION diff --git a/Marlin/src/module/ft_motion/shaping.h b/Marlin/src/module/ft_motion/shaping.h index f207b3d2b7..0140a969ba 100644 --- a/Marlin/src/module/ft_motion/shaping.h +++ b/Marlin/src/module/ft_motion/shaping.h @@ -91,14 +91,39 @@ typedef FTShapedAxes ft_shaped_float_t; typedef FTShapedAxes ft_shaped_shaper_t; typedef FTShapedAxes ft_shaped_dfm_t; +#define FTM_MAX_DAMPENING 0.25 +constexpr float ftm_max_dampening = float(FTM_MAX_DAMPENING), + ftm_min_df = SQRT(1.0f - sq(ftm_max_dampening)); + +constexpr uint32_t CALC_N1(const float v) { return LROUND((v / FTM_MIN_SHAPE_FREQ / ftm_min_df) * (FTM_FS)); } + +// Maximum delays for shaping functions +constexpr float ftm_shaping_max_i = _MAX(0.0f + OPTARG(FTM_SHAPER_ZV, 1 * CALC_N1(0.5f)) OPTARG(FTM_SHAPER_EI, 2 * CALC_N1(0.5f) ) + OPTARG(FTM_SHAPER_ZVD, 2 * CALC_N1(0.5f)) OPTARG(FTM_SHAPER_2HEI, 3 * CALC_N1(0.5f) ) + OPTARG(FTM_SHAPER_ZVDD, 3 * CALC_N1(0.5f)) OPTARG(FTM_SHAPER_3HEI, 4 * CALC_N1(0.5f) ) + OPTARG(FTM_SHAPER_ZVDDD, 4 * CALC_N1(0.5f)) OPTARG(FTM_SHAPER_MZV, 2 * CALC_N1(0.375f)) +); + +// Max delays for smoothing +constexpr uint32_t ftm_smooth_max_i = uint32_t(TERN0(FTM_SMOOTHING, CEIL(FTM_FS * FTM_MAX_SMOOTHING_TIME))); + +constexpr size_t ftm_zmax = ftm_shaping_max_i + ftm_smooth_max_i; + +constexpr uint8_t ftm_shaping_ni_size = _MAX(1 + OPTARG(FTM_SHAPER_ZV, 2) OPTARG(FTM_SHAPER_EI, 3) + OPTARG(FTM_SHAPER_ZVD, 3) OPTARG(FTM_SHAPER_2HEI, 4) + OPTARG(FTM_SHAPER_ZVDD, 4) OPTARG(FTM_SHAPER_3HEI, 5) + OPTARG(FTM_SHAPER_ZVDDD, 5) OPTARG(FTM_SHAPER_MZV, 3) +); // Shaping data typedef struct AxisShaping { - bool ena = false; // Enabled indication - float d_zi[FTM_ZMAX] = { 0.0f }; // Data point delay vector - float Ai[5]; // Shaping gain vector - int32_t Ni[5]; // Shaping time index vector - uint32_t max_i; // Vector length for the selected shaper + bool ena = false; // Enabled indication + float d_zi[ftm_zmax] = { 0.0f }; // Data point delay vector + float Ai[ftm_shaping_ni_size]; // Shaping gain vector + int32_t Ni[ftm_shaping_ni_size] = { 0 }; // Shaping time index vector + uint32_t max_i; // Vector length for the selected shaper // Set the gains used by shaping functions void set_axis_shaping_N(const ftMotionShaper_t shaper, const float f, const float zeta); @@ -117,7 +142,7 @@ typedef struct Shaping { axis_shaping_t SHAPED_AXIS_NAMES; uint32_t largest_delay_samples; // Shaping an axis makes it lag with respect to the others by certain amount, the "centroid delay" - // Ni[0] stores how far in the past the first step would need to happen to avoid desynchronisation (it is therefore negative). + // Ni[0] stores how far in the past the first step would need to happen to avoid desynchronization (it is therefore negative). // Of course things can't be done in the past, so when shaping is applied, the all axes are delayed by largest_delay_samples // minus their own centroid delay. This makes them all be equally delayed and therefore in synch. void refresh_largest_delay_samples() { largest_delay_samples = -_MIN(SHAPED_LIST(X.Ni[0], Y.Ni[0], Z.Ni[0], E.Ni[0])); } diff --git a/Marlin/src/module/ft_motion/smoothing.h b/Marlin/src/module/ft_motion/smoothing.h index 3e32b2b917..e3f9962a09 100644 --- a/Marlin/src/module/ft_motion/smoothing.h +++ b/Marlin/src/module/ft_motion/smoothing.h @@ -34,22 +34,22 @@ typedef struct FTSmoothedAxes { } ft_smoothed_float_t; // Smoothing data for each axis -// The smoothing algorithm used is an approximation of moving window averaging with gaussian weights, based -// on chained exponential smoothers. +// For the smoothing algorithm use an approximation of moving window averaging +// with Gaussian weights, based on chained exponential smoothers. typedef struct AxisSmoothing { float smoothing_pass[FTM_SMOOTHING_ORDER] = { 0.0f }; // Last value of each of the exponential smoothing passes - float alpha = 0.0f; // Pre-calculated alpha for smoothing. - uint32_t delay_samples = 0; // Pre-calculated delay in samples for smoothing. - void set_time(const float s_time); // Set smoothing time, recalculate alpha and delay. + float alpha = 0.0f; // Pre-calculated alpha for smoothing + uint32_t delay_samples = 0; // Pre-calculated delay in samples for smoothing + void set_time(const float s_time); // Set smoothing time, recalculate alpha and delay } axis_smoothing_t; typedef struct Smoothing { axis_smoothing_t CARTES_AXIS_NAMES; int32_t largest_delay_samples; - // Smoothing causes a phase delay equal to smoothing_time. This delay is componensated for during axis synchronisation, which - // is done by delaying all axes to match the laggiest one (i.e largest_delay_samples). + // Smoothing causes a phase delay equal to smoothing_time. This delay is compensated-for during axis synchronization, + // which is done by delaying all axes to match the laggiest one (i.e., largest_delay_samples). void refresh_largest_delay_samples() { largest_delay_samples = _MAX(CARTES_LIST(X.delay_samples, Y.delay_samples, Z.delay_samples, E.delay_samples)); } - // Note: the delay equals smoothing_time iff the input signal frequency is lower than 1/smoothing_time, luckily for us, this holds in this case + // Note: The delay equals smoothing_time only if the input signal frequency is under 1/smoothing_time; which, luckily, holds in this case. void reset() { #define _CLEAR(A) ZERO(A.smoothing_pass); LOGICAL_AXIS_MAP(_CLEAR); diff --git a/Marlin/src/module/ft_motion/stepping.h b/Marlin/src/module/ft_motion/stepping.h index 474918ec75..b7cbe8391b 100644 --- a/Marlin/src/module/ft_motion/stepping.h +++ b/Marlin/src/module/ft_motion/stepping.h @@ -30,19 +30,22 @@ FORCE_INLINE constexpr uint32_t a_times_b_shift_16(const uint32_t a, const uint3 const uint32_t hi = a >> 16, lo = a & 0x0000FFFF; return (hi * b) + ((lo * b) >> 16); } -#define FTM_NEVER uint32_t(UINT16_MAX) // Reserved number to indicate "no ticks in this frame" (FRAME_TICKS_FP+1 would work too) -constexpr uint32_t FRAME_TICKS = STEPPER_TIMER_RATE / FTM_FS; // Timer ticks per frame (by default, 1kHz) -constexpr uint32_t TICKS_BITS = __builtin_clzl(FRAME_TICKS + 1UL); // Bits to represent the max value (duration of a frame, +1 one for FTM_NEVER). -constexpr uint32_t FTM_Q_INT = 32u - TICKS_BITS; // Bits remaining - // "clz" counts leading zeroes. -constexpr uint32_t FTM_Q = 16u - FTM_Q_INT; // uint16 interval fractional bits. - // Intervals buffer has fixed point numbers with the point on this position -static_assert(FRAME_TICKS < FTM_NEVER, "(STEPPER_TIMER_RATE / FTM_FS) must be < " STRINGIFY(FTM_NEVER) " to fit 16-bit fixed-point numbers."); -static_assert(FRAME_TICKS != 2000 || FTM_Q_INT == 11, "FTM_Q_INT should be 11"); -static_assert(FRAME_TICKS != 2000 || FTM_Q == 5, "FTM_Q should be 5"); -static_assert(FRAME_TICKS != 25000 || FTM_Q_INT == 15, "FTM_Q_INT should be 15"); -static_assert(FRAME_TICKS != 25000 || FTM_Q == 1, "FTM_Q should be 1"); +// Count leading zeroes of v when stored in a 32 bit uint, equivalent to `32 - ceil(log2(v))` +constexpr int CLZ32(const uint32_t v, const int c=0) { + return v ? (TEST32(v, 31)) ? c : CLZ32(v << 1, c + 1) : 32; +} +#define FTM_NEVER uint32_t(UINT16_MAX) // Reserved number to indicate "no ticks in this frame" (FRAME_TICKS_FP+1 would work too) +constexpr uint32_t FRAME_TICKS = STEPPER_TIMER_RATE / FTM_FS; // Timer ticks per frame +constexpr uint32_t FTM_Q_INT = 32u - CLZ32(FRAME_TICKS + 1U); // Bits to represent the integer part of the max value (duration of a frame, +1 one for FTM_NEVER). +constexpr uint32_t FTM_Q = 16u - FTM_Q_INT; // uint16 interval fractional bits. + // Intervals buffer has fixed point numbers with the point on this position + +static_assert(FRAME_TICKS < FTM_NEVER, "(STEPPER_TIMER_RATE / FTM_FS) (" STRINGIFY(STEPPER_TIMER_RATE) " / " STRINGIFY(FTM_FS) ") must be < " STRINGIFY(FTM_NEVER) " to fit 16-bit fixed-point numbers."); + +// Sanity check +static_assert(POW(2, 16 - FTM_Q) > FRAME_TICKS, "FRAME_TICKS in Q format should fit in a uint16"); +static_assert(POW(2, 16 - FTM_Q - 1) <= FRAME_TICKS, "A smaller FTM_Q would still alow a FRAME_TICKS in Q format to fit in a uint16"); // The _FP and _fp suffixes mean the number is in fixed point format with the point at the FTM_Q position. // See: https://en.wikipedia.org/wiki/Fixed-point_arithmetic @@ -151,6 +154,8 @@ typedef struct Stepping { // Buffering part // + #define FTM_BUFFER_MASK (FTM_BUFFER_SIZE - 1u) + stepper_plan_t stepper_plan_buff[FTM_BUFFER_SIZE]; uint32_t stepper_plan_tail = 0, stepper_plan_head = 0; XYZEval curr_steps_q48_16{0}; diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index f39a358457..b11740b00a 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -783,22 +783,29 @@ block_t* Planner::get_future_block(const uint8_t offset) { } /** - * Calculate trapezoid parameters, multiplying the entry- and exit-speeds - * by the provided factors. If entry_factor is 0 don't change the initial_rate. - * Assumes that the implied initial_rate and final_rate are no less than - * sqrt(block->acceleration_steps_per_s2 / 2). This is ensured through - * minimum_planner_speed_sqr / min_entry_speed_sqr - but there's one - * exception in recalculate_trapezoids(). + * Calculate trapezoid (or or update FTM) motion parameters for a block. + * + * `entry_speed` is an optional override in mm/s. + * A value of `0` is a sentinel meaning “do not override the block’s + * existing entry speed / initial_rate.” + * + * This is relied upon by recalculate_trapezoids(), which intentionally + * passes `0` to preserve previously propagated speeds. + * + * Assumes implied entry and exit speeds are >= sqrt(acceleration / 2), + * enforced via minimum_planner_speed_sqr / min_entry_speed_sqr, with one + * controlled exception in recalculate_trapezoids(). * * ############ VERY IMPORTANT ############ - * NOTE: The PRECONDITION to call this function is that the block is - * NOT BUSY and it is marked as RECALCULATE. That WARRANTIES the Stepper ISR - * is not and will not use the block while we modify it. + * PRECONDITIONs to run this function: + * - The block is NOT BUSY. + * - The block is marked RECALCULATE. + * That WARRANTIES the Stepper ISR is not and will not use the block while we modify it. */ void Planner::calculate_trapezoid_for_block(block_t * const block, const float entry_speed, const float exit_speed) { #if ENABLED(FT_MOTION) - block->entry_speed = entry_speed; + if (entry_speed) block->entry_speed = entry_speed; block->exit_speed = exit_speed; #endif @@ -2628,7 +2635,7 @@ bool Planner::_populate_block( // Fast acos(-t) approximation (max. error +-0.033rad = 1.89°) // Based on MinMax polynomial published by W. Randolph Franklin, see - // https://wrf.ecse.rpi.edu/Research/Short_Notes/arcsin/onlyelem.html + // https://wrfranklin.org/Research/Short_Notes/arcsin/onlyelem.html // acos( t) = pi / 2 - asin(x) // acos(-t) = pi - acos(t) ... pi / 2 + asin(x) diff --git a/Marlin/src/module/planner_bezier.cpp b/Marlin/src/module/planner_bezier.cpp index b88301b2f0..bcf92f7e51 100644 --- a/Marlin/src/module/planner_bezier.cpp +++ b/Marlin/src/module/planner_bezier.cpp @@ -67,7 +67,7 @@ static inline float dist1(const float x1, const float y1, const float x2, const /** * The algorithm for computing the step is loosely based on the one in Kig - * (See https://sources.debian.net/src/kig/4:15.08.3-1/misc/kigpainter.cpp/#L759) + * (See https://sources.debian.org/src/kig/4:15.08.3-1/misc/kigpainter.cpp/#L759) * However, we do not use the stack. * * The algorithm goes as it follows: the parameters t runs from 0.0 to diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 86ad562e8c..2a10c83800 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1593,8 +1593,10 @@ void Stepper::isr() { // FT Motion can be toggled if Standard Motion is also active const bool using_ftMotion = ENABLED(NO_STANDARD_MOTION) || TERN0(FT_MOTION, ftMotion.cfg.active); - // We need this variable here to be able to use it in the following loop + // Storage for the soonest timer value of the next possible ISR, used in this do loop hal_timer_t min_ticks; + + // Loop until all events for this ISR have been issued do { hal_timer_t interval = 0; @@ -1744,7 +1746,7 @@ void Stepper::isr() { * Get the current tick value + margin * Assuming at least 6µs between calls to this ISR... * On AVR the ISR epilogue+prologue is estimated at 100 instructions - Give 8µs as margin - * On ARM the ISR epilogue+prologue is estimated at 20 instructions - Give 1µs as margin + * On ARM the ISR epilogue+prologue is estimated at 20 instructions - Give 1µs as margin */ min_ticks = HAL_timer_get_count(MF_TIMER_STEP) + hal_timer_t(TERN(__AVR__, 8, 1) * (STEPPER_TIMER_TICKS_PER_US)); @@ -3623,7 +3625,24 @@ void Stepper::report_positions() { DIR_WAIT_AFTER(); } - // Start step pulses. Edge stepping will toggle the STEP pin. + /** + * - For every axis drive STEP pins + * - If any axes lack DEDGE stepping: + * - Wait for the longest required Pulse Delay + * - Reset state of all non-DEDGE STEP pins + * + * The stepper_extruder must be pre-filled at this point. + * + * Emits macros of the form: [XYZEIJKUVW]_APPLY_STEP(state, ?always?) + * For the standard E axis this expands to: E_STEP_WRITE(stepper_extruder, state) + * + * TODO: For MIXING_EXTRUDER stepping distribute the steps proportionally to the + * E stepper drivers' STEP pins according to pre-calculated Bresenham factors. + * So the events are timed just like normal E stepping; only the STEP pin varies. + */ + + // Start step pulses on all axes including the active Extruder. + // Edge stepping will simply toggle the STEP pin. #define _FTM_STEP_START(A) A##_APPLY_STEP(step_bits.A, false); LOGICAL_AXIS_MAP(_FTM_STEP_START); diff --git a/Marlin/src/module/thermistor/thermistor_13.h b/Marlin/src/module/thermistor/thermistor_13.h index 7e87373948..930deb9d53 100644 --- a/Marlin/src/module/thermistor/thermistor_13.h +++ b/Marlin/src/module/thermistor/thermistor_13.h @@ -21,7 +21,7 @@ */ #pragma once -// R25 = 100 kOhm, beta25 = 4100 K, 4.7 kOhm pull-up, Hisens thermistor +// R25 = 100 kOhm, beta25 = 4100 K, 4.7 kOhm pull-up, Hisense thermistor constexpr temp_entry_t temptable_13[] PROGMEM = { { OV( 20.04), 300 }, { OV( 23.19), 290 }, diff --git a/Marlin/src/module/thermistor/thermistors.h b/Marlin/src/module/thermistor/thermistors.h index f3562d1505..e5dfcf1617 100644 --- a/Marlin/src/module/thermistor/thermistors.h +++ b/Marlin/src/module/thermistor/thermistors.h @@ -122,7 +122,7 @@ typedef struct { raw_adc_t value; celsius_t celsius; } temp_entry_t; #if ANY_THERMISTOR_IS(12) // beta25 = 4700 K, R25 = 100kΩ, Pullup = 4.7kΩ, "Personal calibration for Makibox hot bed" #include "thermistor_12.h" #endif -#if ANY_THERMISTOR_IS(13) // beta25 = 4100 K, R25 = 100kΩ, Pullup = 4.7kΩ, "Hisens" +#if ANY_THERMISTOR_IS(13) // beta25 = 4100 K, R25 = 100kΩ, Pullup = 4.7kΩ, "Hisense" #include "thermistor_13.h" #endif #if ANY_THERMISTOR_IS(14) // beta25 = 4092 K, R25 = 100kΩ, Pullup = 4.7kΩ, "EPCOS" for hot bed diff --git a/Marlin/src/pins/mega/pins_GT2560_REV_A_PLUS.h b/Marlin/src/pins/mega/pins_GT2560_REV_A_PLUS.h index a593393f08..a8410f21f6 100644 --- a/Marlin/src/pins/mega/pins_GT2560_REV_A_PLUS.h +++ b/Marlin/src/pins/mega/pins_GT2560_REV_A_PLUS.h @@ -23,7 +23,7 @@ /** * Geeetech GT2560 Revision A+ board pin assignments - * Schematic: https://www.geeetech.com/wiki/images/d/d3/Hardware_GT2560_RevA%2B.pdf + * Schematic: https://wiki.geeetech.com/images/d/d3/Hardware_GT2560_RevA+.pdf * ATmega2560 */ diff --git a/Marlin/src/pins/mega/pins_GT2560_REV_B.h b/Marlin/src/pins/mega/pins_GT2560_REV_B.h index 24915ce395..966dea7057 100644 --- a/Marlin/src/pins/mega/pins_GT2560_REV_B.h +++ b/Marlin/src/pins/mega/pins_GT2560_REV_B.h @@ -23,7 +23,7 @@ /** * Geeetech GT2560 Rev B Pins - * Schematic: https://www.geeetech.com/wiki/images/7/72/GT2560_REVB.pdf + * Schematic: https://wiki.geeetech.com/images/7/72/GT2560_REVB.pdf * ATmega2560 */ diff --git a/Marlin/src/pins/mega/pins_PROTONEER_CNC_SHIELD_V3.h b/Marlin/src/pins/mega/pins_PROTONEER_CNC_SHIELD_V3.h index 4b7d1007be..94bc6ebab0 100644 --- a/Marlin/src/pins/mega/pins_PROTONEER_CNC_SHIELD_V3.h +++ b/Marlin/src/pins/mega/pins_PROTONEER_CNC_SHIELD_V3.h @@ -23,7 +23,7 @@ /** * Protoneer v3.00 pin assignments - * Schematic: https://i0.wp.com/blog.protoneer.co.nz/wp-content/uploads/2013/07/Arduino-CNC-Shield-Scematics-V3.XX_.jpg + * Schematic: https://hexmix.ru/wp-content/uploads/2019/03/Arduino-CNC-Shield-V3.XX_.pdf * ATmega2560 * * This CNC shield has an UNO pinout and fits all Arduino-compatibles. diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 56c4b78dff..a89f1e1d52 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -1072,7 +1072,7 @@ #elif MB(ERROR) #warning "Most likely missing / misplaced Configuration files." #elif defined(MOTHERBOARD) - #error "Unknown MOTHERBOARD value set in Configuration.h." + static_assert(false, "Unknown MOTHERBOARD value (" STRINGIFY(MOTHERBOARD) ") set in Configuration.h."); #else #error "MOTHERBOARD not defined! Use '#define MOTHERBOARD BOARD_...' in Configuration.h." #endif diff --git a/Marlin/src/pins/ramps/pins_DUPLICATOR_I3_PLUS.h b/Marlin/src/pins/ramps/pins_DUPLICATOR_I3_PLUS.h index 40351d2bde..edac07fdd1 100644 --- a/Marlin/src/pins/ramps/pins_DUPLICATOR_I3_PLUS.h +++ b/Marlin/src/pins/ramps/pins_DUPLICATOR_I3_PLUS.h @@ -181,5 +181,5 @@ * ################################## * * Pictogram by Ludy https://github.com/Ludy87 - * See: https://sebastien.andrivet.com/en/posts/wanhao-duplicator-i3-plus-3d-printer/ + * See: https://sebastien.andrivet.com/en/posts/wanhao-duplicator-i3-plus-3d-printers/ */ diff --git a/Marlin/src/pins/ramps/pins_K8200.h b/Marlin/src/pins/ramps/pins_K8200.h index b6bed2dc55..f8d6c3d804 100644 --- a/Marlin/src/pins/ramps/pins_K8200.h +++ b/Marlin/src/pins/ramps/pins_K8200.h @@ -24,7 +24,7 @@ /** * K8200 Arduino Mega with RAMPS v1.3 pin assignments * Identical to 3DRAG - * Schematic: https://www.velleman.eu/images/tmp/K8200diagram.jpg + * Schematic: https://cdn.velleman.eu/images/tmp/K8200diagram.jpg * ATmega2560 */ diff --git a/Marlin/src/pins/ramps/pins_K8400.h b/Marlin/src/pins/ramps/pins_K8400.h index 31912064d0..210c5a9cd9 100644 --- a/Marlin/src/pins/ramps/pins_K8400.h +++ b/Marlin/src/pins/ramps/pins_K8400.h @@ -24,7 +24,7 @@ /** * Velleman K8400 (Vertex) * 3DRAG clone - * Schematic: https://filimprimante3d.fr/documents/k8400-schema-electronique.jpg + * Schematic: https://www.filimprimante3d.fr/documents/k8400-schema-electronique.jpg * ATmega2560, ATmega1280 * * K8400 has some minor differences over a normal 3Drag: diff --git a/Marlin/src/pins/ramps/pins_VORON.h b/Marlin/src/pins/ramps/pins_VORON.h index ee3d7f0185..7da23b3ae5 100644 --- a/Marlin/src/pins/ramps/pins_VORON.h +++ b/Marlin/src/pins/ramps/pins_VORON.h @@ -23,7 +23,7 @@ /** * VORON Design v2 pin assignments - * See https://github.com/mzbotreprap/VORON/blob/master/Firmware/Marlin/pins_RAMPS_VORON.h + * See https://github.com/thaytan/VORON/blob/master/Firmware/Marlin/pins_RAMPS_VORON.h * ATmega2560 */ diff --git a/Marlin/src/pins/rp2040/pins_BTT_SKR_Pico.h b/Marlin/src/pins/rp2040/pins_BTT_SKR_Pico.h index 7eb0188820..d9e686ad5b 100644 --- a/Marlin/src/pins/rp2040/pins_BTT_SKR_Pico.h +++ b/Marlin/src/pins/rp2040/pins_BTT_SKR_Pico.h @@ -107,51 +107,35 @@ // #define NEOPIXEL_PIN 24 +// Custom serial pins for RP2040 UART remapping +#define SERIAL1_TX_PIN 8 +#define SERIAL1_RX_PIN 9 + /** * TMC2208/TMC2209 stepper drivers */ #if HAS_TMC_UART /** * Hardware serial communication ports. - * If undefined software serial is used according to the pins below */ - //#define X_HARDWARE_SERIAL Serial1 - //#define X2_HARDWARE_SERIAL Serial1 - //#define Y_HARDWARE_SERIAL Serial1 - //#define Y2_HARDWARE_SERIAL Serial1 - //#define Z_HARDWARE_SERIAL MSerial1 - //#define Z2_HARDWARE_SERIAL Serial1 - //#define E0_HARDWARE_SERIAL Serial1 - //#define E1_HARDWARE_SERIAL Serial1 - //#define E2_HARDWARE_SERIAL Serial1 - //#define E3_HARDWARE_SERIAL Serial1 - //#define E4_HARDWARE_SERIAL Serial1 + #define X_HARDWARE_SERIAL MarlinSerial1 + #define Y_HARDWARE_SERIAL MarlinSerial1 + #define Z_HARDWARE_SERIAL MarlinSerial1 + #define E0_HARDWARE_SERIAL MarlinSerial1 - /** - * Software serial - */ - #ifndef X_SERIAL_TX_PIN - #define X_SERIAL_TX_PIN 8 + // Default TMC slave addresses + #ifndef X_SLAVE_ADDRESS + #define X_SLAVE_ADDRESS 0 #endif - #ifndef X_SERIAL_RX_PIN - #define X_SERIAL_RX_PIN 9 + #ifndef Y_SLAVE_ADDRESS + #define Y_SLAVE_ADDRESS 2 #endif - #ifndef Y_SERIAL_TX_PIN - #define Y_SERIAL_TX_PIN 8 + #ifndef Z_SLAVE_ADDRESS + #define Z_SLAVE_ADDRESS 1 #endif - #ifndef Y_SERIAL_RX_PIN - #define Y_SERIAL_RX_PIN 9 - #endif - #ifndef Z_SERIAL_TX_PIN - #define Z_SERIAL_TX_PIN 8 - #endif - #ifndef Z_SERIAL_RX_PIN - #define Z_SERIAL_RX_PIN 9 - #endif - #ifndef E0_SERIAL_TX_PIN - #define E0_SERIAL_TX_PIN 8 - #endif - #ifndef E0_SERIAL_RX_PIN - #define E0_SERIAL_RX_PIN 9 + #ifndef E0_SLAVE_ADDRESS + #define E0_SLAVE_ADDRESS 3 #endif + + #define TMC_BAUD_RATE 115200 #endif diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h index d3f435a25c..c2810f313b 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_LITE_V1_0.h @@ -23,7 +23,7 @@ /** * Bricolemon Lite Board. Based on atsamd51 (AGCM4), bootloader and credits by ADAFRUIT. - * https://lemoncrest.com https://bricogeek.com + * https://lemoncrest.com https://tienda.bricogeek.com * * This board its a 3.3V LOGIC Board, following the ADAFRUIT example, all of the board is open source. * Schematic: Refer to the Bricolemon diff --git a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h index cbd655d7fe..5e981d4270 100644 --- a/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h +++ b/Marlin/src/pins/samd/pins_BRICOLEMON_V1_0.h @@ -23,7 +23,7 @@ /** * Bricolemon Board. Based on ATSAMD51 (AGCM4), bootloader and credits by ADAFRUIT. - * https://lemoncrest.com https://bricogeek.com + * https://lemoncrest.com https://tienda.bricogeek.com */ #if NOT_TARGET(ARDUINO_GRAND_CENTRAL_M4) diff --git a/Marlin/src/pins/samd/pins_MINITRONICS20.h b/Marlin/src/pins/samd/pins_MINITRONICS20.h index bd673ff3da..d3851b8cad 100644 --- a/Marlin/src/pins/samd/pins_MINITRONICS20.h +++ b/Marlin/src/pins/samd/pins_MINITRONICS20.h @@ -24,6 +24,7 @@ /** * ReprapWorld Minitronics v2.0 * https://reprap.org/wiki/Minitronics_20 + * https://www.123-3d.nl/pdf/datasheet_minitronics_20_20181003.pdf * 48MHz Atmel SAMD21J18 ARM Cortex-M0+ */ diff --git a/Marlin/src/pins/sanguino/pins_ANET_10.h b/Marlin/src/pins/sanguino/pins_ANET_10.h index 0d87e9ad0e..4c39ed63d1 100644 --- a/Marlin/src/pins/sanguino/pins_ANET_10.h +++ b/Marlin/src/pins/sanguino/pins_ANET_10.h @@ -54,7 +54,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * @@ -76,7 +76,6 @@ * Anet Schematics - https://github.com/ralf-e/ANET-3D-Board-V1.0 * Wiring RRDFG Smart Controller - https://www.thingiverse.com/thing:2103748 * SkyNet3D Anet software development - https://github.com/SkyNet3D/Marlin/ - * Anet Users / Skynet SW on Facebook - https://www.facebook.com/skynet3ddevelopment/ * * Many thanks to Hans Raaf (@oderwat) for developing the Anet-specific software and supporting the Anet community. */ diff --git a/Marlin/src/pins/sanguino/pins_GEN3_MONOLITHIC.h b/Marlin/src/pins/sanguino/pins_GEN3_MONOLITHIC.h index 7befd7fe0a..0e8a2dba3a 100644 --- a/Marlin/src/pins/sanguino/pins_GEN3_MONOLITHIC.h +++ b/Marlin/src/pins/sanguino/pins_GEN3_MONOLITHIC.h @@ -30,7 +30,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_GEN3_PLUS.h b/Marlin/src/pins/sanguino/pins_GEN3_PLUS.h index d9c07eec50..1f5f3808e1 100644 --- a/Marlin/src/pins/sanguino/pins_GEN3_PLUS.h +++ b/Marlin/src/pins/sanguino/pins_GEN3_PLUS.h @@ -29,7 +29,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_GEN6.h b/Marlin/src/pins/sanguino/pins_GEN6.h index e3c5802919..d4604e9a2e 100644 --- a/Marlin/src/pins/sanguino/pins_GEN6.h +++ b/Marlin/src/pins/sanguino/pins_GEN6.h @@ -30,7 +30,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_GEN6_DELUXE.h b/Marlin/src/pins/sanguino/pins_GEN6_DELUXE.h index ffe14e6974..3ed060563d 100644 --- a/Marlin/src/pins/sanguino/pins_GEN6_DELUXE.h +++ b/Marlin/src/pins/sanguino/pins_GEN6_DELUXE.h @@ -29,7 +29,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_GEN7_12.h b/Marlin/src/pins/sanguino/pins_GEN7_12.h index 691199f64e..315dd2816b 100644 --- a/Marlin/src/pins/sanguino/pins_GEN7_12.h +++ b/Marlin/src/pins/sanguino/pins_GEN7_12.h @@ -33,7 +33,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_GEN7_13.h b/Marlin/src/pins/sanguino/pins_GEN7_13.h index 8ec4d4928f..76f4ca371a 100644 --- a/Marlin/src/pins/sanguino/pins_GEN7_13.h +++ b/Marlin/src/pins/sanguino/pins_GEN7_13.h @@ -29,7 +29,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_GEN7_14.h b/Marlin/src/pins/sanguino/pins_GEN7_14.h index 2e4cacb56e..8d4d896958 100644 --- a/Marlin/src/pins/sanguino/pins_GEN7_14.h +++ b/Marlin/src/pins/sanguino/pins_GEN7_14.h @@ -31,7 +31,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_GEN7_CUSTOM.h b/Marlin/src/pins/sanguino/pins_GEN7_CUSTOM.h index eb03fe3178..a9a3d2bb22 100644 --- a/Marlin/src/pins/sanguino/pins_GEN7_CUSTOM.h +++ b/Marlin/src/pins/sanguino/pins_GEN7_CUSTOM.h @@ -32,7 +32,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_MELZI_CREALITY.h b/Marlin/src/pins/sanguino/pins_MELZI_CREALITY.h index adbbbc0300..409e84d332 100644 --- a/Marlin/src/pins/sanguino/pins_MELZI_CREALITY.h +++ b/Marlin/src/pins/sanguino/pins_MELZI_CREALITY.h @@ -30,7 +30,7 @@ * If you don't have a chip programmer you can use a spare Arduino plus a few * electronic components to write the bootloader. * - * See https://www.instructables.com/id/Burn-Arduino-Bootloader-with-Arduino-MEGA/ + * See https://www.instructables.com/Burn-Arduino-Bootloader-with-Arduino-MEGA/ * * Schematic: https://bit.ly/2XOnsWb */ diff --git a/Marlin/src/pins/sanguino/pins_OMCA.h b/Marlin/src/pins/sanguino/pins_OMCA.h index 07a614a7ff..abab4fe48b 100644 --- a/Marlin/src/pins/sanguino/pins_OMCA.h +++ b/Marlin/src/pins/sanguino/pins_OMCA.h @@ -56,7 +56,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_OMCA_A.h b/Marlin/src/pins/sanguino/pins_OMCA_A.h index b60591aa58..593f606c2a 100644 --- a/Marlin/src/pins/sanguino/pins_OMCA_A.h +++ b/Marlin/src/pins/sanguino/pins_OMCA_A.h @@ -54,7 +54,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h b/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h index b1a91dc72c..77cda78a95 100644 --- a/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h +++ b/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h @@ -34,7 +34,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/sanguino/pins_SETHI.h b/Marlin/src/pins/sanguino/pins_SETHI.h index 66e7e64d4f..96efe27ebe 100644 --- a/Marlin/src/pins/sanguino/pins_SETHI.h +++ b/Marlin/src/pins/sanguino/pins_SETHI.h @@ -29,7 +29,7 @@ * Requires this Arduino IDE extension for Boards Manager: * https://github.com/Lauszus/Sanguino * - * Follow the installation instructions at https://learn.sparkfun.com/pages/CustomBoardsArduino + * Follow the installation instructions at https://learn.sparkfun.com/tutorials/installing-board-definitions-in-the-arduino-ide * Just use this JSON URL instead of Sparkfun's: * https://raw.githubusercontent.com/Lauszus/Sanguino/master/package_lauszus_sanguino_index.json * diff --git a/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h b/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h index 62ecaf10b6..63b0ada609 100644 --- a/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h +++ b/Marlin/src/pins/stm32f1/pins_GTM32_PRO_VB.h @@ -23,7 +23,7 @@ /** * Geeetech GTM32 Pro VB board pin assignments - * https://www.geeetech.com/wiki/index.php/File:Hardware_GTM32_PRO_VB.pdf + * https://wiki.geeetech.com/index.php/File:Hardware_GTM32_PRO_VB.pdf * * Also applies to GTM32 Pro VD */ diff --git a/Marlin/src/pins/stm32f4/pins_LERDGE_S.h b/Marlin/src/pins/stm32f4/pins_LERDGE_S.h index 0d129cb624..ee9b46bc6e 100644 --- a/Marlin/src/pins/stm32f4/pins_LERDGE_S.h +++ b/Marlin/src/pins/stm32f4/pins_LERDGE_S.h @@ -102,7 +102,7 @@ #define TEMP_1_TR_ENABLE_PIN PF4 // MAX6675 Cold-Junction-Compensated K-Thermocouple to Digital Converter (0°C to +1024°C) -// https://datasheets.maximintegrated.com/en/ds/MAX6675.pdf +// https://datasheets.maximintegrated.com/en/ds/max6675.pdf #define TEMP_0_CS_PIN PC4 // max6675 datasheet: /CS pin, found with multimeter, not tested and likely wrong #define TEMP_0_SCK_PIN PB3 // max6675 datasheet: SCK pin, found with multimeter, not tested diff --git a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h index 9474616f4c..9d2b279b43 100644 --- a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h +++ b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV3.h @@ -23,7 +23,7 @@ /** * STM32F407VET6 on Opulo Lumen PnP Rev3 - * Website - https://opulo.io/ + * Website - https://www.opulo.io/ */ #define ALLOW_STM32DUINO diff --git a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h index 03bb77c265..2cdf80f951 100644 --- a/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h +++ b/Marlin/src/pins/stm32f4/pins_OPULO_LUMEN_REV4.h @@ -23,7 +23,7 @@ /** * STM32F407VET6 on Opulo Lumen PnP Rev3 - * Website - https://opulo.io/ + * Website - https://www.opulo.io/ */ #define ALLOW_STM32DUINO diff --git a/Marlin/src/pins/teensy2/pins_BRAINWAVE.h b/Marlin/src/pins/teensy2/pins_BRAINWAVE.h index 8bdd926dda..445cb45121 100644 --- a/Marlin/src/pins/teensy2/pins_BRAINWAVE.h +++ b/Marlin/src/pins/teensy2/pins_BRAINWAVE.h @@ -25,53 +25,23 @@ * Brainwave 1.0 pin assignments (AT90USB646) * https://www.reprap.org/wiki/Brainwave * - * Requires hardware bundle for Arduino: - * https://github.com/unrepentantgeek/brainwave-arduino - * * Schematic: https://github.com/unrepentantgeek/Brainwave/blob/master/brainwave/brainwave.sch - */ - -/** + * + * Build with PlatformIO for best results. + * + * Arduino IDE requires hardware bundle + * https://github.com/unrepentantgeek/brainwave-arduino + * (May also require retired Marlin_AT90USB package) + * * Rev B 16 JAN 2017 + * - Added pointer to a currently available Arduino IDE extension that will + * allow this board to use the latest Marlin software * - * Added pointer to a currently available Arduino IDE extension that will - * allow this board to use the latest Marlin software - */ - -/** * Rev C 2 JUN 2017 - * - * Converted to Arduino pin numbering + * - Converted to Arduino pin numbering */ -/** - * Marlin_AT90USB - https://github.com/Bob-the-Kuhn/Marlin_AT90USB - * This is the only known IDE extension that is compatible with the pin definitions - * in this file, Adrduino 1.6.12 and the latest mainstream Marlin software. - * - * "Marlin_AT90USB" makes PWM0A available rather than the usual PWM1C. These PWMs share - * the same physical pin. Marlin uses TIMER1 to generate interrupts and sets it up such - * that PWM1A, PWM1B & PWM1C can't be used. - * - * Installation: - * - * 1. In the Arduino IDE, under Files -> Preferences paste the following URL - * https://rawgit.com/Bob-the-Kuhn/Marlin_AT90USB/master/package_MARLIN_AT90USB_index.json - * 2. Under Tools > Board -> Boards manager, scroll to the bottom, click on MARLIN_AT90USB - * and then click on "Install" - * 3. Select "AT90USB646_TEENSYPP" from the 'Tools > Board' menu. - */ - -/** - * To burn the bootloader that comes with Marlin_AT90USB: - * - * 1. Connect your programmer to the board. - * 2. In Arduino IDE select "AT90USB646_TEENSYPP" and then select the programmer. - * 3. In Arduino IDE click on "burn bootloader". Don't worry about the "verify failed at 1F000" error message. - * 4. The programmer is no longer needed. Remove it. - */ - -#if NOT_TARGET(__AVR_AT90USB646__) +#if NOT_TARGET(__AVR_AT90USB646__, __AVR_AT90USB1286__) #error "Oops! Select 'Brainwave' in 'Tools > Board.'" #endif diff --git a/Marlin/src/sd/SdInfo.h b/Marlin/src/sd/SdInfo.h index bfa5a01ae2..9c97820048 100644 --- a/Marlin/src/sd/SdInfo.h +++ b/Marlin/src/sd/SdInfo.h @@ -39,7 +39,7 @@ // Version 3.01 // May 18, 2010 // -// https://www.sdcard.org/downloads/pls/index.html +// https://www.sdcard.org/downloads/pls/ // SD card commands uint8_t const CMD0 = 0x00, // GO_IDLE_STATE - init card in spi mode if CS low diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 98b44e5d14..b6a0c73c09 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -102,23 +102,15 @@ int16_t CardReader::nrItems = -1; //bool CardReader::sort_reverse; #endif - #if ENABLED(SDSORT_DYNAMIC_RAM) - uint8_t *CardReader::sort_order; - #else - uint8_t CardReader::sort_order[SDSORT_LIMIT]; - #endif + uint8_t *CardReader::sort_order; #if ENABLED(SDSORT_USES_RAM) #if ENABLED(SDSORT_CACHE_NAMES) - #if ENABLED(SDSORT_DYNAMIC_RAM) - char **CardReader::sortshort, **CardReader::sortnames; - #else - char CardReader::sortshort[SDSORT_LIMIT][FILENAME_LENGTH]; - char CardReader::sortnames[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE]; - #endif - #elif DISABLED(SDSORT_USES_STACK) - char CardReader::sortnames[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE]; + char (*CardReader::sortshort)[FILENAME_LENGTH]; + #endif + #if ENABLED(SDSORT_CACHE_NAMES) || DISABLED(SDSORT_USES_STACK) + char (*CardReader::sortnames)[SORTED_LONGNAME_STORAGE]; #endif #if HAS_FOLDER_SORTING @@ -163,6 +155,19 @@ uint32_t CardReader::filesize, CardReader::sdpos; CardReader::CardReader() { #if ENABLED(SDCARD_SORT_ALPHA) + #if DISABLED(SDSORT_DYNAMIC_RAM) + static uint8_t sort_order_static[SDSORT_LIMIT]; + sort_order = sort_order_static; + #endif + #if ENABLED(SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM) + static char sortshort_static[SDSORT_LIMIT][FILENAME_LENGTH]; + sortshort = sortshort_static; + #endif + #if ENABLED(SDSORT_CACHE_NAMES) && !ALL(SDSORT_DYNAMIC_RAM, SDSORT_USES_STACK) + static char sortnames_static[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE]; + sortnames = sortnames_static; + #endif + sort_count = 0; #if ENABLED(SDSORT_GCODE) sort_alpha = TERN(SDSORT_REVERSE, AS_REV, AS_FWD); @@ -204,8 +209,8 @@ char *createFilename(char * const buffer, const dir_t &p) { return buffer; } -inline bool extIsBIN(char *ext) { - return ext[0] == 'B' && ext[1] == 'I' && ext[2] == 'N'; +inline bool extIsBIN(char * const ext) { + return ext && ext[0] == 'B' && ext[1] == 'I' && ext[2] == 'N'; } // @@ -1122,7 +1127,8 @@ void CardReader::selectFileByIndex(const int16_t nr) { strcpy(filename, sortshort[nr]); strcpy(longFilename, sortnames[nr]); TERN_(HAS_FOLDER_SORTING, flag.filenameIsDir = IS_DIR(nr)); - setBinFlag(extIsBIN(strrchr(filename, '.') + 1)); + char *ext = strrchr(filename, '.'); + setBinFlag(extIsBIN(ext ? ext + 1 : nullptr)); return; } #endif @@ -1136,14 +1142,17 @@ void CardReader::selectFileByIndex(const int16_t nr) { // void CardReader::selectFileByName(const char * const match) { #if ENABLED(SDSORT_CACHE_NAMES) - for (int16_t nr = 0; nr < sort_count; nr++) - if (strcasecmp(match, sortshort[nr]) == 0) { - strcpy(filename, sortshort[nr]); + for (int16_t nr = 0; nr < sort_count; nr++) { + const char *name = sortshort[nr]; + if (strcasecmp(match, name) == 0) { + strcpy(filename, name); strcpy(longFilename, sortnames[nr]); TERN_(HAS_FOLDER_SORTING, flag.filenameIsDir = IS_DIR(nr)); - setBinFlag(extIsBIN(strrchr(filename, '.') + 1)); + char *ext = strrchr(filename, '.'); + setBinFlag(extIsBIN(ext ? ext + 1 : nullptr)); return; } + } #endif workDir.rewind(); selectByName(workDir, match); @@ -1306,11 +1315,11 @@ void CardReader::cdroot() { #if ENABLED(SDSORT_USES_RAM) #if ENABLED(SDSORT_DYNAMIC_RAM) // Use dynamic method to copy long filename - #define SET_SORTNAME(I) (sortnames[I] = strdup(longest_filename())) + #define SET_SORTNAME(I) strlcpy(sortnames[I], longest_filename(), SORTED_LONGNAME_STORAGE) #if ENABLED(SDSORT_CACHE_NAMES) // When caching also store the short name, since // we're replacing the selectFileByIndex() behavior. - #define SET_SORTSHORT(I) (sortshort[I] = strdup(filename)) + #define SET_SORTSHORT(I) strlcpy(sortshort[I], filename, SORTED_SHORTNAME_STORAGE) #else #define SET_SORTSHORT(I) NOOP #endif @@ -1366,8 +1375,8 @@ void CardReader::cdroot() { // If using dynamic ram for names, allocate on the heap. #if ENABLED(SDSORT_CACHE_NAMES) #if ENABLED(SDSORT_DYNAMIC_RAM) - sortshort = new char*[fileCnt]; - sortnames = new char*[fileCnt]; + sortshort = new char[fileCnt][SORTED_SHORTNAME_STORAGE]; + sortnames = new char[fileCnt][SORTED_LONGNAME_STORAGE]; #endif #elif ENABLED(SDSORT_USES_STACK) char sortnames[fileCnt][SORTED_LONGNAME_STORAGE]; @@ -1388,7 +1397,7 @@ void CardReader::cdroot() { // Init sort order. for (int16_t i = 0; i < fileCnt; i++) { - sort_order[i] = i; + sort_order[i] = uint8_t(i); // If using RAM then read all filenames now. #if ENABLED(SDSORT_USES_RAM) selectFileByIndex(i); @@ -1427,18 +1436,18 @@ void CardReader::cdroot() { const char *name1 = sortnames[o1], *name2 = sortnames[o2]; #endif - #if HAS_FOLDER_SORTING - #if ENABLED(SDSORT_GCODE) - if (sort_folders && dir1 != dir2) - return (sort_folders > 0) ? dir1 : !dir1; - #else - if (dir1 != dir2) - return (SDSORT_FOLDERS > 0) ? dir1 : !dir1; - #endif + #if ENABLED(SDSORT_GCODE) + if (sort_folders && dir1 != dir2) + return (sort_folders > 0) ? !dir1 : dir1; + #elif SDSORT_FOLDERS + if (dir1 != dir2) + return (SDSORT_FOLDERS > 0) ? !dir1 : dir1; #endif - const bool sort = strcasecmp(name1, name2) < 0; - return (TERN(SDSORT_GCODE, sort_alpha == AS_REV, ENABLED(SDSORT_REVERSE))) ? !sort : sort; + const bool sort = strcasecmp(name1, name2) < 0, + reversed = TERN(SDSORT_GCODE, sort_alpha == AS_REV, ENABLED(SDSORT_REVERSE)); + + return reversed ? !sort : sort; }; auto partition = [&](uint8_t* arr, int16_t low, int16_t high) -> int16_t { @@ -1523,7 +1532,11 @@ void CardReader::cdroot() { const bool sort = strcasecmp(n1, n2) > 0; return (TERN(SDSORT_GCODE, sort_alpha == AS_REV, ENABLED(SDSORT_REVERSE))) ? !sort : sort; }; - #define _SORT_CMP_FILE() _sort_cmp_file(TERN(SDSORT_USES_RAM, sortnames[o1], name1), TERN(SDSORT_USES_RAM, sortnames[o2], name2)) + #if ENABLED(SDSORT_USES_RAM) + #define _SORT_CMP_FILE() _sort_cmp_file(sortnames[o1], sortnames[o2]) + #else + #define _SORT_CMP_FILE() _sort_cmp_file(name1, name2) + #endif #if HAS_FOLDER_SORTING #if ENABLED(SDSORT_USES_RAM) @@ -1576,19 +1589,16 @@ void CardReader::cdroot() { #endif // Bubble Sort // Using RAM but not keeping names around - #if ENABLED(SDSORT_USES_RAM) && DISABLED(SDSORT_CACHE_NAMES) - #if ENABLED(SDSORT_DYNAMIC_RAM) - for (int16_t i = 0; i < fileCnt; ++i) free(sortnames[i]); - TERN_(HAS_FOLDER_SORTING, delete [] isDir); - #endif + #if ALL(HAS_FOLDER_SORTING, SDSORT_DYNAMIC_RAM) && DISABLED(SDSORT_CACHE_NAMES) + delete [] isDir; #endif } else { - sort_order[0] = 0; + sort_order[0] = uint8_t(0); #if ALL(SDSORT_USES_RAM, SDSORT_CACHE_NAMES) #if ENABLED(SDSORT_DYNAMIC_RAM) - sortnames = new char*[1]; - sortshort = new char*[1]; + sortnames = new char[1][SORTED_LONGNAME_STORAGE]; + sortshort = new char[1][SORTED_SHORTNAME_STORAGE]; #endif selectFileByIndex(0); SET_SORTNAME(0); @@ -1609,10 +1619,6 @@ void CardReader::cdroot() { #if ENABLED(SDSORT_DYNAMIC_RAM) delete [] sort_order; #if ENABLED(SDSORT_CACHE_NAMES) - for (uint8_t i = 0; i < sort_count; ++i) { - free(sortshort[i]); // strdup - free(sortnames[i]); // strdup - } delete [] sortshort; delete [] sortnames; #endif diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h index c6b3dc6384..5956ffd091 100644 --- a/Marlin/src/sd/cardreader.h +++ b/Marlin/src/sd/cardreader.h @@ -360,12 +360,8 @@ private: //static bool sort_reverse; // Flag to enable / disable reverse sorting #endif - // By default the sort index is statically allocated - #if ENABLED(SDSORT_DYNAMIC_RAM) - static uint8_t *sort_order; - #else - static uint8_t sort_order[SDSORT_LIMIT]; - #endif + // Pointer to the static or dynamic sort index + static uint8_t *sort_order; #if ALL(SDSORT_USES_RAM, SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM) #define SORTED_LONGNAME_MAXLEN (SDSORT_CACHE_VFATS) * (FILENAME_LENGTH) @@ -375,20 +371,17 @@ private: #define SORTED_LONGNAME_STORAGE SORTED_LONGNAME_MAXLEN #endif + #define SORTED_SHORTNAME_STORAGE FILENAME_LENGTH + // Cache filenames to speed up SD menus. #if ENABLED(SDSORT_USES_RAM) - // If using dynamic ram for names, allocate on the heap. + // Pointers to static or dynamic arrays of sorted names #if ENABLED(SDSORT_CACHE_NAMES) - #if ENABLED(SDSORT_DYNAMIC_RAM) - static char **sortshort, **sortnames; - #else - static char sortshort[SDSORT_LIMIT][FILENAME_LENGTH]; - #endif + static char (*sortshort)[SORTED_SHORTNAME_STORAGE]; #endif - - #if (ENABLED(SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM)) || NONE(SDSORT_CACHE_NAMES, SDSORT_USES_STACK) - static char sortnames[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE]; + #if ENABLED(SDSORT_CACHE_NAMES) || DISABLED(SDSORT_USES_STACK) + static char (*sortnames)[SORTED_LONGNAME_STORAGE]; #endif // Folder sorting uses an isDir array when caching items. diff --git a/README.md b/README.md index 7de24fb08b..d68fd0297e 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ To build and upload Marlin you will use one of these tools: - The free [Visual Studio Code](//code.visualstudio.com/download) using the [Auto Build Marlin](//marlinfw.org/docs/basics/auto_build_marlin.html) extension. - Marlin is optimized to build with the [PlatformIO IDE](//platformio.org/) extension for Visual Studio Code. -- You can also use VSCode with devcontainer : See [Installing Marlin (VSCode devcontainer)](http://marlinfw.org/docs/basics/install_devcontainer_vscode.html). +- You can also use VSCode with devcontainer : See [Installing Marlin (VSCode devcontainer)](https://marlinfw.org/docs/basics/install_devcontainer_vscode.html). - You can still build Marlin with [Arduino IDE](//www.arduino.cc/en/main/software) : See [Building Marlin with Arduino](//marlinfw.org/docs/basics/install_arduino.html). We hope to improve the Arduino build experience, but at this time, PlatformIO is the preferred choice. ## 32-bit ARM boards @@ -204,4 +204,4 @@ Marlin Firmware original logo design by Ahmet Cem TURAN [@ahmetcemturan](//githu ## License -Marlin is published under the [GPL license](/LICENSE) because we believe in open development. The GPL comes with both rights and obligations. Whether you use Marlin firmware as the driver for your open or closed-source product, you must keep Marlin open, and you must provide your compatible Marlin source code to end users upon request. The most straightforward way to comply with the Marlin license is to make a fork of Marlin on Github, perform your modifications, and direct users to your modified fork. +Marlin is published under the [GPL license](/LICENSE) because we believe in open development. The GPL comes with both rights and obligations. Whether you use Marlin firmware as the driver for your open or closed-source product, you must keep Marlin open, and you must provide your compatible Marlin source code to end users upon request. The most straightforward way to comply with the Marlin license is to make a fork of Marlin on GitHub, perform your modifications, and direct users to your modified fork. diff --git a/buildroot/bin/build_example b/buildroot/bin/build_example index 433cdeb81a..809f3d565e 100755 --- a/buildroot/bin/build_example +++ b/buildroot/bin/build_example @@ -11,6 +11,7 @@ # [-o|--output] - Redirect export / archiving to another location # (By default export to origin config folder) # [-f|--nofail] - Don't stop on a failed build +# [-x|--noxfer] - Skip the build if the env ends with _xfer. Implied with --many. # [-w|--nowarn] - Suppress warnings with extra config options # [-r|--reveal] - Reveal the config/export folder after the build # [-h|--help] - Print usage and exit @@ -28,6 +29,7 @@ build_example -b|--base= - Configurations root folder (e.g., ./.pio/bu [-o|--output] - Redirect export / archiving to another location (By default export to origin config folder) [-f|--nofail] - Don't stop on a failed build + [-x|--noxfer] - Skip the build if the env ends with _xfer. Implied with --many. [-w|--nowarn] - Suppress warnings with extra config options [-r|--reveal] - Reveal the config/export folder after the build [-h|--help] - Print usage and exit @@ -56,8 +58,9 @@ NOFAIL= OUTBASE= BUILDINDEX=1 MANY= +NOXFER= -while getopts 'ab:c:e:fhmn:o:r-:' OFLAG; do +while getopts 'ab:c:e:fhmn:o:r-:x' OFLAG; do case "${OFLAG}" in a) ARCHIVE=1 ;; b) BASE="${OPTARG%/}" ;; @@ -65,23 +68,25 @@ while getopts 'ab:c:e:fhmn:o:r-:' OFLAG; do e) EXPNUM="$OPTARG" ;; f) NOFAIL=1 ;; h) EXIT_USAGE=1 ; break ;; - m) MANY=1 ;; + m) MANY=1 ; NOXFER=1 ;; n) BUILDINDEX="$OPTARG" ;; o) OUTBASE="${OPTARG%/}" ;; r) REVEAL=1 ;; + x) NOXFER=1 ;; -) ONAM="${OPTARG%%=*}" ; OVAL="${OPTARG#*=}" case "$ONAM" in archive) ARCHIVE=1 ;; allow) ALLOW=1 ;; base) BASE="${OVAL%/}" ;; config) CONFIG="${OVAL%/}" ;; - many) MANY=1 ;; + many) MANY=1 ; NOXFER=1 ;; index) BUILDINDEX="$OVAL" ;; export) EXPNUM="$OVAL" ;; output) OUTBASE="${OVAL%/}" ;; help) EXIT_USAGE=1 ; break ;; nofail) NOFAIL=1 ;; reveal) REVEAL=1 ;; + noxfer) NOXFER=1 ;; *) EXIT_USAGE=2 ; echo "$SELF: unrecognized option \`--$ONAM'" ; break ;; esac ;; @@ -188,7 +193,7 @@ echo "Building example $CONFIG..." # If doing many builds get a list of all environment names, # which also gives us the number of environments. if ((MANY)); then - ENVLIST=$(mfenvs -n) # BOARD_NAME_STRING (1234): [ env1 env2 env3 ... ] + ENVLIST=$(mfenvs) # BOARD_NAME_STRING (1234): [ env1 env2 env3 ... ] ENVLIST=${ENVLIST##*: [ } ENVARRAY=(${ENVLIST% ]}) ENVCOUNT=${#ENVARRAY[*]} @@ -200,83 +205,92 @@ fi # Build all from BUILDINDEX onward (usually 1) meaning ALL. # MANY with a BUILDINDEX may be useful for continuing an interrupted build. -while ((1)); do +while true; do set +e - echo "Building example $CONFIG ($BUILDINDEX)..." + # Skip over "_xfer" environments when specified + if [[ -n $NOXFER && ${ENVARRAY[BUILDINDEX-1]} =~ _xfer$ ]]; then - # Run a build and record the error number - mftest -s -a -n$BUILDINDEX ; ERR=$? - - # "Index out of range" can fail without an error - ((MANY)) && ((ERR == 66)) && ERR=0 && break # "index out of range" - - set -e - - if [[ $ERR -gt 0 ]]; then - - alrt "Failed ($ERR)" - - # Error? For --nofail simply log. Otherwise return the error. - if [[ -n $NOFAIL ]]; then - date +"%F %T [FAIL] $CONFIG ($BUILDINDEX)" >>./.pio/error-log.txt - else - exit $ERR - fi + echo "Skipping example $CONFIG ($BUILDINDEX)..." else - annc "Success" + echo "Building example $CONFIG ($BUILDINDEX)..." - # Copy exports back to the configs - if [[ -n $EXPNUM ]]; then - annc "Exporting $EXPNUM" - [[ -f Marlin/Config-export.h ]] && { cp Marlin/Config-export.h "$ARCSUB"/Config.h ; } - find "$BUILD" -type f \( "${ENAME[@]}" \) -exec cp "{}" "$ARCSUB" \; - fi + # Run a build and record the error number + mftest -s -a -n$BUILDINDEX ; ERR=$? + + # "Index out of range" can fail without an error + ((MANY)) && ((ERR == 66)) && ERR=0 && break # "index out of range" + + set -e + + if [[ $ERR -gt 0 ]]; then + + alrt "Failed ($ERR)" + + # Error? For --nofail simply log. Otherwise return the error. + if [[ -n $NOFAIL ]]; then + date +"%F %T [FAIL] $CONFIG ($BUILDINDEX)" >>./.pio/error-log.txt + else + exit $ERR + fi - # When building many, create sub-folders for each build env name - if [[ -n $MANY ]]; then - ENV=${ENVARRAY[BUILDINDEX-1]} - ARCENVSUB="$ARCSUB/$ENV" else - ARCENVSUB="$ARCSUB" - fi - # Copy potential firmware files into the config folder - # TODO: Consider firmware that needs an STM32F4_UPDATE folder. - # Currently only BOARD_CREALITY_F401RE env:STM32F401RE_creality - if ((ARCHIVE)); then - annc "Archiving" - find "$BUILD" -type f \( "${BNAME[@]}" \) -exec sh -c ' - ARCDIR="$1" ; CONFIG="$2" ; FILE="$3" ; shift 3 - NAME=${FILE##*/} ; SHRT=${NAME%.*} ; DIR=${FILE%/*} - ZIPX= - if [[ $CONFIG == *Simulator* ]]; then - case $(uname | tr '[:upper:]' '[:lower:]') in - darwin) SUB="macOS" ; ZIPX="-X" ;; - *linux) SUB="Linux" ;; - win*) SUB="Windows" ;; - msys*) SUB="Windows" ;; - cygwin*) SUB="Windows" ;; - mingw*) SUB="Windows" ;; - *) SUB='Unix' ;; - esac - ARCH=$(uname -m | tr '[:lower:]' '[:upper:]') - ARCDIR="$ARCDIR/$SUB-$ARCH" - fi - mkdir -p "$ARCDIR" - rm -f "$ARCDIR"/*.zip "$ARCDIR"/*.sha256.txt - cd "$DIR" - SHASUM=$(sha256sum "$NAME" | cut -d" " -f1) - echo "$CONFIG\n$SHASUM" > "$ARCDIR/$NAME.sha256.txt" - zip $ZIPX "$ARCDIR/$SHRT.zip" "$NAME" && rm "$NAME" - cd - >/dev/null - ' sh "$ARCENVSUB" "$CONFIG" {} + - fi + annc "Success" - # Reveal the configs after the build, if requested - ((REVEAL)) && { annc "Revealing $ARCENVSUB" ; open "$ARCENVSUB" ; } + # Copy exports back to the configs + if [[ -n $EXPNUM ]]; then + annc "Exporting $EXPNUM" + [[ -f Marlin/Config-export.h ]] && { cp Marlin/Config-export.h "$ARCSUB"/Config.h ; } + find "$BUILD" -type f \( "${ENAME[@]}" \) -exec cp "{}" "$ARCSUB" \; + fi + + # When building many, create sub-folders for each build env name + if [[ -n $MANY ]]; then + ENV=${ENVARRAY[BUILDINDEX-1]} + ARCENVSUB="$ARCSUB/$ENV" + else + ARCENVSUB="$ARCSUB" + fi + + # Copy potential firmware files into the config folder + # TODO: Consider firmware that needs an STM32F4_UPDATE folder. + # Currently only BOARD_CREALITY_F401RE env:STM32F401RE_creality + if ((ARCHIVE)); then + annc "Archiving" + find "$BUILD" -type f \( "${BNAME[@]}" \) -exec sh -c ' + ARCDIR="$1" ; CONFIG="$2" ; FILE="$3" ; shift 3 + NAME=${FILE##*/} ; SHRT=${NAME%.*} ; DIR=${FILE%/*} + ZIPX= + if [[ $CONFIG == *Simulator* ]]; then + case $(uname | tr '[:upper:]' '[:lower:]') in + darwin) SUB="macOS" ; ZIPX="-X" ;; + *linux) SUB="Linux" ;; + win*) SUB="Windows" ;; + msys*) SUB="Windows" ;; + cygwin*) SUB="Windows" ;; + mingw*) SUB="Windows" ;; + *) SUB='Unix' ;; + esac + ARCH=$(uname -m | tr '[:lower:]' '[:upper:]') + ARCDIR="$ARCDIR/$SUB-$ARCH" + fi + mkdir -p "$ARCDIR" + rm -f "$ARCDIR"/*.zip "$ARCDIR"/*.sha256.txt + cd "$DIR" + SHASUM=$(sha256sum "$NAME" | cut -d" " -f1) + echo "$CONFIG\n$SHASUM" > "$ARCDIR/$NAME.sha256.txt" + zip $ZIPX "$ARCDIR/$SHRT.zip" "$NAME" && rm "$NAME" + cd - >/dev/null + ' sh "$ARCENVSUB" "$CONFIG" {} + + fi # ARCHIVE + + # Reveal the configs after the build, if requested + ((REVEAL)) && { annc "Revealing $ARCENVSUB" ; open "$ARCENVSUB" ; } + + fi # Success fi diff --git a/buildroot/bin/generate_version b/buildroot/bin/generate_version index edc25e18af..8bcad94374 100755 --- a/buildroot/bin/generate_version +++ b/buildroot/bin/generate_version @@ -105,7 +105,7 @@ cat > "${WRITE_FILE}" < 1" + err = "Error: FILAMENT_RUNOUT_SCRIPT needs a %c parameter (e.g., \"M600 T%c\") when NUM_RUNOUT_SENSORS is > 1" raise SystemExit(err) diff --git a/buildroot/share/PlatformIO/scripts/schema.py b/buildroot/share/PlatformIO/scripts/schema.py index 6a669d887e..9621e30c62 100755 --- a/buildroot/share/PlatformIO/scripts/schema.py +++ b/buildroot/share/PlatformIO/scripts/schema.py @@ -61,8 +61,7 @@ def find_grouping(gdict, filekey, sectkey, optkey, pindex): optparts[pindex] = '*' wildkey = '_'.join(optparts) kkey = f'{filekey}|{sectkey}|{wildkey}' - if kkey not in gdict: gdict[kkey] = [] - gdict[kkey].append((subkey, modkey)) + gdict.setdefault(kkey, []).append((subkey, modkey)) # Build a list of potential groups. Only those with multiple items will be grouped. def group_options(schema): @@ -137,7 +136,9 @@ def extract_files(filekey): # Regex for #define NAME [VALUE] [COMMENT] with sanitized line defgrep = re.compile(r'^(//)?\s*(#define)\s+([A-Za-z0-9_]+)\s*(.*?)\s*(//.+)?$') # Pattern to match a float value - flt = r'[-+]?\s*(\d+\.|\d*\.\d+)([eE][-+]?\d+)?[fF]?' + flt = r'[-+]?\s*(?:\d+\.|\d*\.\d+)(?:[eE][-+]?\d+)?[fF]?' + # Pattern to match an integer expression + int_expr = r'(?:[-+]?\s*\d+(?:\s*[*\/+\-]\s*\d+)*)' # Start with unknown state state = Parse.NORMAL # Serial ID @@ -314,9 +315,11 @@ def extract_files(filekey): # Parenthesize the given expression if needed def atomize(s): - if s == '' \ - or re.match(r'^[A-Za-z0-9_]*(\([^)]+\))?$', s) \ - or re.match(r'^[A-Za-z0-9_]+ == \d+?$', s): + s = s.strip() + if not s or s.isidentifier() or (s.startswith('(') and s.endswith(')')): + return s + if re.match(r'^[A-Za-z0-9_]*(\([^)]+\))$', s) \ + or re.match(r'^[A-Za-z0-9_]+\s*[=!<>]=?\s*.*$', s): return s return f'({s})' @@ -369,27 +372,30 @@ def extract_files(filekey): } # Type is based on the value - value_type = \ - 'switch' if val == '' \ - else 'int' if re.match(r'^[-+]?\s*\d+$', val) \ - else 'ints' if re.match(r'^([-+]?\s*\d+)(\s*,\s*[-+]?\s*\d+)+$', val) \ - else 'floats' if re.match(rf'({flt}(\s*,\s*{flt})+)', val) \ - else 'float' if re.match(f'^({flt})$', val) \ - else 'string' if val[0] == '"' \ - else 'char' if val[0] == "'" \ - else 'bool' if val in ('true', 'false') \ - else 'state' if val in ('HIGH', 'LOW') \ - else 'enum' if re.match(r'^[A-Za-z0-9_]{3,}$', val) \ - else 'int[]' if re.match(r'^{\s*[-+]?\s*\d+(\s*,\s*[-+]?\s*\d+)*\s*}$', val) \ - else 'float[]' if re.match(r'^{{\s*{flt}(\s*,\s*{flt})*\s*}}$', val) \ - else 'array' if val[0] == '{' \ - else '' + value_type = ( + 'switch' if val == '' + else 'int' if re.match(r'^[-+]?\s*\d+$', val) + else 'ints' if re.match(r'^[-+]?\s*\d+(?:\s*,\s*[-+]?\s*\d+)+$', val) + else 'floats' if re.match(rf"^{flt}(?:\s*,\s*{flt})+$", val) + else 'float' if re.match(rf"^{flt}$", val) + else 'string' if val.startswith('"') + else 'char' if val.startswith("'") + else 'bool' if val in ('true', 'false') + else 'state' if val in ('HIGH', 'LOW') + else 'int[]' if re.match(rf"^\{{\s*{int_expr}(?:\s*,\s*{int_expr})*\s*\}}$", val) + else 'float[]' if re.match(rf"^\{{\s*{flt}(?:\s*,\s*{flt})*\s*\}}$", val) + else 'array' if val.startswith('{') + else 'enum' if re.match(r'^[A-Za-z0-9_]{3,}$', val) + else '' + ) - val = (val == 'true') if value_type == 'bool' \ - else int(val) if value_type == 'int' \ - else val.replace('f','') if value_type == 'floats' \ - else float(val.replace('f','')) if value_type == 'float' \ - else val + val = ( + (val == 'true') if value_type == 'bool' + else int(val) if value_type == 'int' + else val.replace('f','') if value_type == 'floats' + else float(val.replace('f','')) if value_type == 'float' + else val + ) if val != '': define_info['value'] = val if value_type != '': define_info['type'] = value_type @@ -496,9 +502,14 @@ def main(): unk = not inargs(['some','json','jsons','group','yml','yaml', '-h', '--help']) if (unk): print(f"Unknown option: '{args[0]}'") if inargs(['-h', '--help']) or unk: + print("Extract firmware configuration into structured JSON or YAML schema format.") print("Usage: schema.py [-h] [some|json|jsons|group|yml|yaml]") - print(" some = json + yml") - print(" jsons = json + group") + print(" some Generate both JSON and YAML output (schema.json and schema.yml)") + print(" json Generate JSON output (schema.json)") + print(" jsons Generate grouped JSON output with wildcard options (schema.json and schema_grouped.json)") + print(" group Generate grouped JSON output only (schema_grouped.json)") + print(" yml Generate YAML output (schema.yml)") + print(" yaml Same as 'yml'") return # JSON schema diff --git a/buildroot/share/dwin/icons-svg/alert.svg b/buildroot/share/dwin/icons-svg/alert.svg index e98bd58bd8..a319bbdc00 100644 --- a/buildroot/share/dwin/icons-svg/alert.svg +++ b/buildroot/share/dwin/icons-svg/alert.svg @@ -1,12 +1,12 @@ diff --git a/buildroot/share/dwin/icons-svg/bed_leveled_on.svg b/buildroot/share/dwin/icons-svg/bed_leveled_on.svg index bda0c77a9e..f899f68cf2 100644 --- a/buildroot/share/dwin/icons-svg/bed_leveled_on.svg +++ b/buildroot/share/dwin/icons-svg/bed_leveled_on.svg @@ -7,12 +7,12 @@ viewBox="0 0 48 36" height="36" width="48" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://inkscape.org/namespaces/inkscape" + xmlns:sodipodi="https://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="https://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="https://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> diff --git a/buildroot/share/dwin/icons-svg/bed_off.svg b/buildroot/share/dwin/icons-svg/bed_off.svg index 936710e49b..53a06e06e9 100644 --- a/buildroot/share/dwin/icons-svg/bed_off.svg +++ b/buildroot/share/dwin/icons-svg/bed_off.svg @@ -7,12 +7,12 @@ viewBox="0 0 48 36" height="36" width="48" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://inkscape.org/namespaces/inkscape" + xmlns:sodipodi="https://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="https://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="https://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> diff --git a/buildroot/share/dwin/icons-svg/bed_on.svg b/buildroot/share/dwin/icons-svg/bed_on.svg index 61218e57a6..45e36c9b82 100644 --- a/buildroot/share/dwin/icons-svg/bed_on.svg +++ b/buildroot/share/dwin/icons-svg/bed_on.svg @@ -7,12 +7,12 @@ id="svg1468" inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" sodipodi:docname="bed_on.svg" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://inkscape.org/namespaces/inkscape" + xmlns:sodipodi="https://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="https://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="https://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> diff --git a/buildroot/share/dwin/icons-svg/bedline.svg b/buildroot/share/dwin/icons-svg/bedline.svg index 51670b7a19..cc64a6194d 100644 --- a/buildroot/share/dwin/icons-svg/bedline.svg +++ b/buildroot/share/dwin/icons-svg/bedline.svg @@ -1,12 +1,12 @@ diff --git a/buildroot/share/dwin/icons-svg/hotend_on.svg b/buildroot/share/dwin/icons-svg/hotend_on.svg index f112ba186b..925825a3d3 100644 --- a/buildroot/share/dwin/icons-svg/hotend_on.svg +++ b/buildroot/share/dwin/icons-svg/hotend_on.svg @@ -7,12 +7,12 @@ id="svg857" inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" sodipodi:docname="hotend_on.svg" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://inkscape.org/namespaces/inkscape" + xmlns:sodipodi="https://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="https://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="https://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> diff --git a/buildroot/share/dwin/icons-svg/question.svg b/buildroot/share/dwin/icons-svg/question.svg index 8d8849ca4e..87723a349b 100644 --- a/buildroot/share/dwin/icons-svg/question.svg +++ b/buildroot/share/dwin/icons-svg/question.svg @@ -1,12 +1,12 @@ - The upstream project ('`MarlinFirmware`')
- the '`origin`' project (i.e., your Github username),
- the repository name ('`Marlin`'),
- the PR target branch ('`bugfix-1.1.x`'), and
- the current branch (or the first command-line argument).

By itself, `mfinfo` simply prints these values to the console. | +| mfinfo | This utility script is used by the other scripts to get:
- The upstream project ('`MarlinFirmware`')
- the '`origin`' project (i.e., your GitHub username),
- the repository name ('`Marlin`'),
- the PR target branch ('`bugfix-1.1.x`'), and
- the current branch (or the first command-line argument).

By itself, `mfinfo` simply prints these values to the console. | | mfclean      | Prune your merged and remotely-deleted branches. | --- diff --git a/buildroot/share/git/mfinfo b/buildroot/share/git/mfinfo index c74e48650c..d7ae7c9edd 100755 --- a/buildroot/share/git/mfinfo +++ b/buildroot/share/git/mfinfo @@ -5,7 +5,7 @@ # Print the following info about the working copy: # # - Remote (upstream) Org name (MarlinFirmware) -# - Remote (origin) Org name (your Github username) +# - Remote (origin) Org name (your GitHub username) # - Repo Name (Marlin, MarlinDocumentation) # - PR Target branch (e.g., bugfix-2.1.x) # - Branch Arg (the branch argument or current branch) diff --git a/buildroot/share/git/mfpub b/buildroot/share/git/mfpub index 6ffe627b92..46771c21d3 100755 --- a/buildroot/share/git/mfpub +++ b/buildroot/share/git/mfpub @@ -3,7 +3,7 @@ # mfpub # # Use Jekyll to generate Marlin Documentation, which is then -# git-pushed to Github to publish it to the live site. +# git-pushed to GitHub to publish it to the live site. # This publishes the current branch, and doesn't force # changes to be pushed to the 'master' branch. Be sure to # push any permanent changes to 'master'. diff --git a/buildroot/share/scripts/check-urls.sh b/buildroot/share/make/check-urls.sh similarity index 89% rename from buildroot/share/scripts/check-urls.sh rename to buildroot/share/make/check-urls.sh index 5e90b8f433..098a9edea9 100755 --- a/buildroot/share/scripts/check-urls.sh +++ b/buildroot/share/make/check-urls.sh @@ -8,8 +8,10 @@ UA="Mozilla/5.0 (Linux; Android 10; SM-G996U Build/QP1A.190711.020; wv) AppleWeb UTMP=$(mktemp) #echo "[debug 1] UTMP = ${UTMP}" echo "Gathering URLs. Please wait..." -grep -R -E "https?:\/\/[^ \"''\(\)\<\>]+" . 2>/dev/null \ +find Marlin/src -type f ! -path "*/\.*" -exec grep -Eo "https?:\/\/[^ \"'\$\<\>]+" {} \; 2>/dev/null \ + | sort -u -R \ | grep -v "Binary file" \ + | grep -v "/licenses" | grep -v "MarlinFirmware/Marlin" | grep -v "st.com/resource" \ | sed -E "s/\/https?:\/\//\//" \ | sed -E 's/.*\((https?:\/\/[^ ]+)\).*$/\1/' \ | sed -E 's/.*\[(https?:\/\/[^ ]+)\].*$/\1/' \ @@ -17,7 +19,6 @@ grep -R -E "https?:\/\/[^ \"''\(\)\<\>]+" . 2>/dev/null \ | grep -vE "(127\.0\.0\.1|localhost|myserver|doc\.qt\.io|docs\.google\.com|raw\.githubusercontent\.com|[\${}])" \ | sed -E 's/]$//' | sed -E "s/'$//" | sed -E "s/[#.',]+$//" \ | sed -E 's/youtu\.be\/(.+)/www.youtube.com\/watch?v=\1/' \ - | sort -u -R \ >"$UTMP" #echo "[debug 2] link count = $(wc -l $UTMP)" @@ -30,7 +31,7 @@ grep -R -E "https?:\/\/[^ \"''\(\)\<\>]+" . 2>/dev/null \ if [[ $HERR > 0 ]]; then # Error 92 may be domain blocking curl / wget [[ $HERR == 92 ]] || { ISERR=1 ; BADURLS+=($URL) ; } - echo "[FAIL ($HERR)]" + echo "${URL} ... [FAIL ($HERR)]" else HEAD1=$(echo $HEAD | head -n1) EMSG= @@ -47,6 +48,7 @@ grep -R -E "https?:\/\/[^ \"''\(\)\<\>]+" . 2>/dev/null \ *) EMSG="[Other Err]" ;; esac if [[ -n $EMSG ]]; then + echo -n "${URL} ... " if [[ -n $WHERE ]]; then [[ ${HEAD,,} =~ "location: " ]] && EMSG+=" to $(echo "$HEAD" | grep -i "location: " | sed -E 's/location: (.*)/\1/')" else diff --git a/buildroot/share/make/find.py b/buildroot/share/make/find.py new file mode 100755 index 0000000000..e0dd925931 --- /dev/null +++ b/buildroot/share/make/find.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# This is a cut-down version of the Linux 'find' command, implemented in Python for Marlin build scripts. +import sys +import os +import fnmatch + +def find_files(root, mindepth, pattern): + results = [] + root = os.path.normpath(root) + for dirpath, dirnames, filenames in os.walk(root): + for filename in filenames: + if fnmatch.fnmatch(filename, pattern): + full_path = os.path.join(dirpath, filename) + rel_path = os.path.relpath(full_path, root) + # mindepth: number of path components in rel_path >= mindepth + if rel_path.count(os.sep) + 1 >= mindepth: + results.append(full_path) + return results + +if __name__ == "__main__": + if len(sys.argv) != 6 or sys.argv[2] != '-mindepth' or sys.argv[4] != '-name': + print("Usage: find.py -mindepth -name ", file=sys.stderr) + sys.exit(1) + root = sys.argv[1] + mindepth = int(sys.argv[3]) + pattern = sys.argv[5] + files = find_files(root, mindepth, pattern) + for f in files: + print(f.replace('\\', '/')) diff --git a/buildroot/share/scripts/get_test_targets.py b/buildroot/share/make/get_test_targets.py similarity index 86% rename from buildroot/share/scripts/get_test_targets.py rename to buildroot/share/make/get_test_targets.py index b187de9cac..669a1c4418 100644 --- a/buildroot/share/scripts/get_test_targets.py +++ b/buildroot/share/make/get_test_targets.py @@ -1,6 +1,6 @@ #!/usr/bin/env python """ -Extract the builds used in Github CI, so that we can run them locally +Extract the builds used in GitHub CI, so that we can run them locally """ import yaml diff --git a/buildroot/share/scripts/validate_boards.py b/buildroot/share/make/validate_boards.py similarity index 100% rename from buildroot/share/scripts/validate_boards.py rename to buildroot/share/make/validate_boards.py diff --git a/buildroot/share/pixmaps/logo/marlin-old.svg b/buildroot/share/pixmaps/logo/marlin-old.svg index a8c9369f8e..f375354b02 100644 --- a/buildroot/share/pixmaps/logo/marlin-old.svg +++ b/buildroot/share/pixmaps/logo/marlin-old.svg @@ -6,12 +6,12 @@ --> Marlin WebUI by atbox.tech - MarlinLogo + MarlinLogo @@ -500,7 +500,7 @@ Marlin WebUI

Release date: January, 1 2020

- Github project: E4d-box-project
+ GitHub project: E4d-box-project
Facebook: E4d@box

Open source dependencies:

diff --git a/ini/native.ini b/ini/native.ini index 67938852ec..9450cda303 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -111,7 +111,7 @@ build_flags = ${simulator_linux.build_flags} ${simulator_linux.release_flags} # [simulator_macos] -build_unflags = -g3 -lGL -fstack-protector-strong +build_unflags = -g3 -lGL -fstack-protector-strong -fsingle-precision-constant build_flags = -g2 -DHAS_LIBBSD -I/opt/local/include diff --git a/ini/raspberrypi.ini b/ini/raspberrypi.ini index 2ee74631f9..d93cabbc92 100644 --- a/ini/raspberrypi.ini +++ b/ini/raspberrypi.ini @@ -20,8 +20,7 @@ lib_deps = ${common.lib_deps} #lvgl/lvgl@^8.1.0 lib_ignore = WiFi build_flags = ${common.build_flags} -D__PLAT_RP2040__ -DPLATFORM_M997_SUPPORT -DNO_SD_HOST_DRIVE -Wno-expansion-to-defined -Wno-vla -Wno-ignored-qualifiers -#debug_tool = jlink -#upload_protocol = jlink +upload_protocol = picotool #custom_marlin.HAS_SD_HOST_DRIVE = tinyusb [env:RP2040-alt] @@ -34,6 +33,5 @@ board_build.core = earlephilhower # [env:SKR_Pico] extends = env:RP2040 - -[env:SKR_Pico_UART] -extends = env:SKR_Pico +lib_deps = ${common.lib_deps} + arduino-libraries/Servo