From 9215bf791b015a8970c3ca54188f8145ab0cc263 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:50:21 +1200 Subject: [PATCH 01/22] =?UTF-8?q?=F0=9F=94=A8=20MarlinSimUI=20updates=20(#?= =?UTF-8?q?26955)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/native.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/native.ini b/ini/native.ini index ba5ddbc4cc..d07eaa2205 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -44,7 +44,7 @@ debug_build_flags = -fstack-protector-strong -g -g3 -ggdb lib_compat_mode = off build_src_filter = ${common.default_src_filter} + lib_deps = ${common.lib_deps} - MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/8791f3ff43.zip + MarlinSimUI=https://github.com/p3p/MarlinSimUI/archive/66a2b82c8f.zip Adafruit NeoPixel=https://github.com/p3p/Adafruit_NeoPixel/archive/c6b319f447.zip LiquidCrystal=https://github.com/p3p/LiquidCrystal/archive/322fb5fc23.zip extra_scripts = ${common.extra_scripts} From e6755450df46870c961f8d675815da1415d6436f Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Tue, 9 Apr 2024 22:58:13 -0700 Subject: [PATCH 02/22] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20ESP3D=20WiFi=20Suppo?= =?UTF-8?q?rt=20(#26822)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 2 +- Marlin/src/inc/SanityCheck.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 434aa83e56..559eafdbf6 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -4342,7 +4342,7 @@ * Extras for an ESP32-based motherboard with WIFISUPPORT * These options don't apply to add-on WiFi modules based on ESP32 WiFi101. */ -#if ENABLED(WIFISUPPORT) +#if ANY(WIFISUPPORT, ESP3D_WIFISUPPORT) //#define WEBSUPPORT // Start a webserver (which may include auto-discovery) using SPIFFS //#define OTASUPPORT // Support over-the-air firmware updates //#define WIFI_CUSTOM_COMMAND // Accept feature config commands (e.g., WiFi ESP3D) from the host diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index b2f909de08..eea7d15d9b 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3935,11 +3935,11 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #if !(defined(WIFI_SSID) && defined(WIFI_PWD)) #error "ESP32 motherboard with WIFISUPPORT requires WIFI_SSID and WIFI_PWD." #endif -#elif ENABLED(WIFI_CUSTOM_COMMAND) +#elif ENABLED(WIFI_CUSTOM_COMMAND) && NONE(ESP3D_WIFISUPPORT, WIFISUPPORT) #error "WIFI_CUSTOM_COMMAND requires an ESP32 motherboard and WIFISUPPORT." -#elif ENABLED(OTASUPPORT) +#elif ENABLED(OTASUPPORT) && NONE(ESP3D_WIFISUPPORT, WIFISUPPORT) #error "OTASUPPORT requires an ESP32 motherboard and WIFISUPPORT." -#elif defined(WIFI_SSID) || defined(WIFI_PWD) +#elif (defined(WIFI_SSID) || defined(WIFI_PWD)) && NONE(ESP3D_WIFISUPPORT, WIFISUPPORT) #error "WIFI_SSID and WIFI_PWD only apply to ESP32 motherboard with WIFISUPPORT." #endif From 80dd02fbdb81e149fb2e63d76f3a17c0a6537a91 Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Wed, 10 Apr 2024 18:02:32 +1200 Subject: [PATCH 03/22] =?UTF-8?q?=F0=9F=93=9D=20Update=20RGB565=20color=20?= =?UTF-8?q?picker=20url=20(#26951)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp | 2 +- Marlin/src/lcd/tft/tft_color.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp b/Marlin/src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp index dcf835a6cb..73b35b0ec2 100644 --- a/Marlin/src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp +++ b/Marlin/src/lcd/dogm/u8g/u8g_dev_tft_upscale_from_128x64.cpp @@ -84,7 +84,7 @@ TFT_IO tftio; #define X_HI (UPSCALE(TFT_PIXEL_OFFSET_X, WIDTH) - 1) #define Y_HI (UPSCALE(TFT_PIXEL_OFFSET_Y, HEIGHT) - 1) -// RGB565 color picker: https://embeddednotepad.com/page/rgb565-color-picker +// RGB565 color picker: https://rgbcolorpicker.com/565 // Hex code to color name: https://www.color-name.com/ #define COLOR_BLACK 0x0000 // #000000 diff --git a/Marlin/src/lcd/tft/tft_color.h b/Marlin/src/lcd/tft/tft_color.h index cd03224615..ef0d2fa5b5 100644 --- a/Marlin/src/lcd/tft/tft_color.h +++ b/Marlin/src/lcd/tft/tft_color.h @@ -30,7 +30,7 @@ #define COLOR(color) RGB(((color >> 16) & 0xFF), ((color >> 8) & 0xFF), (color & 0xFF)) #define HALF(color) RGB(RED(color) >> 1, GREEN(color) >> 1, BLUE(color) >> 1) -// RGB565 color picker: https://embeddednotepad.com/page/rgb565-color-picker +// RGB565 color picker: https://rgbcolorpicker.com/565 // Hex code to color name: https://www.color-name.com/ #define COLOR_BLACK 0x0000 // #000000 From a75a5f8b2a5fd163bfc2710ef649a0cf6f65e6a6 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Wed, 10 Apr 2024 06:13:36 +0000 Subject: [PATCH 04/22] [cron] Bump distribution date (2024-04-10) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 0b350f6bdb..412c144adc 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 "2024-04-08" +//#define STRING_DISTRIBUTION_DATE "2024-04-10" /** * Defines a generic printer name to be output to the LCD after booting Marlin. diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index d574879705..771e9b593f 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 "2024-04-08" + #define STRING_DISTRIBUTION_DATE "2024-04-10" #endif /** From 1b091ecb874bb873c12c686746084e6ee71b056f Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Thu, 11 Apr 2024 02:13:54 -0400 Subject: [PATCH 05/22] =?UTF-8?q?=E2=9C=8F=EF=B8=8FMinor=20style=20and=20t?= =?UTF-8?q?ypo=20fixups=20(#26947)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * tweaks from PR, whitespace, wording in pause.h * Update Marlin/src/feature/pause.h --- Marlin/src/feature/pause.h | 8 +++----- Marlin/src/lcd/HD44780/marlinui_HD44780.cpp | 2 +- Marlin/src/lcd/marlinui.cpp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Marlin/src/feature/pause.h b/Marlin/src/feature/pause.h index b86f86b633..4d968406c2 100644 --- a/Marlin/src/feature/pause.h +++ b/Marlin/src/feature/pause.h @@ -57,9 +57,7 @@ enum PauseMessage : char { }; #if M600_PURGE_MORE_RESUMABLE - /** - * Input methods can Purge More, Resume, or request input - */ + // Input methods can Purge More, Resume, or request input enum PauseMenuResponse : char { PAUSE_RESPONSE_WAIT_FOR, PAUSE_RESPONSE_EXTRUDE_MORE, @@ -109,7 +107,7 @@ void wait_for_confirmation( void resume_print( const_float_t slow_load_length=0, // (mm) Slow Load Length for finishing move const_float_t fast_load_length=0, // (mm) Fast Load Length for initial move - const_float_t extrude_length=ADVANCED_PAUSE_PURGE_LENGTH, // (mm) Purge length + const_float_t purge_length=ADVANCED_PAUSE_PURGE_LENGTH, // (mm) Purge length const int8_t max_beep_count=0, // Beep alert for attention const celsius_t targetTemp=0 // (ยฐC) A target temperature for the hotend DXC_PARAMS // Dual-X-Carriage extruder index @@ -118,7 +116,7 @@ void resume_print( bool load_filament( const_float_t slow_load_length=0, // (mm) Slow Load Length for finishing move const_float_t fast_load_length=0, // (mm) Fast Load Length for initial move - const_float_t extrude_length=0, // (mm) Purge length + const_float_t purge_length=0, // (mm) Purge length const int8_t max_beep_count=0, // Beep alert for attention const bool show_lcd=false, // Set LCD status messages? const bool pause_for_user=false, // Pause for user before returning? diff --git a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp index d36233d73d..0ab045bda3 100644 --- a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp +++ b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp @@ -1169,7 +1169,7 @@ void MarlinUI::draw_status_screen() { lcd_moveto(LCD_WIDTH - 9, 2); lcd_put_lchar('S'); - + #endif // LCD_INFO_SCREEN_STYLE diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index aaa8fb65e8..dca18f2125 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1668,7 +1668,7 @@ void MarlinUI::host_notify(const char * const cstr) { card.abortFilePrintSoon(); else if (card.isMounted()) card.closefile(); - #endif + #endif #ifdef ACTION_ON_CANCEL hostui.cancel(); #endif From 9a570b23a3be455e9bf5f2a5b8355f42c0957ca1 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Thu, 11 Apr 2024 12:07:54 +0000 Subject: [PATCH 06/22] [cron] Bump distribution date (2024-04-11) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 412c144adc..4bdfcdaebb 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 "2024-04-10" +//#define STRING_DISTRIBUTION_DATE "2024-04-11" /** * Defines a generic printer name to be output to the LCD after booting Marlin. diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 771e9b593f..cb598b58ad 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 "2024-04-10" + #define STRING_DISTRIBUTION_DATE "2024-04-11" #endif /** From 2715e5ba1b2015b4e25d4b5c27505e753d2aa4d4 Mon Sep 17 00:00:00 2001 From: InsanityAutomation <38436470+InsanityAutomation@users.noreply.github.com> Date: Sat, 13 Apr 2024 02:29:59 -0400 Subject: [PATCH 07/22] =?UTF-8?q?=F0=9F=90=9BFix=20IDEX=20X2=20Direction?= =?UTF-8?q?=20(#26958)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix IDEX X2 Direction * Sanity Check IDEX X1_MAX_POS --- Marlin/src/inc/Conditionals_adv.h | 6 ++++++ Marlin/src/inc/SanityCheck.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h index aa55731d90..78da97f67b 100644 --- a/Marlin/src/inc/Conditionals_adv.h +++ b/Marlin/src/inc/Conditionals_adv.h @@ -954,6 +954,12 @@ #define HAS_MOTOR_CURRENT_I2C 1 #endif +#if ENABLED(DUAL_X_CARRIAGE) + #ifndef INVERT_X2_DIR + #define INVERT_X2_DIR INVERT_X_DIR + #endif +#endif + // X2 but not IDEX => Dual Synchronized X Steppers #if defined(X2_DRIVER_TYPE) && DISABLED(DUAL_X_CARRIAGE) #define HAS_SYNCED_X_STEPPERS 1 diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index eea7d15d9b..392d75675e 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1837,6 +1837,8 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #error "DUAL_X_CARRIAGE requires X2_HOME_POS, X2_MIN_POS, and X2_MAX_POS." #elif X_HOME_TO_MAX #error "DUAL_X_CARRIAGE requires X_HOME_DIR -1." + #elif (X2_HOME_POS <= X1_MAX_POS) || (X2_MAX_POS < X1_MAX_POS) + #error "DUAL_X_CARRIAGE will crash if X1 can meet or exceed X2 travel." #endif #endif From 6575dcc803d71b38cf0bb922f8d048c867142db7 Mon Sep 17 00:00:00 2001 From: InsanityAutomation <38436470+InsanityAutomation@users.noreply.github.com> Date: Sat, 13 Apr 2024 02:40:59 -0400 Subject: [PATCH 08/22] =?UTF-8?q?=F0=9F=A9=B9=20Reduce=20Kill=20Pin=20Wait?= =?UTF-8?q?=20(#26945)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce kill pin wait time, and allow override by setting KILL_DELAY --- Marlin/src/MarlinCore.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 272e50340a..97e7c32bf6 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -474,11 +474,16 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { #if HAS_KILL - // Check if the kill button was pressed and wait just in case it was an accidental - // key kill key press + // Check if the kill button was pressed and wait to ensure the signal is not noise + // typically caused by poor insulation and grounding on LCD cables. + // Lower numbers here will increase response time and therefore safety rating. + // It is recommended to set this as low as possibe without false triggers. // ------------------------------------------------------------------------------- + #ifndef KILL_DELAY + #define KILL_DELAY 250 + #endif + static int killCount = 0; // make the inactivity button a bit less responsive - const int KILL_DELAY = 750; if (kill_state()) killCount++; else if (killCount > 0) From 71d9a3e1dfa55edd5ec737a4f4ca82e9f2a11d32 Mon Sep 17 00:00:00 2001 From: Vovodroid Date: Sat, 13 Apr 2024 10:04:34 +0300 Subject: [PATCH 09/22] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20M413=20report=20(#26?= =?UTF-8?q?846)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/feature/powerloss/M413.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/src/gcode/feature/powerloss/M413.cpp b/Marlin/src/gcode/feature/powerloss/M413.cpp index 733a34484c..b12257b4e5 100644 --- a/Marlin/src/gcode/feature/powerloss/M413.cpp +++ b/Marlin/src/gcode/feature/powerloss/M413.cpp @@ -72,6 +72,7 @@ void GcodeSuite::M413_report(const bool forReplay/*=true*/) { , " B", recovery.bed_temp_threshold #endif ); + SERIAL_ECHO(" ; "); serialprintln_onoff(recovery.enabled); } From 9e88eb6100a30761bde51294814c5a4ddff72278 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sat, 13 Apr 2024 12:06:36 +0000 Subject: [PATCH 10/22] [cron] Bump distribution date (2024-04-13) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 4bdfcdaebb..113c27fe54 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 "2024-04-11" +//#define STRING_DISTRIBUTION_DATE "2024-04-13" /** * Defines a generic printer name to be output to the LCD after booting Marlin. diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index cb598b58ad..1fa8ce961f 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 "2024-04-11" + #define STRING_DISTRIBUTION_DATE "2024-04-13" #endif /** From d99e150097ddfd9cf369c4643888622769e147fb Mon Sep 17 00:00:00 2001 From: David Buezas Date: Sat, 13 Apr 2024 18:54:25 +0200 Subject: [PATCH 11/22] =?UTF-8?q?=E2=9A=A1=EF=B8=8FReduce=20DISPLAY=5FSLEE?= =?UTF-8?q?P=5FMINUTES=20overhead=20(#26964)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/lcd/dogm/marlinui_DOGM.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp index a96d8e3002..06a234d04d 100644 --- a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp +++ b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp @@ -377,7 +377,13 @@ void MarlinUI::draw_kill_screen() { void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop #if HAS_DISPLAY_SLEEP - void MarlinUI::sleep_display(const bool sleep/*=true*/) { sleep ? u8g.sleepOn() : u8g.sleepOff(); } + void MarlinUI::sleep_display(const bool sleep/*=true*/) { + static bool asleep = false; + if (asleep != sleep){ + sleep ? u8g.sleepOn() : u8g.sleepOff(); + asleep = sleep; + } + } #endif #if HAS_LCD_BRIGHTNESS From cf7c86d5815e604a7be13f570761514d5897bbd4 Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Sat, 13 Apr 2024 14:59:59 -0400 Subject: [PATCH 12/22] =?UTF-8?q?=F0=9F=94=A7Fix=20M936=20in=20features.in?= =?UTF-8?q?i=20(#26957)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/features.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ini/features.ini b/ini/features.ini index 1100216867..8999c8f23d 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -314,7 +314,6 @@ HAS_ZV_SHAPING = build_src_filter=+ GRADIENT_MIX = build_src_filter=+ NONLINEAR_EXTRUSION = build_src_filter=+ -OTA_FIRMWARE_UPDATE = build_src_filter=+ HAS_SAVED_POSITIONS = build_src_filter=+ + PARK_HEAD_ON_PAUSE = build_src_filter=+ FILAMENT_LOAD_UNLOAD_GCODES = build_src_filter=+ @@ -340,6 +339,7 @@ TOUCH_SCREEN_CALIBRATION = build_src_filter=+ GCODE_MOTION_MODES = build_src_filter=+ BABYSTEPPING = build_src_filter=+ + +OTA_FIRMWARE_UPDATE = build_src_filter=+ Z_PROBE_SLED = build_src_filter=+ G38_PROBE_TARGET = build_src_filter=+ MAGNETIC_PARKING_EXTRUDER = build_src_filter=+ From d10861e478d60042a0836e95b8a22e7b68a1d9e5 Mon Sep 17 00:00:00 2001 From: Jason Smith Date: Sat, 13 Apr 2024 12:06:08 -0700 Subject: [PATCH 13/22] =?UTF-8?q?=E2=9C=85=20Add=20unit=20testing=20framew?= =?UTF-8?q?ork=20(#26948)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add a framework to build and execute unit tests for Marlin. - Enable unit test execution as part of PR checks. --------- Co-authored-by: Costas Basdekis Co-authored-by: Scott Lahteine --- .../{test-builds.yml => ci-build-tests.yml} | 6 +- .github/workflows/ci-unit-tests.yml | 73 ++++++++ Makefile | 34 +++- Marlin/src/HAL/LINUX/hardware/Timer.cpp | 5 +- Marlin/src/HAL/LINUX/main.cpp | 2 + Marlin/src/tests/marlin_tests.cpp | 35 ---- Marlin/tests/README.md | 5 + Marlin/tests/gcode/test_gcode.cpp | 58 +++++++ Marlin/tests/runout/test_runout_sensor.cpp | 36 ++++ Marlin/tests/types/test_types.cpp | 160 ++++++++++++++++++ README.md | 106 +++++------- buildroot/bin/restore_configs | 2 +- .../PlatformIO/scripts/collect-code-tests.py | 59 +++++++ .../PlatformIO/scripts/preflight-checks.py | 4 +- ini/native.ini | 15 +- test/001-default.ini | 8 + test/002-extruders_1_runout.ini | 18 ++ test/003-extruders_3_runout.ini | 32 ++++ test/README.md | 40 +++++ test/unit_tests.cpp | 52 ++++++ test/unit_tests.h | 73 ++++++++ 21 files changed, 711 insertions(+), 112 deletions(-) rename .github/workflows/{test-builds.yml => ci-build-tests.yml} (98%) create mode 100644 .github/workflows/ci-unit-tests.yml create mode 100644 Marlin/tests/README.md create mode 100644 Marlin/tests/gcode/test_gcode.cpp create mode 100644 Marlin/tests/runout/test_runout_sensor.cpp create mode 100644 Marlin/tests/types/test_types.cpp create mode 100644 buildroot/share/PlatformIO/scripts/collect-code-tests.py create mode 100644 test/001-default.ini create mode 100644 test/002-extruders_1_runout.ini create mode 100644 test/003-extruders_3_runout.ini create mode 100644 test/README.md create mode 100644 test/unit_tests.cpp create mode 100644 test/unit_tests.h diff --git a/.github/workflows/test-builds.yml b/.github/workflows/ci-build-tests.yml similarity index 98% rename from .github/workflows/test-builds.yml rename to .github/workflows/ci-build-tests.yml index a3cf32739c..ad37100d60 100644 --- a/.github/workflows/test-builds.yml +++ b/.github/workflows/ci-build-tests.yml @@ -1,9 +1,9 @@ # -# test-builds.yml +# ci-build-tests.yml # Do test builds to catch compile errors # -name: CI +name: CI - Build Tests on: pull_request: @@ -27,7 +27,7 @@ on: jobs: test_builds: - name: Run All Tests + name: Build Test if: github.repository == 'MarlinFirmware/Marlin' runs-on: ubuntu-latest diff --git a/.github/workflows/ci-unit-tests.yml b/.github/workflows/ci-unit-tests.yml new file mode 100644 index 0000000000..caed5b1fbc --- /dev/null +++ b/.github/workflows/ci-unit-tests.yml @@ -0,0 +1,73 @@ +# +# ci-unit-tests.yml +# Build and execute unit tests to catch functional issues in code +# + +name: CI - Unit Tests + +on: + pull_request: + branches: + - bugfix-2.1.x + # Cannot be enabled on 2.1.x until it contains the unit test framework + #- 2.1.x + paths-ignore: + - config/** + - data/** + - docs/** + - '**/*.md' + push: + branches: + - bugfix-2.1.x + # Cannot be enabled on 2.1.x until it contains the unit test framework + #- 2.1.x + paths-ignore: + - config/** + - data/** + - docs/** + - '**/*.md' + +jobs: + # This runs all unit tests as a single job. While it should be possible to break this up into + # multiple jobs, they currently run quickly and finish long before the compilation tests. + run_unit_tests: + name: Unit Test + # These tests will only be able to run on the bugfix-2.1.x branch, until the next release + # pulls them into additional branches. + if: github.repository == 'MarlinFirmware/Marlin' + + runs-on: ubuntu-latest + + steps: + - name: Check out the PR + uses: actions/checkout@v4 + + - name: Cache pip + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Cache PlatformIO + uses: actions/cache@v4 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + + - name: Select Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: '3.9' + architecture: 'x64' + + - name: Install PlatformIO + run: | + pip install -U platformio + pio upgrade --dev + pio pkg update --global + + - name: Run All Unit Tests + run: | + make unit-test-all-local diff --git a/Makefile b/Makefile index bc26173aaf..029ab3ada1 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,12 @@ help: @echo "make tests-single-local-docker : Run a single test locally, using docker" @echo "make tests-all-local : Run all tests locally" @echo "make tests-all-local-docker : Run all tests locally, using docker" - @echo "make setup-local-docker : Build the local docker image" +# @echo "make unit-test-single-ci : Run a single code test from inside the CI" +# @echo "make unit-test-single-local : Run a single code test locally" +# @echo "make unit-test-single-local-docker : Run a single code test locally, using docker-compose" + @echo "make unit-test-all-local : Run all code tests locally" + @echo "make unit-test-all-local-docker : Run all code tests locally, using docker-compose" + @echo "make setup-local-docker : Setup local docker-compose" @echo "" @echo "Options for testing:" @echo " TEST_TARGET Set when running tests-single-*, to select the" @@ -43,7 +48,7 @@ tests-single-local: tests-single-local-docker: @if ! test -n "$(TEST_TARGET)" ; then echo "***ERROR*** Set TEST_TARGET= or use make tests-all-local-docker" ; return 1; fi @if ! $(CONTAINER_RT_BIN) images -q $(CONTAINER_IMAGE) > /dev/null ; then $(MAKE) setup-local-docker ; fi - $(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) $(MAKE) tests-single-local TEST_TARGET=$(TEST_TARGET) VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) ONLY_TEST="$(ONLY_TEST)" + $(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) make tests-single-local TEST_TARGET=$(TEST_TARGET) VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) ONLY_TEST="$(ONLY_TEST)" tests-all-local: export PATH="./buildroot/bin/:./buildroot/tests/:${PATH}" \ @@ -52,10 +57,31 @@ tests-all-local: tests-all-local-docker: @if ! $(CONTAINER_RT_BIN) images -q $(CONTAINER_IMAGE) > /dev/null ; then $(MAKE) setup-local-docker ; fi - $(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) $(MAKE) tests-all-local VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) + $(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) make tests-all-local VERBOSE_PLATFORMIO=$(VERBOSE_PLATFORMIO) GIT_RESET_HARD=$(GIT_RESET_HARD) + +#unit-test-single-ci: +# export GIT_RESET_HARD=true +# $(MAKE) unit-test-single-local TEST_TARGET=$(TEST_TARGET) + +# TODO: How can we limit tests with ONLY_TEST with platformio? +#unit-test-single-local: +# @if ! test -n "$(TEST_TARGET)" ; then echo "***ERROR*** Set TEST_TARGET= or use make unit-test-all-local" ; return 1; fi +# platformio run -t marlin_$(TEST_TARGET) + +#unit-test-single-local-docker: +# @if ! test -n "$(TEST_TARGET)" ; then echo "***ERROR*** Set TEST_TARGET= or use make unit-test-all-local-docker" ; return 1; fi +# @if ! $(CONTAINER_RT_BIN) images -q $(CONTAINER_IMAGE) > /dev/null ; then $(MAKE) setup-local-docker ; fi +# $(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) make unit-test-single-local TEST_TARGET=$(TEST_TARGET) ONLY_TEST="$(ONLY_TEST)" + +unit-test-all-local: + platformio run -t test-marlin -e linux_native_test + +unit-test-all-local-docker: + @if ! $(CONTAINER_RT_BIN) images -q $(CONTAINER_IMAGE) > /dev/null ; then $(MAKE) setup-local-docker ; fi + $(CONTAINER_RT_BIN) run $(CONTAINER_RT_OPTS) $(CONTAINER_IMAGE) make unit-test-all-local setup-local-docker: - $(CONTAINER_RT_BIN) build -t $(CONTAINER_IMAGE) -f docker/Dockerfile . + $(CONTAINER_RT_BIN) buildx build -t $(CONTAINER_IMAGE) -f docker/Dockerfile . PINS := $(shell find Marlin/src/pins -mindepth 2 -name '*.h') diff --git a/Marlin/src/HAL/LINUX/hardware/Timer.cpp b/Marlin/src/HAL/LINUX/hardware/Timer.cpp index 9f0d6a8f3a..013690a404 100644 --- a/Marlin/src/HAL/LINUX/hardware/Timer.cpp +++ b/Marlin/src/HAL/LINUX/hardware/Timer.cpp @@ -37,7 +37,10 @@ Timer::Timer() { } Timer::~Timer() { - timer_delete(timerid); + if (timerid != 0) { + timer_delete(timerid); + timerid = 0; + } } void Timer::init(uint32_t sig_id, uint32_t sim_freq, callback_fn* fn) { diff --git a/Marlin/src/HAL/LINUX/main.cpp b/Marlin/src/HAL/LINUX/main.cpp index f2af2ff33f..27a066d619 100644 --- a/Marlin/src/HAL/LINUX/main.cpp +++ b/Marlin/src/HAL/LINUX/main.cpp @@ -21,6 +21,7 @@ */ #ifdef __PLAT_LINUX__ +#ifndef UNIT_TEST //#define GPIO_LOGGING // Full GPIO and Positional Logging @@ -135,4 +136,5 @@ int main() { read_serial.join(); } +#endif // UNIT_TEST #endif // __PLAT_LINUX__ diff --git a/Marlin/src/tests/marlin_tests.cpp b/Marlin/src/tests/marlin_tests.cpp index f61f840176..89e5664345 100644 --- a/Marlin/src/tests/marlin_tests.cpp +++ b/Marlin/src/tests/marlin_tests.cpp @@ -37,41 +37,6 @@ // Startup tests are run at the end of setup() void runStartupTests() { // Call post-setup tests here to validate behaviors. - - // String with cutoff at 20 chars: - // "F-string, 1234.50, 2" - SString<20> str20; - str20 = F("F-string, "); - str20.append(1234.5f).append(',').append(' ') - .append(2345.67).append(',').append(' ') - .echoln(); - - // Truncate to "F-string" - str20.trunc(8).echoln(); - - // 100 dashes, but chopped down to DEFAULT_MSTRING_SIZE (20) - TSS(repchr_t('-', 100)).echoln(); - - // Hello World!-123456------ str(F("Hello")); - str.append(F(" World!")); - str += '-'; - str += uint8_t(123); - str += F("456"); - str += repchr_t('-', 6); - str += Spaces(3); - str += "< spaces!"; - str += int8_t(33); - str.eol(); - str += "^ eol!"; - - str.append("...", 1234.5f, '*', p_float_t(2345.602, 3), F(" = "), 1234.5 * 2345.602).echoln(); - - // Print it again with SERIAL_ECHOLN - auto print_char_ptr = [](char * const str) { SERIAL_ECHOLN(str); }; - print_char_ptr(str); - } // Periodic tests are run from within loop() diff --git a/Marlin/tests/README.md b/Marlin/tests/README.md new file mode 100644 index 0000000000..883069f044 --- /dev/null +++ b/Marlin/tests/README.md @@ -0,0 +1,5 @@ +These test files are executed by the unit-tests built from the `/test` folder. + +These are placed outside of the main PlatformIO test folder so we can collect all test files and compile them into multiple PlatformIO test binaries. This enables tests to be executed against a variety of Marlin configurations. + +To execute these tests, refer to the top-level Makefile. diff --git a/Marlin/tests/gcode/test_gcode.cpp b/Marlin/tests/gcode/test_gcode.cpp new file mode 100644 index 0000000000..be364cb905 --- /dev/null +++ b/Marlin/tests/gcode/test_gcode.cpp @@ -0,0 +1,58 @@ +/** + * 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 . + * + */ + +#include "../test/unit_tests.h" +#include +#include + +MARLIN_TEST(gcode, process_parsed_command) { + GcodeSuite suite; + parser.command_letter = 'G'; + parser.codenum = 0; + suite.process_parsed_command(false); +} + +MARLIN_TEST(gcode, parse_g1_xz) { + char current_command[] = "G0 X10 Z30"; + parser.command_letter = -128; + parser.codenum = -1; + parser.parse(current_command); + TEST_ASSERT_EQUAL('G', parser.command_letter); + TEST_ASSERT_EQUAL(0, parser.codenum); + TEST_ASSERT_TRUE(parser.seen('X')); + TEST_ASSERT_FALSE(parser.seen('Y')); + TEST_ASSERT_TRUE(parser.seen('Z')); + TEST_ASSERT_FALSE(parser.seen('E')); +} + +MARLIN_TEST(gcode, parse_g1_nxz) { + char current_command[] = "N123 G0 X10 Z30"; + parser.command_letter = -128; + parser.codenum = -1; + parser.parse(current_command); + TEST_ASSERT_EQUAL('G', parser.command_letter); + TEST_ASSERT_EQUAL(0, parser.codenum); + TEST_ASSERT_TRUE(parser.seen('X')); + TEST_ASSERT_FALSE(parser.seen('Y')); + TEST_ASSERT_TRUE(parser.seen('Z')); + TEST_ASSERT_FALSE(parser.seen('E')); +} diff --git a/Marlin/tests/runout/test_runout_sensor.cpp b/Marlin/tests/runout/test_runout_sensor.cpp new file mode 100644 index 0000000000..2719446437 --- /dev/null +++ b/Marlin/tests/runout/test_runout_sensor.cpp @@ -0,0 +1,36 @@ +/** + * 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 . + * + */ + +#include "../test/unit_tests.h" + +#if ENABLED(FILAMENT_RUNOUT_SENSOR) + +#include + +MARLIN_TEST(runout, poll_runout_states) { + FilamentSensorBase sensor; + // Expected default value is one bit set for each extruder + uint8_t expected = static_cast(~(~0u << NUM_RUNOUT_SENSORS)); + TEST_ASSERT_EQUAL(expected, sensor.poll_runout_states()); +} + +#endif diff --git a/Marlin/tests/types/test_types.cpp b/Marlin/tests/types/test_types.cpp new file mode 100644 index 0000000000..11ed19f4c3 --- /dev/null +++ b/Marlin/tests/types/test_types.cpp @@ -0,0 +1,160 @@ +/** + * 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 . + * + */ + +#include "../test/unit_tests.h" +#include "src/core/types.h" + +MARLIN_TEST(types, XYval_const_as_bools) { + const XYval xy_const_true = {1, 2}; + TEST_ASSERT_TRUE(xy_const_true); + + const XYval xy_const_false = {0, 0}; + TEST_ASSERT_FALSE(xy_const_false); +} + +MARLIN_TEST(types, XYval_non_const_as_bools) { + XYval xy_true = {1, 2}; + TEST_ASSERT_TRUE(xy_true); + + XYval xy_false = {0, 0}; + TEST_ASSERT_FALSE(xy_false); +} + +MARLIN_TEST(types, XYZval_const_as_bools) { + const XYZval xyz_const_true = {1, 2, 3}; + TEST_ASSERT_TRUE(xyz_const_true); + + const XYZval xyz_const_false = {0, 0, 0}; + TEST_ASSERT_FALSE(xyz_const_false); +} + +MARLIN_TEST(types, XYZval_non_const_as_bools) { + XYZval xyz_true = {1, 2, 3}; + TEST_ASSERT_TRUE(xyz_true); + + XYZval xyz_false = {0, 0, 0}; + TEST_ASSERT_FALSE(xyz_false); +} + +MARLIN_TEST(types, XYZEval_const_as_bools) { + const XYZEval xyze_const_true = {1, 2, 3, 4}; + TEST_ASSERT_TRUE(xyze_const_true); + + const XYZEval xyze_const_false = {0, 0, 0, 0}; + TEST_ASSERT_FALSE(xyze_const_false); +} + +MARLIN_TEST(types, XYZEval_non_const_as_bools) { + XYZEval xyze_true = {1, 2, 3, 4}; + TEST_ASSERT_TRUE(xyze_true); + + XYZEval xyze_false = {0, 0, 0, 0}; + TEST_ASSERT_FALSE(xyze_false); +} + +MARLIN_TEST(types, Flags_const_as_bools) { + const Flags<32> flags_const_false = {0}; + TEST_ASSERT_FALSE(flags_const_false); + + const Flags<32> flags_const_true = {1}; + TEST_ASSERT_TRUE(flags_const_true); +} + +MARLIN_TEST(types, Flags_non_const_as_bools) { + Flags<32> flags_false = {0}; + TEST_ASSERT_FALSE(flags_false); + + Flags<32> flags_true = {1}; + TEST_ASSERT_TRUE(flags_true); +} + +MARLIN_TEST(types, AxisFlags_const_as_bools) { + const AxisFlags axis_flags_const_false = {0}; + TEST_ASSERT_FALSE(axis_flags_const_false); + + const AxisFlags axis_flags_const_true = {1}; + TEST_ASSERT_TRUE(axis_flags_const_true); +} + +MARLIN_TEST(types, AxisFlags_non_const_as_bools) { + AxisFlags axis_flags_false = {0}; + TEST_ASSERT_FALSE(axis_flags_false); + + AxisFlags axis_flags_true = {1}; + TEST_ASSERT_TRUE(axis_flags_true); +} + +MARLIN_TEST(types, AxisBits_const_as_bools) { + const AxisBits axis_bits_const_false = {0}; + TEST_ASSERT_FALSE(axis_bits_const_false); + + const AxisBits axis_bits_const_true = {1}; + TEST_ASSERT_TRUE(axis_bits_const_true); +} + +MARLIN_TEST(types, AxisBits_non_const_as_bools) { + AxisBits axis_bits_false = {0}; + TEST_ASSERT_FALSE(axis_bits_false); + + AxisBits axis_bits_true = {1}; + TEST_ASSERT_TRUE(axis_bits_true); +} + +MARLIN_TEST(types, MString1) { + // String with cutoff at 20 chars: + // "F-string, 1234.50, 2" + MString<20> str20; + str20 = F("F-string, "); + str20.append(1234.5f).append(',').append(' ') + .append(2345.67).append(',').append(' '); + + TEST_ASSERT_TRUE(strcmp_P(str20, PSTR("F-string, 1234.50, 2")) == 0); + + // Truncate to "F-string" + str20.trunc(8); + + TEST_ASSERT_FALSE(strcmp_P(&str20, PSTR("F-string")) != 0); +} + +MARLIN_TEST(types, MString2) { + // 100 dashes, but chopped down to DEFAULT_MSTRING_SIZE (20) + TEST_ASSERT_TRUE(TSS(repchr_t('-', 100)).length() == 20); +} + +MARLIN_TEST(types, SString) { + // Hello World!-123456------ < spaces!33 + // ^ eol! ... 1234.50*2345.602 = 2895645.67 + SString<100> str(F("Hello")); + str.append(F(" World!")); + str += '-'; + str += uint8_t(123); + str += F("456"); + str += repchr_t('-', 6); + str += Spaces(3); + str += "< spaces!"; + str += int8_t(33); + str.eol(); + str += "^ eol!"; + str.append(" ... ", 1234.5f, '*', p_float_t(2345.602, 3), F(" = "), 1234.5 * 2345.602); + + TEST_ASSERT_TRUE(strcmp_P(str, PSTR("Hello World!-123456------ < spaces!33\n^ eol! ... 1234.50*2345.602 = 2895645.67")) == 0); +} diff --git a/README.md b/README.md index 83614ad9cc..efbba1de27 100644 --- a/README.md +++ b/README.md @@ -39,16 +39,16 @@ To build and upload Marlin you will use one of these tools: Marlin is optimized to build with the **PlatformIO IDE** extension for **Visual Studio Code**. You can still build Marlin with **Arduino IDE**, and we hope to improve the Arduino build experience, but at this time PlatformIO is the better choice. +## 8-Bit AVR Boards + +We intend to continue supporting 8-bit AVR boards in perpetuity, maintaining a single codebase that can apply to all machines. We want casual hobbyists and tinkerers and owners of older machines to benefit from the community's innovations just as much as those with fancier machines. Plus, those old AVR-based machines are often the best for your testing and feedback! + ## Hardware Abstraction Layer (HAL) Marlin includes an abstraction layer to provide a common API for all the platforms it targets. This allows Marlin code to address the details of motion and user interface tasks at the lowest and highest levels with no system overhead, tying all events directly to the hardware clock. Every new HAL opens up a world of hardware. At this time we need HALs for RP2040 and the Duet3D family of boards. A HAL that wraps an RTOS is an interesting concept that could be explored. Did you know that Marlin includes a Simulator that can run on Windows, macOS, and Linux? Join the Discord to help move these sub-projects forward! -## 8-Bit AVR Boards - -A core tenet of this project is to keep supporting 8-bit AVR boards while also maintaining a single codebase that applies equally to all machines. We want casual hobbyists to benefit from the community's innovations as much as possible just as much as those with fancier machines. Plus, those old AVR-based machines are often the best for your testing and feedback! - ### Supported Platforms Platform|MCU|Example Boards @@ -71,22 +71,9 @@ A core tenet of this project is to keep supporting 8-bit AVR boards while also m [Teensy 4.1](https://www.pjrc.com/store/teensy41.html)|ARMยฎ Cortex-M7| Linux Native|x86/ARM/etc.|Raspberry Pi -## Submitting Patches - -Proposed patches should be submitted as a Pull Request against the ([bugfix-2.1.x](https://github.com/MarlinFirmware/Marlin/tree/bugfix-2.1.x)) branch. - -- This branch is for fixing bugs and integrating any new features for the duration of the Marlin 2.1.x life-cycle. -- Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) to gain points with the maintainers. -- Please submit Feature Requests and Bug Reports to the [Issue Queue](https://github.com/MarlinFirmware/Marlin/issues/new/choose). Support resources are also listed there. -- Whenever you add new features, be sure to add tests to `buildroot/tests` and then run your tests locally, if possible. - - It's optional: Running all the tests on Windows might take a long time, and they will run anyway on GitHub. - - If you're running the tests on Linux (or on WSL with the code on a Linux volume) the speed is much faster. - - You can use `make tests-all-local` or `make tests-single-local TEST_TARGET=...`. - - If you prefer Docker you can use `make tests-all-local-docker` or `make tests-all-local-docker TEST_TARGET=...`. - ## Marlin Support -The Issue Queue is reserved for Bug Reports and Feature Requests. To get help with configuration and troubleshooting, please use the following resources: +The Issue Queue is reserved for Bug Reports and Feature Requests. Please use the following resources for help with configuration and troubleshooting: - [Marlin Documentation](https://marlinfw.org) - Official Marlin documentation - [Marlin Discord](https://discord.gg/n5NJ59y) - Discuss issues with Marlin users and developers @@ -95,59 +82,48 @@ The Issue Queue is reserved for Bug Reports and Feature Requests. To get help wi - Facebook Group ["Marlin Firmware for 3D Printers"](https://www.facebook.com/groups/3Dtechtalk/) - [Marlin Configuration](https://www.youtube.com/results?search_query=marlin+configuration) on YouTube +## Contributing Patches + +You can contribute patches by submitting a Pull Request to the ([bugfix-2.1.x](https://github.com/MarlinFirmware/Marlin/tree/bugfix-2.1.x)) branch. + +- We use branches named with a "bugfix" or "dev" prefix to fix bugs and integrate new features. +- Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) to gain points with the maintainers. +- Please submit Feature Requests and Bug Reports to the [Issue Queue](https://github.com/MarlinFirmware/Marlin/issues/new/choose). See above for user support. +- Whenever you add new features, be sure to add one or more build tests to `buildroot/tests`. Any tests added to a PR will be run within that PR on GitHub servers as soon as they are pushed. To minimize iteration be sure to run your new tests locally, if possible. + - Local build tests: + - All: `make tests-config-all-local` + - Single: `make tests-config-single-local TEST_TARGET=...` + - Local build tests in Docker: + - All: `make tests-config-all-local-docker` + - Single: `make tests-config-all-local-docker TEST_TARGET=...` + - To run all unit test suites: + - Using PIO: `platformio run -t test-marlin` + - Using Make: `make unit-test-all-local` + - Using Docker + make: `maker unit-test-all-local-docker` + - To run a single unit test suite: + - Using PIO: `platformio run -t marlin_` + - Using make: `make unit-test-single-local TEST_TARGET=` + - Using Docker + make: `maker unit-test-single-local-docker TEST_TARGET=` +- If your feature can be unit tested, add one or more unit tests. For more information see our documentation on [Unit Tests](test). + ## Contributors Marlin is constantly improving thanks to a huge number of contributors from all over the world bringing their specialties and talents. Huge thanks are due to [all the contributors](https://github.com/MarlinFirmware/Marlin/graphs/contributors) who regularly patch up bugs, help direct traffic, and basically keep Marlin from falling apart. Marlin's continued existence would not be possible without them. -## Administration +## Project Leadership -Regular users can open and close their own issues, but only the administrators can do project-related things like add labels, merge changes, set milestones, and kick trolls. The current Marlin admin team consists of: - - - - -
Project Maintainer
- - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Scott Lahteine** - โ€…โ€…โ€…โ€…โ€…โ€…[@thinkyhead](https://github.com/thinkyhead) - โ€…โ€…โ€…โ€…โ€…โ€…[โ€…โ€…Donate ๐Ÿ’ธโ€…โ€…](https://www.thinkyhead.com/donate-to-marlin) - - - - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Roxanne Neufeld** - โ€…โ€…โ€…โ€…โ€…โ€…[@Roxy-3D](https://github.com/Roxy-3D) - - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Keith Bennett** - โ€…โ€…โ€…โ€…โ€…โ€…[@thisiskeithb](https://github.com/thisiskeithb) - โ€…โ€…โ€…โ€…โ€…โ€…[โ€…โ€…Donate ๐Ÿ’ธโ€…โ€…](https://github.com/sponsors/thisiskeithb) - - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Jason Smith** - โ€…โ€…โ€…โ€…โ€…โ€…[@sjasonsmith](https://github.com/sjasonsmith) - - - - ๐Ÿ‡ง๐Ÿ‡ทโ€…โ€…**Victor Oliveira** - โ€…โ€…โ€…โ€…โ€…โ€…[@rhapsodyv](https://github.com/rhapsodyv) - - ๐Ÿ‡ฌ๐Ÿ‡งโ€…โ€…**Chris Pepper** - โ€…โ€…โ€…โ€…โ€…โ€…[@p3p](https://github.com/p3p) - -๐Ÿ‡ณ๐Ÿ‡ฟโ€…โ€…**Peter Ellens** - โ€…โ€…โ€…โ€…โ€…โ€…[@ellensp](https://github.com/ellensp) - โ€…โ€…โ€…โ€…โ€…โ€…[โ€…โ€…Donate ๐Ÿ’ธโ€…โ€…](https://ko-fi.com/ellensp) - - - - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Bob Kuhn** - โ€…โ€…โ€…โ€…โ€…โ€…[@Bob-the-Kuhn](https://github.com/Bob-the-Kuhn) - - ๐Ÿ‡ณ๐Ÿ‡ฑโ€…โ€…**Erik van der Zalm** - โ€…โ€…โ€…โ€…โ€…โ€…[@ErikZalm](https://github.com/ErikZalm) - -
+Name|Role|Link|Donate +----|----|----|---- +๐Ÿ‡บ๐Ÿ‡ธ Scott Lahteine|Project Lead|[[@thinkyhead](https://github.com/thinkyhead)]|[๐Ÿ’ธ Donate](https://www.thinkyhead.com/donate-to-marlin) +๐Ÿ‡บ๐Ÿ‡ธ Roxanne Neufeld|Admin|[[@Roxy-3D](https://github.com/Roxy-3D)]| +๐Ÿ‡บ๐Ÿ‡ธ Keith Bennett|Admin|[[@thisiskeithb](https://github.com/thisiskeithb)]|[๐Ÿ’ธ Donate](https://github.com/sponsors/thisiskeithb) +๐Ÿ‡บ๐Ÿ‡ธ Jason Smith|Admin|[[@sjasonsmith](https://github.com/sjasonsmith)]| +๐Ÿ‡ง๐Ÿ‡ท Victor Oliveira|Admin|[[@rhapsodyv](https://github.com/rhapsodyv)]| +๐Ÿ‡ฌ๐Ÿ‡ง Chris Pepper|Admin|[[@p3p](https://github.com/p3p)]| +๐Ÿ‡ณ๐Ÿ‡ฟ Peter Ellens|Admin|[[@ellensp](https://github.com/ellensp)]|[๐Ÿ’ธ Donate](https://ko-fi.com/ellensp) +๐Ÿ‡บ๐Ÿ‡ธ Bob Kuhn|Admin|[[@Bob-the-Kuhn](https://github.com/Bob-the-Kuhn)]| +๐Ÿ‡ณ๐Ÿ‡ฑ Erik van der Zalm|Founder|[[@ErikZalm](https://github.com/ErikZalm)]|[๐Ÿ’ธ Donate](https://flattr.com/submit/auto?user_id=ErikZalm&url=https://github.com/MarlinFirmware/Marlin&title=Marlin&language=&tags=github&category=software) ## 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. - -While we can't prevent the use of this code in products (3D printers, CNC, etc.) that are closed source or crippled by a patent, we would prefer that you choose another firmware or, better yet, make your own. diff --git a/buildroot/bin/restore_configs b/buildroot/bin/restore_configs index ea998484c2..51f72c5792 100755 --- a/buildroot/bin/restore_configs +++ b/buildroot/bin/restore_configs @@ -7,5 +7,5 @@ if [[ $1 == '-d' || $1 == '--default' ]]; then else git checkout Marlin/Configuration.h 2>/dev/null git checkout Marlin/Configuration_adv.h 2>/dev/null - git checkout Marlin/src/pins/ramps/pins_RAMPS.h 2>/dev/null + git checkout Marlin/src/pins/*/pins_*.h 2>/dev/null fi diff --git a/buildroot/share/PlatformIO/scripts/collect-code-tests.py b/buildroot/share/PlatformIO/scripts/collect-code-tests.py new file mode 100644 index 0000000000..a0e0e86b11 --- /dev/null +++ b/buildroot/share/PlatformIO/scripts/collect-code-tests.py @@ -0,0 +1,59 @@ +# +# collect-code-tests.py +# Convenience script to collect all code tests. Used by env:linux_native_test in native.ini. +# + +import pioutil +if pioutil.is_pio_build(): + + import os, re + Import("env") + Import("projenv") + + os.environ['PATH'] = f"./buildroot/bin/:./buildroot/tests/:{os.environ['PATH']}" + + def collect_test_suites(): + """Get all the test suites""" + from pathlib import Path + return sorted(list(Path("./test").glob("*.ini"))) + + def register_test_suites(): + """Register all the test suites""" + targets = [] + test_suites = collect_test_suites() + for path in test_suites: + name = re.sub(r'^\d+-|\.ini$', '', path.name) + targets += [name]; + + env.AddCustomTarget( + name = f"marlin_{name}", + dependencies = None, + actions = [ + f"echo ====== Configuring for marlin_{name} ======", + "restore_configs", + f"cp -f {path} ./Marlin/config.ini", + "python ./buildroot/share/PlatformIO/scripts/configuration.py", + f"platformio test -e linux_native_test -f {name}", + "restore_configs", + ], + title = "Marlin: {}".format(name.lower().title().replace("_", " ")), + description = ( + f"Run a Marlin test suite, with the appropriate configuration, " + f"that sits in {path}" + ) + ) + + env.AddCustomTarget( + name = "test-marlin", + dependencies = None, + actions = [ + f"platformio run -t marlin_{name} -e linux_native_test" + for name in targets + ], + title = "Marlin: Test all code test suites", + description = ( + f"Run all Marlin code test suites ({len(targets)} found)." + ), + ) + + register_test_suites() diff --git a/buildroot/share/PlatformIO/scripts/preflight-checks.py b/buildroot/share/PlatformIO/scripts/preflight-checks.py index 2e4ab5c92d..2a5f98dbbf 100644 --- a/buildroot/share/PlatformIO/scripts/preflight-checks.py +++ b/buildroot/share/PlatformIO/scripts/preflight-checks.py @@ -71,7 +71,9 @@ if pioutil.is_pio_build(): config = env.GetProjectConfig() result = check_envs("env:"+build_env, board_envs, config) - if not result: + # Make sure board is compatible with the build environment. Skip for _test, + # since the board is manipulated as each unit test is executed. + if not result and build_env != "linux_native_test": err = "Error: Build environment '%s' is incompatible with %s. Use one of these environments: %s" % \ ( build_env, motherboard, ", ".join([ e[4:] for e in board_envs if e.startswith("env:") ]) ) raise SystemExit(err) diff --git a/ini/native.ini b/ini/native.ini index d07eaa2205..332555ed05 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -15,13 +15,24 @@ [env:linux_native] platform = native framework = -build_flags = -D__PLAT_LINUX__ -std=gnu++17 -ggdb -g -lrt -lpthread -D__MARLIN_FIRMWARE__ -Wno-expansion-to-defined +build_flags = ${common.build_flags} -D__PLAT_LINUX__ -std=gnu++17 -ggdb -g -lrt -lpthread -D__MARLIN_FIRMWARE__ -Wno-expansion-to-defined build_src_flags = -Wall -IMarlin/src/HAL/LINUX/include build_unflags = -Wall lib_ldf_mode = off -lib_deps = build_src_filter = ${common.default_src_filter} + +# Environment specifically for unit testing through the Makefile +# This is somewhat unorthodox, in that it uses the PlatformIO Unity testing framework, +# but actual targets are dynamically generated during the build. This seems to prevent +# Unity from being automatically included, so it is added here. +[env:linux_native_test] +extends = env:linux_native +extra_scripts = ${common.extra_scripts} + post:buildroot/share/PlatformIO/scripts/collect-code-tests.py +build_src_filter = ${env:linux_native.build_src_filter} + +lib_deps = throwtheswitch/Unity@^2.5.2 +test_build_src = true + # # Native Simulation # Builds with a small subset of available features diff --git a/test/001-default.ini b/test/001-default.ini new file mode 100644 index 0000000000..b98042cc2d --- /dev/null +++ b/test/001-default.ini @@ -0,0 +1,8 @@ +# This file should remain empty except for the motherboard. +# If changes are needed by tests, it should be performed in another configuration. + +[config:base] +ini_use_config = base + +# Unit tests must use BOARD_SIMULATED to run natively in Linux +motherboard = BOARD_SIMULATED diff --git a/test/002-extruders_1_runout.ini b/test/002-extruders_1_runout.ini new file mode 100644 index 0000000000..74afa0f02f --- /dev/null +++ b/test/002-extruders_1_runout.ini @@ -0,0 +1,18 @@ +# +# Test configuration with a single extruder and a filament runout sensor +# +[config:base] +ini_use_config = base + +# Unit tests must use BOARD_SIMULATED to run natively in Linux +motherboard = BOARD_SIMULATED + +# Options to support runout sensors test +filament_runout_sensor = on +fil_runout_pin = 4 # dummy +advanced_pause_feature = on +emergency_parser = on +nozzle_park_feature = on + +# Option to support testing parsing with parentheses comments enabled +paren_comments = on diff --git a/test/003-extruders_3_runout.ini b/test/003-extruders_3_runout.ini new file mode 100644 index 0000000000..4bd91e8b7c --- /dev/null +++ b/test/003-extruders_3_runout.ini @@ -0,0 +1,32 @@ +# +# Test configuration with three extruders and filament runout sensors +# +[config:base] +ini_use_config = base + +# Unit tests must use BOARD_SIMULATED to run natively in Linux +motherboard = BOARD_SIMULATED + +# Options to support runout sensor tests on three extruders. +# Options marked "dummy" are simply required to pass sanity checks. +extruders = 3 +temp_sensor_1 = 1 +temp_sensor_2 = 1 +temp_2_pin = 4 # dummy +temp_3_pin = 4 # dummy +heater_2_pin = 4 # dummy +e2_step_pin = 4 # dummy +e2_dir_pin = 4 # dummy +e2_enable_pin = 4 # dummy +e3_step_pin = 4 # dummy +e3_dir_pin = 4 # dummy +e3_enable_pin = 4 # dummy +num_runout_sensors = 3 +filament_runout_sensor = on +fil_runout_pin = 4 # dummy +fil_runout2_pin = 4 # dummy +fil_runout3_pin = 4 # dummy +filament_runout_script = "M600 %%c" +advanced_pause_feature = on +emergency_parser = on +nozzle_park_feature = on diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000000..19b4cd7d59 --- /dev/null +++ b/test/README.md @@ -0,0 +1,40 @@ +# Testing Marlin + +Marlin included two types of automated tests: +- [Build Tests](../buildroot/tests) to catch syntax and code build errors. +- Unit Tests (this folder) to catch implementation errors. + +This document focuses on Unit tests. + +## Unit tests + +Unit testing allows for functional testing of Marlin logic on a local machine. This strategy is available to all developers, and will be able to be used on generic GitHub workers to automate testing. While PlatformIO does support the execution of unit tests on target controllers, that is not yet implemented and not really practical. This would require dedicated testing labs, and would be less broadly usable than testing directly on the development or build machine. + +Unit tests verify the behavior of small discrete sections of Marlin code. By thoroughly unit testing important parts of Marlin code, we effectively provide "guard rails" which will prevent major regressions in behavior. As long as all submissions go through the Pull Request process and execute automated checks, it is possible to catch most major issues prior to completion of a PR. + +## What unit tests can and can't do + +Unit tests can be used to validate the logic of single functions or whole features, as long as that function or feature doesn't depend on real hardware. So, for example, we can test whether a G-code command is parsed correctly and produces all the expected state changes, but we can't test whether a G-code triggered an endstop or the filament runout sensor without adding a new layer to simulate pins. + +Generally speaking, the types of errors caught by unit tests are most often caught in the initial process of writing the tests, and thereafter they shore up the codebase against regressions, especially in core classes and types, which can be very useful for refactoring. + +### Unit test FAQ + +#### Q: Isn't writing unit tests a lot of work? +A: Yes, and it can be especially difficult with existing code that wasn't designed for unit testing. Some common sense should be used to decide where to employ unit testing, and at what level to perform it. While unit testing takes effort, it pays dividends in preventing regressions, and helping to pinpoint the source of failures when they do occur. + +#### Q: Will this make refactoring harder? +A: Yes and No. Of course if you refactor code that unit tests use directly, it will have to be reworked as well. It actually can make refactoring more efficient, by providing assurance that the mechanism still works as intended. + +#### Q: How can I debug one of these failing unit tests? +A: That's a great question, without a known immediate answer. It is likely possible to debug them interactively through PlatformIO, but that can at times take some creativity to configure. Unit tests are generally extremely small, so even without interactive debugging it can get you fairly close to the cause of the problem. + +### Unit test architecture +We are currently using [PlatformIO unit tests](https://docs.platformio.org/en/latest/plus/unit-testing.html). + +Since Marlin only compiles code required by the configuration, a separate test binary must be generated for any configuration change. The following process is used to unit test a variety of configurations: + +1. This folder contains a set of INI configuration files (See `config.ini`), each containing a distinct set of configuration options for unit testing. All applicable unit tests will be run for each of these configurations. +2. The `Marlin/tests` folder contains the CPP code for all Unit Tests. Marlin macros (`ENABLED(feature)`, `TERN(FEATURE, A, B)`, etc.) are used to determine which tests should be registered and to alter test behavior. +3. The `linux_native_test` PlatformIO environment specifies a script to collect all the tests from this folder and add them to PlatformIO's list of test targets. +4. Tests are built and executed by the `Makefile` commands `unit-test-all-local` or `unit-test-all-local-docker`. diff --git a/test/unit_tests.cpp b/test/unit_tests.cpp new file mode 100644 index 0000000000..0d9e568760 --- /dev/null +++ b/test/unit_tests.cpp @@ -0,0 +1,52 @@ +/** + * 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 . + * + */ + +/** + * Provide the main() function used for all compiled unit test binaries. + * It collects all the tests defined in the code and runs them through Unity. + */ + +#include "unit_tests.h" + +static std::list all_marlin_tests; + +MarlinTest::MarlinTest(const std::string _name, const void(*_test)(), const int _line) +: name(_name), test(_test), line(_line) { + all_marlin_tests.push_back(this); +} + +void MarlinTest::run() { + UnityDefaultTestRun((UnityTestFunction)test, name.c_str(), line); +} + +void run_all_marlin_tests() { + for (const auto registration : all_marlin_tests) { + registration->run(); + } +} + +int main(int argc, char **argv) { + UNITY_BEGIN(); + run_all_marlin_tests(); + UNITY_END(); + return 0; +} diff --git a/test/unit_tests.h b/test/unit_tests.h new file mode 100644 index 0000000000..6f8387619a --- /dev/null +++ b/test/unit_tests.h @@ -0,0 +1,73 @@ +/** + * 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 + +#include +#include +#include + +// Include MarlinConfig so configurations are available to all tests +#include "src/inc/MarlinConfig.h" + +/** + * Class that allows us to dynamically collect tests + */ +class MarlinTest { +public: + MarlinTest(const std::string name, const void(*test)(), const int line); + /** + * Run the test via Unity + */ + void run(); + + /** + * The name, a pointer to the function, and the line number. These are + * passed to the Unity test framework. + */ + const std::string name; + const void(*test)(); + const int line; +}; + +/** + * Internal macros used by MARLIN_TEST + */ +#define _MARLIN_TEST_CLASS_NAME(SUITE, NAME) MarlinTestClass_##SUITE##_##NAME +#define _MARLIN_TEST_INSTANCE_NAME(SUITE, NAME) MarlinTestClass_##SUITE##_##NAME##_instance + +/** + * Macro to define a test. This will create a class with the test body and + * register it with the global list of tests. + * + * Usage: + * MARLIN_TEST(test_suite_name, test_name) { + * // Test body + * } + */ +#define MARLIN_TEST(SUITE, NAME) \ + class _MARLIN_TEST_CLASS_NAME(SUITE, NAME) : public MarlinTest { \ + public: \ + _MARLIN_TEST_CLASS_NAME(SUITE, NAME)() : MarlinTest(#NAME, (const void(*)())&TestBody, __LINE__) {} \ + static void TestBody(); \ + }; \ + const _MARLIN_TEST_CLASS_NAME(SUITE, NAME) _MARLIN_TEST_INSTANCE_NAME(SUITE, NAME); \ + void _MARLIN_TEST_CLASS_NAME(SUITE, NAME)::TestBody() From 1bb4a042e26af49602816ef33fcd2f3f4f728329 Mon Sep 17 00:00:00 2001 From: Jason Smith Date: Sat, 13 Apr 2024 14:11:51 -0700 Subject: [PATCH 14/22] =?UTF-8?q?=E2=9C=85Unit=20test=20improvements=20(#2?= =?UTF-8?q?6965)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Do not warn about display in unit tests * Treat warnings as errors in unit tests * Report actual filenames with unit tests --- Marlin/src/inc/Warnings.cpp | 2 +- ini/native.ini | 2 ++ test/unit_tests.cpp | 5 +++-- test/unit_tests.h | 5 +++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index 3a2153916f..2c2a824978 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -99,7 +99,7 @@ #warning "Warning! Don't use dummy thermistors (998/999) for final build!" #endif -#if NONE(HAS_RESUME_CONTINUE, HOST_PROMPT_SUPPORT) +#if NONE(HAS_RESUME_CONTINUE, HOST_PROMPT_SUPPORT, UNIT_TEST) #warning "Your Configuration provides no method to acquire user feedback!" #endif diff --git a/ini/native.ini b/ini/native.ini index 332555ed05..9df621172d 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -32,6 +32,8 @@ extra_scripts = ${common.extra_scripts} build_src_filter = ${env:linux_native.build_src_filter} + lib_deps = throwtheswitch/Unity@^2.5.2 test_build_src = true +build_unflags = +build_flags = ${env:linux_native.build_flags} -Werror # # Native Simulation diff --git a/test/unit_tests.cpp b/test/unit_tests.cpp index 0d9e568760..e22aa529d0 100644 --- a/test/unit_tests.cpp +++ b/test/unit_tests.cpp @@ -29,12 +29,13 @@ static std::list all_marlin_tests; -MarlinTest::MarlinTest(const std::string _name, const void(*_test)(), const int _line) -: name(_name), test(_test), line(_line) { +MarlinTest::MarlinTest(const std::string _name, const void(*_test)(), const char *_file, const int _line) +: name(_name), test(_test), file(_file), line(_line) { all_marlin_tests.push_back(this); } void MarlinTest::run() { + Unity.TestFile = file.c_str(); UnityDefaultTestRun((UnityTestFunction)test, name.c_str(), line); } diff --git a/test/unit_tests.h b/test/unit_tests.h index 6f8387619a..53bb64074a 100644 --- a/test/unit_tests.h +++ b/test/unit_tests.h @@ -33,7 +33,7 @@ */ class MarlinTest { public: - MarlinTest(const std::string name, const void(*test)(), const int line); + MarlinTest(const std::string name, const void(*test)(), const char *_file, const int line); /** * Run the test via Unity */ @@ -45,6 +45,7 @@ public: */ const std::string name; const void(*test)(); + const std::string file; const int line; }; @@ -66,7 +67,7 @@ public: #define MARLIN_TEST(SUITE, NAME) \ class _MARLIN_TEST_CLASS_NAME(SUITE, NAME) : public MarlinTest { \ public: \ - _MARLIN_TEST_CLASS_NAME(SUITE, NAME)() : MarlinTest(#NAME, (const void(*)())&TestBody, __LINE__) {} \ + _MARLIN_TEST_CLASS_NAME(SUITE, NAME)() : MarlinTest(#SUITE "___" #NAME, (const void(*)())&TestBody, __FILE__, __LINE__) {} \ static void TestBody(); \ }; \ const _MARLIN_TEST_CLASS_NAME(SUITE, NAME) _MARLIN_TEST_INSTANCE_NAME(SUITE, NAME); \ From 0683e8a9a3fc79481376c82528d6850c01ec5bd0 Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Sun, 14 Apr 2024 00:24:15 +0000 Subject: [PATCH 15/22] [cron] Bump distribution date (2024-04-14) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 113c27fe54..6612c2f640 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 "2024-04-13" +//#define STRING_DISTRIBUTION_DATE "2024-04-14" /** * Defines a generic printer name to be output to the LCD after booting Marlin. diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 1fa8ce961f..ad30d74977 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 "2024-04-13" + #define STRING_DISTRIBUTION_DATE "2024-04-14" #endif /** From 52a561399eb5bf9f60106e0fa6a74a50e7522e5a Mon Sep 17 00:00:00 2001 From: Keith Bennett <13375512+thisiskeithb@users.noreply.github.com> Date: Sat, 13 Apr 2024 17:47:16 -0700 Subject: [PATCH 16/22] =?UTF-8?q?=E2=8F=AA=EF=B8=8F=20Revert=20unintended?= =?UTF-8?q?=20README=20changes=20(#26967)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Revert all the changes that went in with the unit test framework This restored broken links and other changes. Restoring to the prior revision seems the most appropriate action until the intentions of those file changes are known. --------- Co-authored-by: Jason Smith --- README.md | 106 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index efbba1de27..83614ad9cc 100644 --- a/README.md +++ b/README.md @@ -39,16 +39,16 @@ To build and upload Marlin you will use one of these tools: Marlin is optimized to build with the **PlatformIO IDE** extension for **Visual Studio Code**. You can still build Marlin with **Arduino IDE**, and we hope to improve the Arduino build experience, but at this time PlatformIO is the better choice. -## 8-Bit AVR Boards - -We intend to continue supporting 8-bit AVR boards in perpetuity, maintaining a single codebase that can apply to all machines. We want casual hobbyists and tinkerers and owners of older machines to benefit from the community's innovations just as much as those with fancier machines. Plus, those old AVR-based machines are often the best for your testing and feedback! - ## Hardware Abstraction Layer (HAL) Marlin includes an abstraction layer to provide a common API for all the platforms it targets. This allows Marlin code to address the details of motion and user interface tasks at the lowest and highest levels with no system overhead, tying all events directly to the hardware clock. Every new HAL opens up a world of hardware. At this time we need HALs for RP2040 and the Duet3D family of boards. A HAL that wraps an RTOS is an interesting concept that could be explored. Did you know that Marlin includes a Simulator that can run on Windows, macOS, and Linux? Join the Discord to help move these sub-projects forward! +## 8-Bit AVR Boards + +A core tenet of this project is to keep supporting 8-bit AVR boards while also maintaining a single codebase that applies equally to all machines. We want casual hobbyists to benefit from the community's innovations as much as possible just as much as those with fancier machines. Plus, those old AVR-based machines are often the best for your testing and feedback! + ### Supported Platforms Platform|MCU|Example Boards @@ -71,9 +71,22 @@ Every new HAL opens up a world of hardware. At this time we need HALs for RP2040 [Teensy 4.1](https://www.pjrc.com/store/teensy41.html)|ARMยฎ Cortex-M7| Linux Native|x86/ARM/etc.|Raspberry Pi +## Submitting Patches + +Proposed patches should be submitted as a Pull Request against the ([bugfix-2.1.x](https://github.com/MarlinFirmware/Marlin/tree/bugfix-2.1.x)) branch. + +- This branch is for fixing bugs and integrating any new features for the duration of the Marlin 2.1.x life-cycle. +- Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) to gain points with the maintainers. +- Please submit Feature Requests and Bug Reports to the [Issue Queue](https://github.com/MarlinFirmware/Marlin/issues/new/choose). Support resources are also listed there. +- Whenever you add new features, be sure to add tests to `buildroot/tests` and then run your tests locally, if possible. + - It's optional: Running all the tests on Windows might take a long time, and they will run anyway on GitHub. + - If you're running the tests on Linux (or on WSL with the code on a Linux volume) the speed is much faster. + - You can use `make tests-all-local` or `make tests-single-local TEST_TARGET=...`. + - If you prefer Docker you can use `make tests-all-local-docker` or `make tests-all-local-docker TEST_TARGET=...`. + ## Marlin Support -The Issue Queue is reserved for Bug Reports and Feature Requests. Please use the following resources for help with configuration and troubleshooting: +The Issue Queue is reserved for Bug Reports and Feature Requests. To get help with configuration and troubleshooting, please use the following resources: - [Marlin Documentation](https://marlinfw.org) - Official Marlin documentation - [Marlin Discord](https://discord.gg/n5NJ59y) - Discuss issues with Marlin users and developers @@ -82,48 +95,59 @@ The Issue Queue is reserved for Bug Reports and Feature Requests. Please use the - Facebook Group ["Marlin Firmware for 3D Printers"](https://www.facebook.com/groups/3Dtechtalk/) - [Marlin Configuration](https://www.youtube.com/results?search_query=marlin+configuration) on YouTube -## Contributing Patches - -You can contribute patches by submitting a Pull Request to the ([bugfix-2.1.x](https://github.com/MarlinFirmware/Marlin/tree/bugfix-2.1.x)) branch. - -- We use branches named with a "bugfix" or "dev" prefix to fix bugs and integrate new features. -- Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) to gain points with the maintainers. -- Please submit Feature Requests and Bug Reports to the [Issue Queue](https://github.com/MarlinFirmware/Marlin/issues/new/choose). See above for user support. -- Whenever you add new features, be sure to add one or more build tests to `buildroot/tests`. Any tests added to a PR will be run within that PR on GitHub servers as soon as they are pushed. To minimize iteration be sure to run your new tests locally, if possible. - - Local build tests: - - All: `make tests-config-all-local` - - Single: `make tests-config-single-local TEST_TARGET=...` - - Local build tests in Docker: - - All: `make tests-config-all-local-docker` - - Single: `make tests-config-all-local-docker TEST_TARGET=...` - - To run all unit test suites: - - Using PIO: `platformio run -t test-marlin` - - Using Make: `make unit-test-all-local` - - Using Docker + make: `maker unit-test-all-local-docker` - - To run a single unit test suite: - - Using PIO: `platformio run -t marlin_` - - Using make: `make unit-test-single-local TEST_TARGET=` - - Using Docker + make: `maker unit-test-single-local-docker TEST_TARGET=` -- If your feature can be unit tested, add one or more unit tests. For more information see our documentation on [Unit Tests](test). - ## Contributors Marlin is constantly improving thanks to a huge number of contributors from all over the world bringing their specialties and talents. Huge thanks are due to [all the contributors](https://github.com/MarlinFirmware/Marlin/graphs/contributors) who regularly patch up bugs, help direct traffic, and basically keep Marlin from falling apart. Marlin's continued existence would not be possible without them. -## Project Leadership +## Administration -Name|Role|Link|Donate -----|----|----|---- -๐Ÿ‡บ๐Ÿ‡ธ Scott Lahteine|Project Lead|[[@thinkyhead](https://github.com/thinkyhead)]|[๐Ÿ’ธ Donate](https://www.thinkyhead.com/donate-to-marlin) -๐Ÿ‡บ๐Ÿ‡ธ Roxanne Neufeld|Admin|[[@Roxy-3D](https://github.com/Roxy-3D)]| -๐Ÿ‡บ๐Ÿ‡ธ Keith Bennett|Admin|[[@thisiskeithb](https://github.com/thisiskeithb)]|[๐Ÿ’ธ Donate](https://github.com/sponsors/thisiskeithb) -๐Ÿ‡บ๐Ÿ‡ธ Jason Smith|Admin|[[@sjasonsmith](https://github.com/sjasonsmith)]| -๐Ÿ‡ง๐Ÿ‡ท Victor Oliveira|Admin|[[@rhapsodyv](https://github.com/rhapsodyv)]| -๐Ÿ‡ฌ๐Ÿ‡ง Chris Pepper|Admin|[[@p3p](https://github.com/p3p)]| -๐Ÿ‡ณ๐Ÿ‡ฟ Peter Ellens|Admin|[[@ellensp](https://github.com/ellensp)]|[๐Ÿ’ธ Donate](https://ko-fi.com/ellensp) -๐Ÿ‡บ๐Ÿ‡ธ Bob Kuhn|Admin|[[@Bob-the-Kuhn](https://github.com/Bob-the-Kuhn)]| -๐Ÿ‡ณ๐Ÿ‡ฑ Erik van der Zalm|Founder|[[@ErikZalm](https://github.com/ErikZalm)]|[๐Ÿ’ธ Donate](https://flattr.com/submit/auto?user_id=ErikZalm&url=https://github.com/MarlinFirmware/Marlin&title=Marlin&language=&tags=github&category=software) +Regular users can open and close their own issues, but only the administrators can do project-related things like add labels, merge changes, set milestones, and kick trolls. The current Marlin admin team consists of: + + + + +
Project Maintainer
+ + ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Scott Lahteine** + โ€…โ€…โ€…โ€…โ€…โ€…[@thinkyhead](https://github.com/thinkyhead) + โ€…โ€…โ€…โ€…โ€…โ€…[โ€…โ€…Donate ๐Ÿ’ธโ€…โ€…](https://www.thinkyhead.com/donate-to-marlin) + + + + ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Roxanne Neufeld** + โ€…โ€…โ€…โ€…โ€…โ€…[@Roxy-3D](https://github.com/Roxy-3D) + + ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Keith Bennett** + โ€…โ€…โ€…โ€…โ€…โ€…[@thisiskeithb](https://github.com/thisiskeithb) + โ€…โ€…โ€…โ€…โ€…โ€…[โ€…โ€…Donate ๐Ÿ’ธโ€…โ€…](https://github.com/sponsors/thisiskeithb) + + ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Jason Smith** + โ€…โ€…โ€…โ€…โ€…โ€…[@sjasonsmith](https://github.com/sjasonsmith) + + + + ๐Ÿ‡ง๐Ÿ‡ทโ€…โ€…**Victor Oliveira** + โ€…โ€…โ€…โ€…โ€…โ€…[@rhapsodyv](https://github.com/rhapsodyv) + + ๐Ÿ‡ฌ๐Ÿ‡งโ€…โ€…**Chris Pepper** + โ€…โ€…โ€…โ€…โ€…โ€…[@p3p](https://github.com/p3p) + +๐Ÿ‡ณ๐Ÿ‡ฟโ€…โ€…**Peter Ellens** + โ€…โ€…โ€…โ€…โ€…โ€…[@ellensp](https://github.com/ellensp) + โ€…โ€…โ€…โ€…โ€…โ€…[โ€…โ€…Donate ๐Ÿ’ธโ€…โ€…](https://ko-fi.com/ellensp) + + + + ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Bob Kuhn** + โ€…โ€…โ€…โ€…โ€…โ€…[@Bob-the-Kuhn](https://github.com/Bob-the-Kuhn) + + ๐Ÿ‡ณ๐Ÿ‡ฑโ€…โ€…**Erik van der Zalm** + โ€…โ€…โ€…โ€…โ€…โ€…[@ErikZalm](https://github.com/ErikZalm) + +
## 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. + +While we can't prevent the use of this code in products (3D printers, CNC, etc.) that are closed source or crippled by a patent, we would prefer that you choose another firmware or, better yet, make your own. From 19684f23bc9b4bdf1f38ff353f8b3546789b07f7 Mon Sep 17 00:00:00 2001 From: Jason Smith Date: Sat, 13 Apr 2024 17:49:08 -0700 Subject: [PATCH 17/22] =?UTF-8?q?=E2=9C=85=20Add=20unit=20tests=20for=20ma?= =?UTF-8?q?cros.h=20(#26968)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/tests/core/test_macros.cpp | 1215 +++++++++++++++++++++++++++++ 1 file changed, 1215 insertions(+) create mode 100644 Marlin/tests/core/test_macros.cpp diff --git a/Marlin/tests/core/test_macros.cpp b/Marlin/tests/core/test_macros.cpp new file mode 100644 index 0000000000..2353342928 --- /dev/null +++ b/Marlin/tests/core/test_macros.cpp @@ -0,0 +1,1215 @@ +/** + * 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 . + * + */ + +#include "../test/unit_tests.h" +#include + +// These represent enabled and disabled configuration options for testing. +// They will be used by multiple tests. +#define OPTION_ENABLED 1 +#define OPTION_DISABLED 0 + +MARLIN_TEST(macros_bitwise_8, TEST) { + uint8_t odd_set = 0xAA; + uint8_t even_set = 0x55; + for (uint8_t b = 0; b < 8; ++b) { + TEST_ASSERT_EQUAL((b % 2) != 0, TEST(odd_set, b)); + TEST_ASSERT_EQUAL((b % 2) == 0, TEST(even_set, b)); + } +} + +MARLIN_TEST(macros_bitwise_8, SET_BIT_TO) { + uint8_t n = 0x00; + + // Test LSB + SET_BIT_TO(n, 0, true); + TEST_ASSERT_EQUAL(0x01, n); + SET_BIT_TO(n, 0, false); + TEST_ASSERT_EQUAL(0x00, n); + + // Test MSB + SET_BIT_TO(n, 7, true); + TEST_ASSERT_EQUAL(0x80, n); + SET_BIT_TO(n, 7, false); + TEST_ASSERT_EQUAL(0x00, n); + + // Test a bit in the middle + SET_BIT_TO(n, 3, true); + TEST_ASSERT_EQUAL(0x08, n); + SET_BIT_TO(n, 3, false); + TEST_ASSERT_EQUAL(0x00, n); +} + +MARLIN_TEST(macros_bitwise_8, SBI) { + uint8_t n; + + // Test LSB + n = 0x00; + SBI(n, 0); + TEST_ASSERT_EQUAL(0x01, n); + + // Test MSB + n = 0x00; + SBI(n, 7); + TEST_ASSERT_EQUAL(0x80, n); + + // Test a bit in the middle + n = 0x00; + SBI(n, 3); + TEST_ASSERT_EQUAL(0x08, n); +} + +MARLIN_TEST(macros_bitwise_8, CBI) { + uint8_t n; + + // Test LSB + n = 0xFF; + CBI(n, 0); + TEST_ASSERT_EQUAL(0xFE, n); + + // Test MSB + n = 0xFF; + CBI(n, 7); + TEST_ASSERT_EQUAL(0x7F, n); + + // Test a bit in the middle + n = 0xFF; + CBI(n, 3); + TEST_ASSERT_EQUAL(0xF7, n); +} + +MARLIN_TEST(macros_bitwise_8, TBI) { + uint8_t n; + + // Test LSB + n = 0xAA; + TBI(n, 0); + TEST_ASSERT_EQUAL(0xAB, n); + + // Test MSB + n = 0xAA; + TBI(n, 7); + TEST_ASSERT_EQUAL(0x2A, n); + + // Test a bit in the middle + n = 0xAA; + TBI(n, 3); + TEST_ASSERT_EQUAL(0xA2, n); +} + +// 32-bit BIT operation tests +// These verify the above macros, but specifically with the MSB of a uint32_t. +// This ensures that the macros are not limited to 8-bit operations. + +MARLIN_TEST(macros_bitwise_32, TEST_32bit) { + uint32_t odd_set = 0x80000000; + uint32_t even_set = 0x00000000; + TEST_ASSERT_EQUAL(true, TEST(odd_set, 31)); + TEST_ASSERT_EQUAL(false, TEST(even_set, 31)); +} + +MARLIN_TEST(macros_bitwise_32, SET_BIT_TO_32bit) { + uint32_t n = 0x00000000; + + // Test MSB + SET_BIT_TO(n, 31, true); + TEST_ASSERT_EQUAL(0x80000000, n); + SET_BIT_TO(n, 31, false); + TEST_ASSERT_EQUAL(0x00000000, n); +} + +MARLIN_TEST(macros_bitwise_32, SBI_32bit) { + uint32_t n = 0x00000000; + + // Test MSB + SBI(n, 31); + TEST_ASSERT_EQUAL(0x80000000, n); +} + +MARLIN_TEST(macros_bitwise_32, CBI_32bit) { + uint32_t n = 0xFFFFFFFF; + + // Test MSB + CBI(n, 31); + TEST_ASSERT_EQUAL(0x7FFFFFFF, n); +} + +MARLIN_TEST(macros_bitwise_32, TBI_32bit) { + uint32_t n = 0x7FFFFFFF; + + // Test MSB + TBI(n, 31); + TEST_ASSERT_EQUAL(0xFFFFFFFF, n); +} + +// Geometry macros +MARLIN_TEST(macros_geometry, cu_int) { + TEST_ASSERT_EQUAL(8, cu(2)); + TEST_ASSERT_EQUAL(27, cu(3)); +} + +MARLIN_TEST(macros_geometry, cu_float) { + TEST_ASSERT_FLOAT_WITHIN(0.001f, 8.615f, cu(2.05f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 28.094f, cu(3.04f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 13.998f, cu(2.41f)); +} + +MARLIN_TEST(macros_geometry, RADIANS) { + TEST_ASSERT_FLOAT_WITHIN(0.001f, float(M_PI), RADIANS(180.0f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 0.0f, RADIANS(0.0f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, float(M_PI) / 4, RADIANS(45.0f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, float(M_PI) / 2, RADIANS(90.0f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 3 * float(M_PI) / 2, RADIANS(270.0f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 4 * float(M_PI), RADIANS(720.0f)); +} + +MARLIN_TEST(macros_geometry, DEGREES) { + TEST_ASSERT_FLOAT_WITHIN(0.001f, 180.0f, DEGREES(float(M_PI))); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 0.0f, DEGREES(0.0f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 45.0f, DEGREES(float(M_PI) / 4)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 90.0f, DEGREES(float(M_PI) / 2)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 270.0f, DEGREES(3 * float(M_PI) / 2)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 720.0f, DEGREES(4 * float(M_PI))); +} + +MARLIN_TEST(macros_geometry, HYPOT2) { + TEST_ASSERT_EQUAL(25, HYPOT2(3, 4)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 13.0f, HYPOT2(2.0f, 3.0f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 18.72f, HYPOT2(2.4f, 3.6f)); +} + +MARLIN_TEST(macros_geometry, NORMSQ) { + TEST_ASSERT_EQUAL(14, NORMSQ(1, 2, 3)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 14.0f, NORMSQ(1.0f, 2.0f, 3.0f)); + TEST_ASSERT_FLOAT_WITHIN(0.001f, 20.16f, NORMSQ(1.2f, 2.4f, 3.6f)); +} + +MARLIN_TEST(macros_geometry, CIRCLE_AREA) { + TEST_ASSERT_EQUAL(float(M_PI) * 4, CIRCLE_AREA(2)); +} + +MARLIN_TEST(macros_geometry, CIRCLE_CIRC) { + TEST_ASSERT_EQUAL(2 * float(M_PI) * 3, CIRCLE_CIRC(3)); +} + +MARLIN_TEST(macros_numeric, SIGN) { + TEST_ASSERT_EQUAL(1, SIGN(100)); + TEST_ASSERT_EQUAL(-1, SIGN(-100)); + TEST_ASSERT_EQUAL(0, SIGN(0)); +} + +MARLIN_TEST(macros_numeric, IS_POWER_OF_2) { + TEST_ASSERT_EQUAL(false, IS_POWER_OF_2(0)); + TEST_ASSERT_EQUAL(true, IS_POWER_OF_2(1)); + TEST_ASSERT_EQUAL(true, IS_POWER_OF_2(4)); + TEST_ASSERT_EQUAL(false, IS_POWER_OF_2(5)); + TEST_ASSERT_EQUAL(false, IS_POWER_OF_2(0x80000001)); + TEST_ASSERT_EQUAL(true, IS_POWER_OF_2(0x80000000)); +} + +// Numeric constraints +MARLIN_TEST(macros_numeric, NOLESS_int) { + // Scenario 1: Input was already acceptable + int a = 8; + NOLESS(a, 5); + TEST_ASSERT_EQUAL(8, a); + + // Original scenario: Input was less than the limit + a = 5; + NOLESS(a, 10); + TEST_ASSERT_EQUAL(10, a); + + // Scenario 2: Input is negative, and coerces to a positive number + a = -5; + NOLESS(a, 0); + TEST_ASSERT_EQUAL(0, a); + + // Scenario 3: Input is negative, and coerces to another negative number + a = -10; + NOLESS(a, -5); + TEST_ASSERT_EQUAL(-5, a); +} + +MARLIN_TEST(macros_numeric, NOLESS_uint) { + // Scenario 1: Input was already acceptable + unsigned int b = 8u; + NOLESS(b, 5u); + TEST_ASSERT_EQUAL(8u, b); + + // Original scenario: Input was less than the limit + b = 5u; + NOLESS(b, 10u); + TEST_ASSERT_EQUAL(10u, b); +} + +MARLIN_TEST(macros_numeric, NOLESS_float) { + // Scenario 1: Input was already acceptable + float c = 8.5f; + NOLESS(c, 5.5f); + TEST_ASSERT_EQUAL_FLOAT(8.5f, c); + + // Original scenario: Input was less than the limit + c = 5.5f; + NOLESS(c, 10.5f); + TEST_ASSERT_EQUAL_FLOAT(10.5f, c); + + // Scenario 2: Input is negative, and coerces to a positive number + c = -5.5f; + NOLESS(c, 5.0f); + TEST_ASSERT_EQUAL_FLOAT(5.0f, c); + + // Scenario 3: Input is negative, and coerces to another negative number + c = -10.5f; + NOLESS(c, -5.5f); + TEST_ASSERT_EQUAL_FLOAT(-5.5f, c); + c = -5.5f; + NOLESS(c, -10.5f); + TEST_ASSERT_EQUAL_FLOAT(-5.5f, c); +} + +MARLIN_TEST(macros_numeric, NOMORE_int) { + // Scenario 1: Input was already acceptable + int a = 8; + NOMORE(a, 10); + TEST_ASSERT_EQUAL(8, a); + + // Original scenario: Input was more than the limit + a = 15; + NOMORE(a, 10); + TEST_ASSERT_EQUAL(10, a); + + // Scenario 2: Input is positive, and coerces to a negative number + a = 5; + NOMORE(a, -2); + TEST_ASSERT_EQUAL(-2, a); + + // Scenario 3: Input is negative, and coerces to another negative number + a = -5; + NOMORE(a, -10); + TEST_ASSERT_EQUAL(-10, a); +} + +MARLIN_TEST(macros_numeric, NOMORE_uint) { + // Scenario 1: Input was already acceptable + unsigned int b = 8u; + NOMORE(b, 10u); + TEST_ASSERT_EQUAL(8u, b); + + // Original scenario: Input was more than the limit + b = 15u; + NOMORE(b, 10u); + TEST_ASSERT_EQUAL(10u, b); +} + +MARLIN_TEST(macros_numeric, NOMORE_float) { + // Scenario 1: Input was already acceptable + float c = 8.5f; + NOMORE(c, 10.5f); + TEST_ASSERT_EQUAL_FLOAT(8.5f, c); + + // Original scenario: Input was more than the limit + c = 15.5f; + NOMORE(c, 10.5f); + TEST_ASSERT_EQUAL_FLOAT(10.5f, c); + + // Scenario 2: Input is positive, and coerces to a negative number + c = 5.5f; + NOMORE(c, -1.7f); + TEST_ASSERT_EQUAL_FLOAT(-1.7f, c); + + // Scenario 3: Input is negative, and coerces to another negative number + c = -5.5f; + NOMORE(c, -10.5f); + TEST_ASSERT_EQUAL_FLOAT(-10.5f, c); +} + +MARLIN_TEST(macros_numeric, LIMIT_int) { + int a = 15; + LIMIT(a, 10, 20); + TEST_ASSERT_EQUAL(15, a); + + a = 5; + LIMIT(a, 10, 20); + TEST_ASSERT_EQUAL(10, a); + + a = 25; + LIMIT(a, 10, 20); + TEST_ASSERT_EQUAL(20, a); + + // Scenario: Range is [-10, -5] + a = -8; + LIMIT(a, -10, -5); + TEST_ASSERT_EQUAL(-8, a); + + a = -12; + LIMIT(a, -10, -5); + TEST_ASSERT_EQUAL(-10, a); + + a = -3; + LIMIT(a, -10, -5); + TEST_ASSERT_EQUAL(-5, a); + + // Scenario: Range is [-10, 5] + a = 0; + LIMIT(a, -10, 5); + TEST_ASSERT_EQUAL(0, a); + + a = -12; + LIMIT(a, -10, 5); + TEST_ASSERT_EQUAL(-10, a); + + a = 6; + LIMIT(a, -10, 5); + TEST_ASSERT_EQUAL(5, a); +} + +MARLIN_TEST(macros_numeric, LIMIT_uint) { + unsigned int b = 15u; + LIMIT(b, 10u, 20u); + TEST_ASSERT_EQUAL(15u, b); + + b = 5u; + LIMIT(b, 10u, 20u); + TEST_ASSERT_EQUAL(10u, b); + + b = 25u; + LIMIT(b, 10u, 20u); + TEST_ASSERT_EQUAL(20u, b); +} + +MARLIN_TEST(macros_numeric, LIMIT_float) { + float c = 15.5f; + LIMIT(c, 10.5f, 20.5f); + TEST_ASSERT_EQUAL_FLOAT(15.5f, c); + + c = 5.5f; + LIMIT(c, 10.5f, 20.5f); + TEST_ASSERT_EQUAL_FLOAT(10.5f, c); + + c = 25.5f; + LIMIT(c, 10.5f, 20.5f); + TEST_ASSERT_EQUAL_FLOAT(20.5f, c); + + // Scenario: Range is [-10.5, -5.5] + c = -8.5f; + LIMIT(c, -10.5f, -5.5f); + TEST_ASSERT_EQUAL_FLOAT(-8.5f, c); + + c = -12.5f; + LIMIT(c, -10.5f, -5.5f); + TEST_ASSERT_EQUAL_FLOAT(-10.5f, c); + + c = -3.5f; + LIMIT(c, -10.5f, -5.5f); + TEST_ASSERT_EQUAL_FLOAT(-5.5f, c); + + // Scenario: Range is [-10.5, 5.5] + c = 0.0f; + LIMIT(c, -10.5f, 5.5f); + TEST_ASSERT_EQUAL_FLOAT(0.0f, c); + + c = -12.5f; + LIMIT(c, -10.5f, 5.5f); + TEST_ASSERT_EQUAL_FLOAT(-10.5f, c); + + c = 6.5f; + LIMIT(c, -10.5f, 5.5f); + TEST_ASSERT_EQUAL_FLOAT(5.5f, c); +} + + +// Looping macros +MARLIN_TEST(macros_looping, DO_macro) { + #define _M_1(A) (A) + int sum = DO(M, +, 1, 2, 3, 4, 5); + TEST_ASSERT_EQUAL(15, sum); + + // Test with maximum number of arguments + sum = DO(M, +, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40); + TEST_ASSERT_EQUAL(820, sum); + #undef _M_1 +} + +// Configuration Options +MARLIN_TEST(macros_options, ENABLED_DISABLED) { + #define OPTION_A + #define OPTION_B 1 + #define OPTION_C true + #define OPTION_D 0 + #define OPTION_E false + // #define OPTION_F + + // Test ENABLED macro + TEST_ASSERT_TRUE(ENABLED(OPTION_A)); + TEST_ASSERT_TRUE(ENABLED(OPTION_B)); + TEST_ASSERT_TRUE(ENABLED(OPTION_C)); + TEST_ASSERT_FALSE(ENABLED(OPTION_D)); + TEST_ASSERT_FALSE(ENABLED(OPTION_E)); + TEST_ASSERT_FALSE(ENABLED(OPTION_F)); + + // Test DISABLED macro + TEST_ASSERT_FALSE(DISABLED(OPTION_A)); + TEST_ASSERT_FALSE(DISABLED(OPTION_B)); + TEST_ASSERT_FALSE(DISABLED(OPTION_C)); + TEST_ASSERT_TRUE(DISABLED(OPTION_D)); + TEST_ASSERT_TRUE(DISABLED(OPTION_E)); + TEST_ASSERT_TRUE(DISABLED(OPTION_F)); + + #undef OPTION_A + #undef OPTION_B + #undef OPTION_C + #undef OPTION_D + #undef OPTION_E +} + +MARLIN_TEST(macros_options, ANY) { + TEST_ASSERT_TRUE(ANY(OPTION_DISABLED, OPTION_ENABLED, OPTION_DISABLED)); // Enabled option in the middle + TEST_ASSERT_TRUE(ANY(OPTION_ENABLED, OPTION_DISABLED, OPTION_DISABLED)); // Enabled option at the beginning + TEST_ASSERT_TRUE(ANY(OPTION_DISABLED, OPTION_DISABLED, OPTION_ENABLED)); // Enabled option at the end + TEST_ASSERT_FALSE(ANY(OPTION_DISABLED, OPTION_DISABLED, OPTION_DISABLED)); // All options disabled +} + +MARLIN_TEST(macros_options, ALL) { + TEST_ASSERT_TRUE(ALL(OPTION_ENABLED, OPTION_ENABLED, OPTION_ENABLED)); // All options enabled + TEST_ASSERT_FALSE(ALL(OPTION_ENABLED, OPTION_DISABLED, OPTION_ENABLED)); // Disabled option in the middle + TEST_ASSERT_FALSE(ALL(OPTION_DISABLED, OPTION_ENABLED, OPTION_ENABLED)); // Disabled option at the beginning + TEST_ASSERT_FALSE(ALL(OPTION_ENABLED, OPTION_ENABLED, OPTION_DISABLED)); // Disabled option at the end + TEST_ASSERT_FALSE(ALL(OPTION_DISABLED, OPTION_DISABLED, OPTION_DISABLED)); // All options disabled +} + +MARLIN_TEST(macros_options, NONE) { + TEST_ASSERT_FALSE(NONE(OPTION_ENABLED, OPTION_ENABLED, OPTION_ENABLED)); // All options enabled + TEST_ASSERT_FALSE(NONE(OPTION_ENABLED, OPTION_DISABLED, OPTION_ENABLED)); // Disabled option in the middle + TEST_ASSERT_FALSE(NONE(OPTION_DISABLED, OPTION_ENABLED, OPTION_ENABLED)); // Disabled option at the beginning + TEST_ASSERT_FALSE(NONE(OPTION_ENABLED, OPTION_ENABLED, OPTION_DISABLED)); // Disabled option at the end + TEST_ASSERT_TRUE(NONE(OPTION_DISABLED, OPTION_DISABLED, OPTION_DISABLED)); // All options disabled +} + +MARLIN_TEST(macros_options, COUNT_ENABLED) { + TEST_ASSERT_EQUAL(3, COUNT_ENABLED(OPTION_ENABLED, OPTION_ENABLED, OPTION_ENABLED)); // All options enabled + TEST_ASSERT_EQUAL(2, COUNT_ENABLED(OPTION_ENABLED, OPTION_DISABLED, OPTION_ENABLED)); // Disabled option in the middle + TEST_ASSERT_EQUAL(2, COUNT_ENABLED(OPTION_DISABLED, OPTION_ENABLED, OPTION_ENABLED)); // Disabled option at the beginning + TEST_ASSERT_EQUAL(2, COUNT_ENABLED(OPTION_ENABLED, OPTION_ENABLED, OPTION_DISABLED)); // Disabled option at the end + TEST_ASSERT_EQUAL(0, COUNT_ENABLED(OPTION_DISABLED, OPTION_DISABLED, OPTION_DISABLED)); // All options disabled +} + +MARLIN_TEST(macros_options, MANY) { + TEST_ASSERT_FALSE(MANY(OPTION_ENABLED, OPTION_DISABLED, OPTION_DISABLED)); // Only one option enabled + TEST_ASSERT_TRUE(MANY(OPTION_ENABLED, OPTION_ENABLED, OPTION_DISABLED)); // Two options enabled + TEST_ASSERT_TRUE(MANY(OPTION_ENABLED, OPTION_ENABLED, OPTION_ENABLED)); // All options enabled + TEST_ASSERT_FALSE(MANY(OPTION_DISABLED, OPTION_DISABLED, OPTION_DISABLED)); // No options enabled +} + + +// Ternary macros +MARLIN_TEST(macros_options, TERN) { + TEST_ASSERT_EQUAL(1, TERN(OPTION_ENABLED, 1, 0)); // OPTION_ENABLED is enabled, so it should return '1' + TEST_ASSERT_EQUAL(0, TERN(OPTION_DISABLED, 1, 0)); // OPTION_DISABLED is disabled, so it should return '0' +} + +MARLIN_TEST(macros_options, TERN0) { + TEST_ASSERT_EQUAL(1, TERN0(OPTION_ENABLED, 1)); // OPTION_ENABLED is enabled, so it should return '1' + TEST_ASSERT_EQUAL(0, TERN0(OPTION_DISABLED, 1)); // OPTION_DISABLED is disabled, so it should return '0' +} + +MARLIN_TEST(macros_options, TERN1) { + TEST_ASSERT_EQUAL(0, TERN1(OPTION_ENABLED, 0)); // OPTION_ENABLED is enabled, so it should return '0' + TEST_ASSERT_EQUAL(1, TERN1(OPTION_DISABLED, 0)); // OPTION_DISABLED is disabled, so it should return '1' +} + +MARLIN_TEST(macros_options, TERN_) { + TEST_ASSERT_EQUAL(-1, TERN_(OPTION_ENABLED, -)1); // OPTION_ENABLED is enabled, so it should return '1' + TEST_ASSERT_EQUAL(1, TERN_(OPTION_DISABLED, -)1); // OPTION_DISABLED is disabled, so it should return nothing +} + +MARLIN_TEST(macros_options, IF_DISABLED) { + TEST_ASSERT_EQUAL(1, IF_DISABLED(OPTION_ENABLED, -)1); // OPTION_ENABLED is enabled, so it should return nothing + TEST_ASSERT_EQUAL(-1, IF_DISABLED(OPTION_DISABLED, -)1); // OPTION_DISABLED is disabled, so it should return '1' +} + +MARLIN_TEST(macros_options, OPTITEM) { + int enabledArray[] = {OPTITEM(OPTION_ENABLED, 1, 2)}; + int disabledArray[] = {OPTITEM(OPTION_DISABLED, 1, 2)}; + TEST_ASSERT_EQUAL(2, sizeof(enabledArray) / sizeof(int)); // OPTION_ENABLED is enabled, so it should return an array of size 2 + TEST_ASSERT_EQUAL(0, sizeof(disabledArray) / sizeof(int)); // OPTION_DISABLED is disabled, so it should return an array of size 0 +} + +MARLIN_TEST(macros_options, OPTARG) { + int enabledArgs[] = {0 OPTARG(OPTION_ENABLED, 1, 2)}; + int disabledArgs[] = {0 OPTARG(OPTION_DISABLED, 1, 2)}; + + int sumEnabledArgs = 0; + for (const auto& arg : enabledArgs) { + sumEnabledArgs += arg; + } + + int sumDisabledArgs = 0; + for (const auto& arg : disabledArgs) { + sumDisabledArgs += arg; + } + + TEST_ASSERT_EQUAL(3, sumEnabledArgs); // OPTION_ENABLED is enabled, so it should return 3 + TEST_ASSERT_EQUAL(0, sumDisabledArgs); // OPTION_DISABLED is disabled, so it should return 0 +} + +MARLIN_TEST(macros_options, OPTCODE) { + int enabledCode = 0; OPTCODE(OPTION_ENABLED, enabledCode = 1); + int disabledCode = 0; OPTCODE(OPTION_DISABLED, disabledCode = 1); + TEST_ASSERT_EQUAL(1, enabledCode); // OPTION_ENABLED is enabled, so it should return 1 + TEST_ASSERT_EQUAL(0, disabledCode); // OPTION_DISABLED is disabled, so it should return 0 +} + +MARLIN_TEST(macros_optional_math, PLUS_TERN0) { + int enabledPlus = 5 PLUS_TERN0(OPTION_ENABLED, 2); + int disabledPlus = 5 PLUS_TERN0(OPTION_DISABLED, 2); + TEST_ASSERT_EQUAL(7, enabledPlus); // OPTION_ENABLED is enabled, so it should return 7 + TEST_ASSERT_EQUAL(5, disabledPlus); // OPTION_DISABLED is disabled, so it should return 5 +} + +MARLIN_TEST(macros_optional_math, MINUS_TERN0) { + int enabledMinus = 5 MINUS_TERN0(OPTION_ENABLED, 2); + int disabledMinus = 5 MINUS_TERN0(OPTION_DISABLED, 2); + TEST_ASSERT_EQUAL(3, enabledMinus); // OPTION_ENABLED is enabled, so it should return 3 + TEST_ASSERT_EQUAL(5, disabledMinus); // OPTION_DISABLED is disabled, so it should return 5 +} + +MARLIN_TEST(macros_optional_math, MUL_TERN1) { + int enabledMul = 5 MUL_TERN1(OPTION_ENABLED, 2); + int disabledMul = 5 MUL_TERN1(OPTION_DISABLED, 2); + TEST_ASSERT_EQUAL(10, enabledMul); // OPTION_ENABLED is enabled, so it should return 10 + TEST_ASSERT_EQUAL(5, disabledMul); // OPTION_DISABLED is disabled, so it should return 5 +} + +MARLIN_TEST(macros_optional_math, DIV_TERN1) { + int enabledDiv = 10 DIV_TERN1(OPTION_ENABLED, 2); + int disabledDiv = 10 DIV_TERN1(OPTION_DISABLED, 2); + TEST_ASSERT_EQUAL(5, enabledDiv); // OPTION_ENABLED is enabled, so it should return 5 + TEST_ASSERT_EQUAL(10, disabledDiv); // OPTION_DISABLED is disabled, so it should return 10 +} + +MARLIN_TEST(macros_optional_math, SUM_TERN) { + int enabledSum = SUM_TERN(OPTION_ENABLED, 5, 2); + int disabledSum = SUM_TERN(OPTION_DISABLED, 5, 2); + TEST_ASSERT_EQUAL(7, enabledSum); // OPTION_ENABLED is enabled, so it should return 7 + TEST_ASSERT_EQUAL(5, disabledSum); // OPTION_DISABLED is disabled, so it should return 5 +} + +MARLIN_TEST(macros_optional_math, DIFF_TERN) { + int enabledDiff = DIFF_TERN(OPTION_ENABLED, 5, 2); + int disabledDiff = DIFF_TERN(OPTION_DISABLED, 5, 2); + TEST_ASSERT_EQUAL(3, enabledDiff); // OPTION_ENABLED is enabled, so it should return 3 + TEST_ASSERT_EQUAL(5, disabledDiff); // OPTION_DISABLED is disabled, so it should return 5 +} + +MARLIN_TEST(macros_optional_math, MUL_TERN) { + int enabledMul = MUL_TERN(OPTION_ENABLED, 5, 2); + int disabledMul = MUL_TERN(OPTION_DISABLED, 5, 2); + TEST_ASSERT_EQUAL(10, enabledMul); // OPTION_ENABLED is enabled, so it should return 10 + TEST_ASSERT_EQUAL(5, disabledMul); // OPTION_DISABLED is disabled, so it should return 5 +} + +MARLIN_TEST(macros_optional_math, DIV_TERN) { + int enabledDiv = DIV_TERN(OPTION_ENABLED, 10, 2); + int disabledDiv = DIV_TERN(OPTION_DISABLED, 10, 2); + TEST_ASSERT_EQUAL(5, enabledDiv); // OPTION_ENABLED is enabled, so it should return 5 + TEST_ASSERT_EQUAL(10, disabledDiv); // OPTION_DISABLED is disabled, so it should return 10 +} + +// Mock pin definitions +#define PIN1_PIN 1 +#define PIN2_PIN 2 +#define PIN3_PIN -1 + +MARLIN_TEST(macros_pins, PIN_EXISTS) { + // Test PIN_EXISTS macro + int pin1_exists, pin2_exists, pin3_exists, pin4_exists; + + #if PIN_EXISTS(PIN1) + pin1_exists = 1; + #else + pin1_exists = 0; + #endif + + #if PIN_EXISTS(PIN2) + pin2_exists = 1; + #else + pin2_exists = 0; + #endif + + #if PIN_EXISTS(PIN3) + pin3_exists = 1; + #else + pin3_exists = 0; + #endif + + #if PIN_EXISTS(PIN4) + pin4_exists = 1; + #else + pin4_exists = 0; + #endif + + TEST_ASSERT_TRUE(pin1_exists); + TEST_ASSERT_TRUE(pin2_exists); + TEST_ASSERT_FALSE(pin3_exists); + TEST_ASSERT_FALSE(pin4_exists); +} + +MARLIN_TEST(macros_pins, PINS_EXIST) { + // Test PINS_EXIST macro + int pins1_2_exist, pins1_3_exist; + + #if PINS_EXIST(PIN1, PIN2) + pins1_2_exist = 1; + #else + pins1_2_exist = 0; + #endif + + #if PINS_EXIST(PIN1, PIN3) + pins1_3_exist = 1; + #else + pins1_3_exist = 0; + #endif + + TEST_ASSERT_TRUE(pins1_2_exist); + TEST_ASSERT_FALSE(pins1_3_exist); +} + +MARLIN_TEST(macros_pins, ANY_PIN) { + // Test ANY_PIN macro + int any_pin1_3, any_pin3_4; + + #if ANY_PIN(PIN1, PIN3) + any_pin1_3 = 1; + #else + any_pin1_3 = 0; + #endif + + #if ANY_PIN(PIN3, PIN4) + any_pin3_4 = 1; + #else + any_pin3_4 = 0; + #endif + + TEST_ASSERT_TRUE(any_pin1_3); + TEST_ASSERT_FALSE(any_pin3_4); +} + +// Undefine mock pin definitions +#undef PIN1_PIN +#undef PIN2_PIN +#undef PIN3_PIN + + +// Mock button definitions +#define BTN_BUTTON1 1 +#define BTN_BUTTON2 2 +#define BTN_BUTTON3 -1 + +MARLIN_TEST(macros_buttons, BUTTON_EXISTS) { + // Test BUTTON_EXISTS macro + int button1_exists, button2_exists, button3_exists, button4_exists; + + #if BUTTON_EXISTS(BUTTON1) + button1_exists = 1; + #else + button1_exists = 0; + #endif + + #if BUTTON_EXISTS(BUTTON2) + button2_exists = 1; + #else + button2_exists = 0; + #endif + + #if BUTTON_EXISTS(BUTTON3) + button3_exists = 1; + #else + button3_exists = 0; + #endif + + #if BUTTON_EXISTS(BUTTON4) + button4_exists = 1; + #else + button4_exists = 0; + #endif + + TEST_ASSERT_TRUE(button1_exists); + TEST_ASSERT_TRUE(button2_exists); + TEST_ASSERT_FALSE(button3_exists); + TEST_ASSERT_FALSE(button4_exists); +} + +MARLIN_TEST(macros_buttons, BUTTONS_EXIST) { + // Test BUTTONS_EXIST macro + int buttons1_2_exist, buttons1_3_exist; + + #if BUTTONS_EXIST(BUTTON1, BUTTON2) + buttons1_2_exist = 1; + #else + buttons1_2_exist = 0; + #endif + + #if BUTTONS_EXIST(BUTTON1, BUTTON3) + buttons1_3_exist = 1; + #else + buttons1_3_exist = 0; + #endif + + TEST_ASSERT_TRUE(buttons1_2_exist); + TEST_ASSERT_FALSE(buttons1_3_exist); +} + +MARLIN_TEST(macros_buttons, ANY_BUTTON) { + // Test ANY_BUTTON macro + int any_button1_3, any_button3_4; + + #if ANY_BUTTON(BUTTON1, BUTTON3) + any_button1_3 = 1; + #else + any_button1_3 = 0; + #endif + + #if ANY_BUTTON(BUTTON3, BUTTON4) + any_button3_4 = 1; + #else + any_button3_4 = 0; + #endif + + TEST_ASSERT_TRUE(any_button1_3); + TEST_ASSERT_FALSE(any_button3_4); +} + +// Undefine mock button definitions +#undef BTN_BUTTON1 +#undef BTN_BUTTON2 +#undef BTN_BUTTON3 + + +MARLIN_TEST(macros_value_functions, WITHIN) { + // Test WITHIN macro + TEST_ASSERT_TRUE(WITHIN(5, 1, 10)); // 5 is within 1 and 10 + TEST_ASSERT_TRUE(WITHIN(1, 1, 10)); // Edge case: 1 is the lower limit + TEST_ASSERT_TRUE(WITHIN(10, 1, 10)); // Edge case: 10 is the upper limit + TEST_ASSERT_FALSE(WITHIN(0, 1, 10)); // Edge case: 0 is just below the lower limit + TEST_ASSERT_FALSE(WITHIN(11, 1, 10)); // Edge case: 11 is just above the upper limit + TEST_ASSERT_FALSE(WITHIN(15, 1, 10)); // 15 is not within 1 and 10 +} + +MARLIN_TEST(macros_value_functions, ISEOL) { + // Test ISEOL macro + TEST_ASSERT_TRUE(ISEOL('\n')); // '\n' is an end-of-line character + TEST_ASSERT_TRUE(ISEOL('\r')); // '\r' is an end-of-line character + TEST_ASSERT_FALSE(ISEOL('a')); // 'a' is not an end-of-line character +} + +MARLIN_TEST(macros_value_functions, NUMERIC) { + // Test NUMERIC macro + TEST_ASSERT_TRUE(NUMERIC('0')); // Edge case: '0' is the lowest numeric character + TEST_ASSERT_TRUE(NUMERIC('5')); // '5' is a numeric character + TEST_ASSERT_TRUE(NUMERIC('9')); // Edge case: '9' is the highest numeric character + TEST_ASSERT_FALSE(NUMERIC('0' - 1)); // Edge case: '/' is just before '0' in ASCII + TEST_ASSERT_FALSE(NUMERIC('9' + 1)); // Edge case: ':' is just after '9' in ASCII + TEST_ASSERT_FALSE(NUMERIC('a')); // 'a' is not a numeric character +} + +MARLIN_TEST(macros_value_functions, DECIMAL) { + // Test DECIMAL macro + TEST_ASSERT_TRUE(DECIMAL('0')); // Edge case: '0' is the lowest numeric character + TEST_ASSERT_TRUE(DECIMAL('5')); // '5' is a numeric character + TEST_ASSERT_TRUE(DECIMAL('9')); // Edge case: '9' is the highest numeric character + TEST_ASSERT_TRUE(DECIMAL('.')); // '.' is a decimal character + TEST_ASSERT_FALSE(DECIMAL('0' - 1)); // Edge case: '/' is just before '0' in ASCII + TEST_ASSERT_FALSE(DECIMAL('9' + 1)); // Edge case: ':' is just after '9' in ASCII + TEST_ASSERT_FALSE(DECIMAL('-')); // '-' is not a decimal character, but can appear in numbers + TEST_ASSERT_FALSE(DECIMAL('+')); // '+' is not a decimal character, but can appear in numbers + TEST_ASSERT_FALSE(DECIMAL('e')); // 'e' is not a decimal character, but can appear in scientific notation +} + +MARLIN_TEST(macros_value_functions, HEXCHR) { + // Test HEXCHR macro + TEST_ASSERT_EQUAL(0, HEXCHR('0')); // Edge case: '0' is the lowest numeric character + TEST_ASSERT_EQUAL(9, HEXCHR('9')); // Edge case: '9' is the highest numeric character + TEST_ASSERT_EQUAL(10, HEXCHR('a')); // 'a' is a hex character with value 10 + TEST_ASSERT_EQUAL(10, HEXCHR('A')); // 'A' is a hex character with value 10 + TEST_ASSERT_EQUAL(15, HEXCHR('f')); // Edge case: 'f' is the highest lowercase hex character + TEST_ASSERT_EQUAL(15, HEXCHR('F')); // Edge case: 'F' is the highest uppercase hex character + TEST_ASSERT_EQUAL(-1, HEXCHR('g')); // 'g' is not a hex character +} + +MARLIN_TEST(macros_value_functions, NUMERIC_SIGNED) { + // Test NUMERIC_SIGNED macro + TEST_ASSERT_TRUE(NUMERIC_SIGNED('0')); // Edge case: '0' is the lowest numeric character + TEST_ASSERT_TRUE(NUMERIC_SIGNED('5')); // '5' is a numeric character + TEST_ASSERT_TRUE(NUMERIC_SIGNED('9')); // Edge case: '9' is the highest numeric character + TEST_ASSERT_TRUE(NUMERIC_SIGNED('-')); // '-' is not a numeric character, but can appear in signed numbers + TEST_ASSERT_TRUE(NUMERIC_SIGNED('+')); // '+' is not a numeric character, but can appear in signed numbers + TEST_ASSERT_FALSE(NUMERIC_SIGNED('.')); // '.' is not a numeric character + TEST_ASSERT_FALSE(NUMERIC_SIGNED('0' - 1)); // Edge case: '/' is just before '0' in ASCII + TEST_ASSERT_FALSE(NUMERIC_SIGNED('9' + 1)); // Edge case: ':' is just after '9' in ASCII + TEST_ASSERT_FALSE(NUMERIC_SIGNED('e')); // 'e' is not a numeric character, but can appear in scientific notation +} + +MARLIN_TEST(macros_value_functions, DECIMAL_SIGNED) { + // Test DECIMAL_SIGNED macro + TEST_ASSERT_TRUE(DECIMAL_SIGNED('0')); // Edge case: '0' is the lowest numeric character + TEST_ASSERT_TRUE(DECIMAL_SIGNED('5')); // '5' is a decimal character + TEST_ASSERT_TRUE(DECIMAL_SIGNED('9')); // Edge case: '9' is the highest numeric character + TEST_ASSERT_TRUE(DECIMAL_SIGNED('-')); // '-' is not a numeric character, but can appear in signed numbers + TEST_ASSERT_TRUE(DECIMAL_SIGNED('+')); // '+' is not a numeric character, but can appear in signed numbers + TEST_ASSERT_TRUE(DECIMAL_SIGNED('.')); // '.' is a decimal character + TEST_ASSERT_FALSE(DECIMAL_SIGNED('0' - 1)); // Edge case: '/' is just before '0' in ASCII + TEST_ASSERT_FALSE(DECIMAL_SIGNED('9' + 1)); // Edge case: ':' is just after '9' in ASCII + TEST_ASSERT_FALSE(DECIMAL_SIGNED('e')); // 'e' is not a decimal character, but can appear in scientific notation +} + +MARLIN_TEST(macros_array, COUNT) { + // Test COUNT macro + int array[10]; + TEST_ASSERT_EQUAL(10, COUNT(array)); // The array has 10 elements +} + +MARLIN_TEST(macros_array, ZERO) { + // Test ZERO macro + int array[5] = {1, 2, 3, 4, 5}; + ZERO(array); + for (auto& element : array) { + TEST_ASSERT_EQUAL(0, element); + } +} + +MARLIN_TEST(macros_array, COPY) { + int array1[5] = {1, 2, 3, 4, 5}; + int array2[5] = {0}; + COPY(array2, array1); + for (const auto& element : array1) { + TEST_ASSERT_EQUAL(element, array2[&element - &array1[0]]); // All elements should be equal + } +} + +MARLIN_TEST(macros_expansion, CODE_N) { + int a = 0; + CODE_N(0, a+=1, a+=2, a+=3, a+=4, a+=5, a+=6, a+=7, a+=8, a+=9, a+=10, a+=11, a+=12, a+=13, a+=14, a+=15, a+=16); + TEST_ASSERT_EQUAL(0, a); + + a = 0; + CODE_N(1, a+=1, a+=2, a+=3, a+=4, a+=5, a+=6, a+=7, a+=8, a+=9, a+=10, a+=11, a+=12, a+=13, a+=14, a+=15, a+=16); + TEST_ASSERT_EQUAL(1, a); + + a = 0; + CODE_N(2, a+=1, a+=2, a+=3, a+=4, a+=5, a+=6, a+=7, a+=8, a+=9, a+=10, a+=11, a+=12, a+=13, a+=14, a+=15, a+=16); + TEST_ASSERT_EQUAL(3, a); + + a = 0; + CODE_N(16, a+=1, a+=2, a+=3, a+=4, a+=5, a+=6, a+=7, a+=8, a+=9, a+=10, a+=11, a+=12, a+=13, a+=14, a+=15, a+=16); + TEST_ASSERT_EQUAL(136, a); + + // 16 is the highest number supported by the CODE_N macro +} + +MARLIN_TEST(macros_expansion, GANG_N) { + TEST_ASSERT_EQUAL(0, 0 GANG_N(0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16)); + TEST_ASSERT_EQUAL(1, 0 GANG_N(1, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16)); + TEST_ASSERT_EQUAL(3, 0 GANG_N(2, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16)); + TEST_ASSERT_EQUAL(136, 0 GANG_N(16, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13, +14, +15, +16)); + + // 16 is the highest number supported by the GANG_N macro +} + +MARLIN_TEST(macros_expansion, GANG_N_1) { + // Count by twos to be sure it can't bass by returning N + TEST_ASSERT_EQUAL(0, 0 GANG_N_1(0, +2)); + TEST_ASSERT_EQUAL(2, 0 GANG_N_1(1, +2)); + TEST_ASSERT_EQUAL(4, 0 GANG_N_1(2, +2)); + TEST_ASSERT_EQUAL(32, 0 GANG_N_1(16, +2)); +} + +MARLIN_TEST(macros_expansion, LIST_N) { + std::vector expected, result; + int compare_size; + + expected = {}; + result = {LIST_N(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)}; + TEST_ASSERT_EQUAL(expected.size(), result.size()); + compare_size = _MIN(expected.size(), result.size()); + for (int i = 0; i < compare_size; i++) { + TEST_ASSERT_EQUAL(expected[i], result[i]); + } + + expected = {1}; + result = {LIST_N(1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)}; + TEST_ASSERT_EQUAL(expected.size(), result.size()); + compare_size = _MIN(expected.size(), result.size()); + for (int i = 0; i < compare_size; i++) { + TEST_ASSERT_EQUAL(expected[i], result[i]); + } + + expected = {1, 2}; + result = {LIST_N(2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)}; + TEST_ASSERT_EQUAL(expected.size(), result.size()); + compare_size = _MIN(expected.size(), result.size()); + for (int i = 0; i < compare_size; i++) { + TEST_ASSERT_EQUAL(expected[i], result[i]); + } + + expected = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + result = {LIST_N(16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)}; + TEST_ASSERT_EQUAL(expected.size(), result.size()); + compare_size = _MIN(expected.size(), result.size()); + for (int i = 0; i < compare_size; i++) { + TEST_ASSERT_EQUAL(expected[i], result[i]); + } +} + +MARLIN_TEST(macros_expansion, LIST_N_1) { + std::vector expected, result; + int compare_size; + + expected = {}; + result = {LIST_N_1(0, 1)}; + TEST_ASSERT_EQUAL(expected.size(), result.size()); + compare_size = _MIN(expected.size(), result.size()); + for (int i = 0; i < compare_size; i++) { + TEST_ASSERT_EQUAL(expected[i], result[i]); + } + + expected = {2}; + result = {LIST_N_1(1, 2)}; + TEST_ASSERT_EQUAL(expected.size(), result.size()); + compare_size = _MIN(expected.size(), result.size()); + for (int i = 0; i < compare_size; i++) { + TEST_ASSERT_EQUAL(expected[i], result[i]); + } + + expected = {1, 1}; + result = {LIST_N_1(2, 1)}; + TEST_ASSERT_EQUAL(expected.size(), result.size()); + compare_size = _MIN(expected.size(), result.size()); + for (int i = 0; i < compare_size; i++) { + TEST_ASSERT_EQUAL(expected[i], result[i]); + } + + expected = std::vector(16, 1); + result = {LIST_N_1(16, 1)}; + TEST_ASSERT_EQUAL(expected.size(), result.size()); + compare_size = _MIN(expected.size(), result.size()); + for (int i = 0; i < compare_size; i++) { + TEST_ASSERT_EQUAL(expected[i], result[i]); + } +} + +MARLIN_TEST(macros_expansion, ARRAY_N) { + // Test ARRAY_N macro + std::array expected = {1, 2, 3, 4, 5}; + std::array result = ARRAY_N(5, 1, 2, 3, 4, 5); + TEST_ASSERT_EQUAL(expected.size(), result.size()); + + std::array expected2 = {1, 2, 3}; + std::array result2 = ARRAY_N(3, 1, 2, 3); + TEST_ASSERT_EQUAL(expected2.size(), result2.size()); +} + +MARLIN_TEST(macros_expansion, ARRAY_N_1) { + // Test ARRAY_N_1 macro + std::array expected = {2, 2, 2, 2, 2}; + std::array result = ARRAY_N_1(5, 2); + TEST_ASSERT_EQUAL(expected.size(), result.size()); + + std::array expected2 = {1, 1, 1}; + std::array result2 = ARRAY_N_1(3, 1); + TEST_ASSERT_EQUAL(expected2.size(), result2.size()); +} + +MARLIN_TEST(macros_math, CEILING) { + TEST_ASSERT_EQUAL(2, CEILING(3, 2)); + TEST_ASSERT_EQUAL(5, CEILING(10, 2)); + TEST_ASSERT_EQUAL(0, CEILING(0, 2)); +} + +MARLIN_TEST(macros_math, ABS) { + TEST_ASSERT_EQUAL(5, ABS(-5)); + TEST_ASSERT_EQUAL(5, ABS(5)); + TEST_ASSERT_EQUAL_FLOAT(5.5, ABS(-5.5)); + TEST_ASSERT_EQUAL_FLOAT(5.5, ABS(5.5)); +} + +MARLIN_TEST(macros_float, UNEAR_ZERO) { + TEST_ASSERT_TRUE(UNEAR_ZERO(0.0000009f)); + TEST_ASSERT_FALSE(UNEAR_ZERO(0.000001f)); +} + +MARLIN_TEST(macros_float, NEAR_ZERO) { + TEST_ASSERT_TRUE(NEAR_ZERO(0.0000001f)); + TEST_ASSERT_TRUE(NEAR_ZERO(-0.0000001f)); + TEST_ASSERT_FALSE(NEAR_ZERO(0.0000011f)); + TEST_ASSERT_FALSE(NEAR_ZERO(-0.0000011f)); +} + +MARLIN_TEST(macros_float, NEAR) { + TEST_ASSERT_TRUE(NEAR(0.000001f, 0.000002f)); + TEST_ASSERT_FALSE(NEAR(0.0000009f, 0.000002f)); +} + +MARLIN_TEST(macros_float, RECIPROCAL) { + TEST_ASSERT_EQUAL_FLOAT(1.0f, RECIPROCAL(1.0f)); + TEST_ASSERT_EQUAL_FLOAT(0.0f, RECIPROCAL(0.0f)); + TEST_ASSERT_EQUAL_FLOAT(2.0f, RECIPROCAL(0.5f)); + TEST_ASSERT_EQUAL_FLOAT(-2.0f, RECIPROCAL(-0.5f)); + TEST_ASSERT_EQUAL_FLOAT(0.0f, RECIPROCAL(0.0000001f)); + TEST_ASSERT_EQUAL_FLOAT(0.0f, RECIPROCAL(-0.0000001f)); +} + +MARLIN_TEST(macros_float, FIXFLOAT) { + TEST_ASSERT_EQUAL(0.0000005f, FIXFLOAT(0.0f)); + TEST_ASSERT_EQUAL(-0.0000005f, FIXFLOAT(-0.0f)); +} + +MARLIN_TEST(macros_math, MATH_MACROS) { + // Sanity check of macros typically mapped to compiler functions + TEST_ASSERT_EQUAL_FLOAT(0.0f, ACOS(1.0f)); + TEST_ASSERT_EQUAL_FLOAT(0.785398f, ATAN2(1.0f, 1.0f)); + TEST_ASSERT_EQUAL_FLOAT(8.0f, POW(2.0f, 3.0f)); + TEST_ASSERT_EQUAL_FLOAT(2.0f, SQRT(4.0f)); + TEST_ASSERT_EQUAL_FLOAT(0.5f, RSQRT(4.0f)); + TEST_ASSERT_EQUAL_FLOAT(2.0f, CEIL(1.5f)); + TEST_ASSERT_EQUAL_FLOAT(1.0f, FLOOR(1.5f)); + TEST_ASSERT_EQUAL_FLOAT(1.0f, TRUNC(1.5f)); + TEST_ASSERT_EQUAL(2, LROUND(1.5f)); + TEST_ASSERT_EQUAL_FLOAT(1.0f, FMOD(5.0f, 2.0f)); + TEST_ASSERT_EQUAL_FLOAT(5.0f, HYPOT(3.0f, 4.0f)); +} + +MARLIN_TEST(macros_math, MIN_MAX) { + // _MIN tests + TEST_ASSERT_EQUAL(-1, _MIN(-1, 0)); + TEST_ASSERT_EQUAL(-1, _MIN(0, -1)); + TEST_ASSERT_EQUAL(-1, _MIN(-1, 1)); + TEST_ASSERT_EQUAL(-1, _MIN(1, -1)); + TEST_ASSERT_EQUAL(-1, _MIN(-1, -1)); + TEST_ASSERT_EQUAL(1, _MIN(1, 1)); + TEST_ASSERT_EQUAL_FLOAT(-1.5f, _MIN(-1.5f, 0.5f)); + TEST_ASSERT_EQUAL_FLOAT(-1.5f, _MIN(0.5f, -1.5f)); + + // _MAX tests + TEST_ASSERT_EQUAL(0, _MAX(-1, 0)); + TEST_ASSERT_EQUAL(0, _MAX(0, -1)); + TEST_ASSERT_EQUAL(1, _MAX(-1, 1)); + TEST_ASSERT_EQUAL(1, _MAX(1, -1)); + TEST_ASSERT_EQUAL(-1, _MAX(-1, -1)); + TEST_ASSERT_EQUAL(1, _MAX(1, 1)); + TEST_ASSERT_EQUAL_FLOAT(0.5f, _MAX(-1.5f, 0.5f)); + TEST_ASSERT_EQUAL_FLOAT(0.5f, _MAX(0.5f, -1.5f)); +} + +MARLIN_TEST(macros_math, INCREMENT) { + TEST_ASSERT_EQUAL(1, INCREMENT(0)); + TEST_ASSERT_EQUAL(21, INCREMENT(20)); + // 20 is the highest number supported by the INCREMENT macro +} + +MARLIN_TEST(macros_math, ADD) { + // Test smallest add + TEST_ASSERT_EQUAL(0, ADD0(0)); + TEST_ASSERT_EQUAL(10, ADD0(10)); + + // Test largest add + TEST_ASSERT_EQUAL(10, ADD10(0)); + TEST_ASSERT_EQUAL(20, ADD10(10)); +} + +MARLIN_TEST(macros_math, SUM) { + // Test smallest sum + TEST_ASSERT_EQUAL(3, SUM(0, 3)); + TEST_ASSERT_EQUAL(7, SUM(3, 4)); + + // Test largest sum + TEST_ASSERT_EQUAL(15, SUM(10, 5)); + TEST_ASSERT_EQUAL(19, SUM(9, 10)); +} + +MARLIN_TEST(macros_math, DOUBLE) { + // Test double + TEST_ASSERT_EQUAL(0, DOUBLE(0)); + TEST_ASSERT_EQUAL(2, DOUBLE(1)); + TEST_ASSERT_EQUAL(4, DOUBLE(2)); + TEST_ASSERT_EQUAL(20, DOUBLE(10)); +} + +MARLIN_TEST(macros_math, DECREMENT) { + TEST_ASSERT_EQUAL(0, DECREMENT(1)); + TEST_ASSERT_EQUAL(14, DECREMENT(15)); +} + +MARLIN_TEST(macros_math, SUB) { + // Test smallest subtraction + TEST_ASSERT_EQUAL(0, SUB0(0)); + TEST_ASSERT_EQUAL(10, SUB0(10)); + + // Test subtracting 1 + TEST_ASSERT_EQUAL(0, SUB1(1)); + TEST_ASSERT_EQUAL(5, SUB1(6)); + + // Test largest subtraction + TEST_ASSERT_EQUAL(0, SUB10(10)); + TEST_ASSERT_EQUAL(5, SUB10(15)); +} + + +// Define a helper macro for testing +#define TEST_OP(i) ++counter; +#define TEST_OP2(i, j) counter += j; + +MARLIN_TEST(macros_repeat, REPEAT) { + int counter = 0; + REPEAT(5, TEST_OP); + TEST_ASSERT_EQUAL(5, counter); +} + +MARLIN_TEST(macros_repeat, REPEAT_1) { + int counter = 0; + REPEAT_1(5, TEST_OP); + TEST_ASSERT_EQUAL(5, counter); +} + +MARLIN_TEST(macros_repeat, REPEAT2) { + int counter = 0; + REPEAT2(5, TEST_OP2, 1); + TEST_ASSERT_EQUAL(5, counter); +} + +MARLIN_TEST(macros_repeat, RREPEAT) { + int counter = 0; + RREPEAT(5, TEST_OP); + TEST_ASSERT_EQUAL(5, counter); +} + +MARLIN_TEST(macros_repeat, RREPEAT_1) { + int counter = 0; + RREPEAT_1(5, TEST_OP); + TEST_ASSERT_EQUAL(5, counter); +} + +MARLIN_TEST(macros_repeat, RREPEAT2) { + int counter = 0; + RREPEAT2(5, TEST_OP2, 1); + TEST_ASSERT_EQUAL(5, counter); +} From dca6afc26efb860e60e8c47c2390e11f426dbe16 Mon Sep 17 00:00:00 2001 From: Chris <52449218+shadow578@users.noreply.github.com> Date: Sun, 14 Apr 2024 20:42:57 +0200 Subject: [PATCH 18/22] =?UTF-8?q?=E2=9C=A8=F0=9F=90=9B=20HC32=20-=20Add=20?= =?UTF-8?q?SERIAL=5FDMA,=20fix=20SDIO=20and=20MEATPACK=20(#26845)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix meatpack on hc32 * add support for SERIAL_DMA on HC32 * add additional checks in HC32 HAL * migrate HC32 HAL to use app_config.h * fix memory leak in HC32 sdio HAL https://github.com/MarlinFirmware/Marlin/pull/26845#issuecomment-1980218771 * hc32: fail if both EMERGENCY_PARSER and SERIAL_DMA are enabled --- Marlin/Configuration_adv.h | 2 +- Marlin/src/HAL/HC32/MarlinHAL.cpp | 31 +++++++++++- Marlin/src/HAL/HC32/MarlinSerial.cpp | 26 ++++++++-- Marlin/src/HAL/HC32/MarlinSerial.h | 46 +++++++++++++++--- Marlin/src/HAL/HC32/app_config.h | 70 +++++++++++++++++++++++++++ Marlin/src/HAL/HC32/inc/SanityCheck.h | 29 +++++++++++ Marlin/src/HAL/HC32/sdio.cpp | 43 +++++++++------- Marlin/src/inc/SanityCheck.h | 6 ++- ini/hc32.ini | 27 +++++------ 9 files changed, 233 insertions(+), 47 deletions(-) create mode 100644 Marlin/src/HAL/HC32/app_config.h diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 559eafdbf6..95e680a6d4 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2698,7 +2698,7 @@ * This feature is EXPERIMENTAL so use with caution and test thoroughly. * Enable this option to receive data on the serial ports via the onboard DMA * controller for more stable and reliable high-speed serial communication. - * Only some STM32 MCUs are currently supported. + * Support is currently limited to some STM32 MCUs and all HC32 MCUs. * Note: This has no effect on emulated USB serial ports. */ //#define SERIAL_DMA diff --git a/Marlin/src/HAL/HC32/MarlinHAL.cpp b/Marlin/src/HAL/HC32/MarlinHAL.cpp index 1ab374fbf1..acb96dadc6 100644 --- a/Marlin/src/HAL/HC32/MarlinHAL.cpp +++ b/Marlin/src/HAL/HC32/MarlinHAL.cpp @@ -123,6 +123,11 @@ void MarlinHAL::init() { // Register min serial TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); + + // warn if low memory after init + if (freeMemory() < 1024) { + SERIAL_WARN_MSG("HAL: low memory after init!\n"); + } } void MarlinHAL::init_board() {} @@ -147,7 +152,31 @@ void MarlinHAL::delay_ms(const int ms) { delay(ms); } -void MarlinHAL::idletask() {} +void MarlinHAL::idletask() { + #if ENABLED(MARLIN_DEV_MODE) + // check & print serial RX errors + MSerialT *serials[] = { &MSerial1, &MSerial2 }; + for (int serial = 0; serial < 2; serial++) { + usart_receive_error_t err = serials[serial]->getReceiveError(); + if (err != usart_receive_error_t::None) { + // "Warning: MSerial[n] RX [Framing|Parity|Overrun] Error" + SERIAL_WARN_START(); + SERIAL_ECHOPGM(" MSerial"); + SERIAL_ECHO(serial + 1); + SERIAL_ECHOPGM(" RX "); + switch(err) { + case usart_receive_error_t::FramingError: SERIAL_ECHOPGM("Framing"); break; + case usart_receive_error_t::ParityError: SERIAL_ECHOPGM("Parity"); break; + case usart_receive_error_t::OverrunError: SERIAL_ECHOPGM("Overrun"); break; + case usart_receive_error_t::RxDataDropped: SERIAL_ECHOPGM("DataDropped"); break; + default: break; + } + SERIAL_ECHOPGM(" Error"); + SERIAL_EOL(); + } + } + #endif +} uint8_t MarlinHAL::get_reset_source() { // Query reset cause from RMU diff --git a/Marlin/src/HAL/HC32/MarlinSerial.cpp b/Marlin/src/HAL/HC32/MarlinSerial.cpp index eb203f79d3..11d4abfab9 100644 --- a/Marlin/src/HAL/HC32/MarlinSerial.cpp +++ b/Marlin/src/HAL/HC32/MarlinSerial.cpp @@ -46,14 +46,34 @@ constexpr bool serial_handles_emergency(int port) { // // Define serial ports // -#define DEFINE_HWSERIAL_MARLIN(name, n) \ + +// serial port where RX and TX use IRQs +#define DEFINE_IRQ_SERIAL_MARLIN(name, n) \ MSerialT name(serial_handles_emergency(n), \ &USART##n##_config, \ BOARD_USART##n##_TX_PIN, \ BOARD_USART##n##_RX_PIN); -DEFINE_HWSERIAL_MARLIN(MSerial1, 1); -DEFINE_HWSERIAL_MARLIN(MSerial2, 2); +// serial port where RX uses DMA and TX uses IRQs +// all serial ports use DMA1 +// since there are 4 USARTs and 4 DMA channels, we can use the USART number as the DMA channel +#define DEFINE_DMA_SERIAL_MARLIN(name, n) \ + MSerialT name(serial_handles_emergency(n), \ + &USART##n##_config, \ + BOARD_USART##n##_TX_PIN, \ + BOARD_USART##n##_RX_PIN, \ + M4_DMA1, \ + ((en_dma_channel_t)(n - 1))); // map USART1 to DMA channel 0, USART2 to DMA channel 1, etc. + +#define DEFINE_SERIAL_MARLIN(name, n) TERN(SERIAL_DMA, DEFINE_DMA_SERIAL_MARLIN(name, n), DEFINE_IRQ_SERIAL_MARLIN(name, n)) + +DEFINE_SERIAL_MARLIN(MSerial1, 1); +DEFINE_SERIAL_MARLIN(MSerial2, 2); + +// TODO: remove this warning when SERIAL_DMA has been tested some more +#if ENABLED(SERIAL_DMA) + #warning "SERIAL_DMA may be unstable on HC32F460." +#endif // // Serial port assertions diff --git a/Marlin/src/HAL/HC32/MarlinSerial.h b/Marlin/src/HAL/HC32/MarlinSerial.h index 08eeef4395..b63b069b9d 100644 --- a/Marlin/src/HAL/HC32/MarlinSerial.h +++ b/Marlin/src/HAL/HC32/MarlinSerial.h @@ -25,17 +25,42 @@ #include // Optionally set uart IRQ priority to reduce overflow errors -// #define UART_IRQ_PRIO 1 +//#define UART_RX_IRQ_PRIO 1 +//#define UART_TX_IRQ_PRIO 1 +//#define UART_RX_DMA_IRQ_PRIO 1 struct MarlinSerial : public Usart { - MarlinSerial(struct usart_config_t *usart_device, gpio_pin_t tx_pin, gpio_pin_t rx_pin) : Usart(usart_device, tx_pin, rx_pin) {} + MarlinSerial( + struct usart_config_t *usart_device, + gpio_pin_t tx_pin, + gpio_pin_t rx_pin + #if ENABLED(SERIAL_DMA) + , M4_DMA_TypeDef *dma_unit = nullptr, + en_dma_channel_t rx_dma_channel = DmaCh0 + #endif + ) : Usart(usart_device, tx_pin, rx_pin) { + #if ENABLED(SERIAL_DMA) + if (dma_unit != nullptr) { + enableRxDma(dma_unit, rx_dma_channel); + } + #endif + } - #ifdef UART_IRQ_PRIO + #if defined(UART_RX_IRQ_PRIO) || defined(UART_TX_IRQ_PRIO) || defined(UART_RX_DMA_IRQ_PRIO) void setPriority() { - NVIC_SetPriority(c_dev()->interrupts.rx_data_available.interrupt_number, UART_IRQ_PRIO); - NVIC_SetPriority(c_dev()->interrupts.rx_error.interrupt_number, UART_IRQ_PRIO); - NVIC_SetPriority(c_dev()->interrupts.tx_buffer_empty.interrupt_number, UART_IRQ_PRIO); - NVIC_SetPriority(c_dev()->interrupts.tx_complete.interrupt_number, UART_IRQ_PRIO); + #if defined(UART_RX_IRQ_PRIO) + NVIC_SetPriority(c_dev()->interrupts.rx_data_available.interrupt_number, UART_RX_IRQ_PRIO); + NVIC_SetPriority(c_dev()->interrupts.rx_error.interrupt_number, UART_RX_IRQ_PRIO); + #endif + + #if defined(UART_TX_IRQ_PRIO) + NVIC_SetPriority(c_dev()->interrupts.tx_buffer_empty.interrupt_number, UART_TX_IRQ_PRIO); + NVIC_SetPriority(c_dev()->interrupts.tx_complete.interrupt_number, UART_TX_IRQ_PRIO); + #endif + + #if defined(UART_RX_DMA_IRQ_PRIO) && ENABLED(SERIAL_DMA) + NVIC_SetPriority(c_dev()->dma.rx.rx_data_available_dma_btc.interrupt_number, UART_RX_DMA_IRQ_PRIO); + #endif } void begin(uint32_t baud) { @@ -47,7 +72,12 @@ struct MarlinSerial : public Usart { Usart::begin(baud, config); setPriority(); } - #endif + + void begin(uint32_t baud, const stc_usart_uart_init_t *config, const bool rxNoiseFilter = true) { + Usart::begin(baud, config, rxNoiseFilter); + setPriority(); + } + #endif // UART_RX_IRQ_PRIO || UART_TX_IRQ_PRIO || UART_RX_DMA_IRQ_PRIO }; typedef Serial1Class MSerialT; diff --git a/Marlin/src/HAL/HC32/app_config.h b/Marlin/src/HAL/HC32/app_config.h new file mode 100644 index 0000000000..bc9d14b4c6 --- /dev/null +++ b/Marlin/src/HAL/HC32/app_config.h @@ -0,0 +1,70 @@ +/** + * app_config.h is included by the hc32f460 arduino build script for every source file. + * it is used to configure the arduino core (and ddl) automatically according + * to the settings in Configuration.h and Configuration_adv.h. + */ +#pragma once +#ifndef _HC32_APP_CONFIG_H_ +#define _HC32_APP_CONFIG_H_ + +#include "../../inc/MarlinConfigPre.h" + +// +// dev mode +// +#if ENABLED(MARLIN_DEV_MODE) + #define __DEBUG 1 + #define __CORE_DEBUG 1 +#endif + +// +// Fault Handlers and Panic +// + +#if ENABLED(POSTMORTEM_DEBUGGING) + // disable arduino core fault handler, as we define our own + #define CORE_DISABLE_FAULT_HANDLER 1 +#endif + +// force-enable panic handler so that we can use our custom one (in MinSerial) +#define PANIC_ENABLE 1 + +// use short filenames in ddl debug and core panic output +#define __DEBUG_SHORT_FILENAMES 1 +#define __PANIC_SHORT_FILENAMES 1 + +// omit panic messages in core panic output +#define __OMIT_PANIC_MESSAGE 1 + +// +// Usart +// + +// disable serial globals (Serial1, Serial2, ...), as we define our own +#define DISABLE_SERIAL_GLOBALS 1 + +// increase the size of the Usart buffers (both RX and TX) +// NOTE: +// the heap usage will increase by (SERIAL_BUFFER_SIZE - 64) * "number of serial ports used" +// if running out of heap, the system may become unstable +//#define SERIAL_BUFFER_SIZE 256 + +// enable support for Usart Clock Divider / Oversampling auto config +#define USART_AUTO_CLKDIV_OS_CONFIG 1 + +// enable USART_RX_DMA_SUPPORT core option when SERIAL_DMA is enabled +#if ENABLED(SERIAL_DMA) + #define USART_RX_DMA_SUPPORT 1 +#endif + +// +// Misc. +// + +// redirect printf to host serial +#define REDIRECT_PRINTF_TO_SERIAL 1 + +// FIXME override F_CPU to PCLK1, as marlin freaks out otherwise +#define F_CPU (SYSTEM_CLOCK_FREQUENCIES.pclk1) + +#endif // _HC32_APP_CONFIG_H_ diff --git a/Marlin/src/HAL/HC32/inc/SanityCheck.h b/Marlin/src/HAL/HC32/inc/SanityCheck.h index ef8d9a9975..0d05448f98 100644 --- a/Marlin/src/HAL/HC32/inc/SanityCheck.h +++ b/Marlin/src/HAL/HC32/inc/SanityCheck.h @@ -20,6 +20,20 @@ * */ #pragma once +#include + +#if !defined(ARDUINO_CORE_VERSION_INT) || !defined(GET_VERSION_INT) + // version macros were introduced in arduino core version 1.1.0 + // below that version, we polyfill them + #define GET_VERSION_INT(major, minor, patch) ((major * 100000) + (minor * 1000) + patch) + #define ARDUINO_CORE_VERSION_INT GET_VERSION_INT(1, 0, 0) +#endif + +#if ARDUINO_CORE_VERSION_INT < GET_VERSION_INT(1, 1, 0) + // because we use app_config.h introduced in arduino core version 1.1.0, the + // HAL is not compatible with older versions + #error "The HC32 HAL is not compatible with Arduino Core versions < 1.1.0. Consider updating the Arduino Core." +#endif #ifndef BOARD_XTAL_FREQUENCY #error "BOARD_XTAL_FREQUENCY is required for HC32F460." @@ -74,3 +88,18 @@ #error "HC32 HAL uses a custom panic handler. Do not define PANIC_USARTx_TX_PIN." #endif #endif + +#if ENABLED(SERIAL_DMA) + #if !defined(USART_RX_DMA_SUPPORT) + #error "SERIAL_DMA requires USART_RX_DMA_SUPPORT to be enabled in the arduino core." + #endif + + // USART_RX_DMA_SUPPORT does not implement core_hook_usart_rx_irq, which is required for the emergency parser + #if ENABLED(EMERGENCY_PARSER) + #error "EMERGENCY_PARSER is not supported with SERIAL_DMA. Please disable either SERIAL_DMA or EMERGENCY_PARSER." + #endif + + #if ARDUINO_CORE_VERSION_INT < GET_VERSION_INT(1, 1, 0) + #error "SERIAL_DMA is not supported with arduino core version < 1.1.0." + #endif +#endif diff --git a/Marlin/src/HAL/HC32/sdio.cpp b/Marlin/src/HAL/HC32/sdio.cpp index 4360d715ff..3c4038f92d 100644 --- a/Marlin/src/HAL/HC32/sdio.cpp +++ b/Marlin/src/HAL/HC32/sdio.cpp @@ -54,7 +54,7 @@ fn \ } -stc_sd_handle_t *handle; +stc_sd_handle_t *handle = nullptr; bool SDIO_Init() { // Configure SDIO pins @@ -66,36 +66,45 @@ bool SDIO_Init() { GPIO_SetFunc(BOARD_SDIO_CMD, Func_Sdio); GPIO_SetFunc(BOARD_SDIO_DET, Func_Sdio); + // If a handle is already initialized, free it before creating a new one + // otherwise, we will leak memory, which will eventually crash the system + if (handle != nullptr) { + delete handle->pstcDmaInitCfg; + delete handle->pstcCardInitCfg; + delete handle; + handle = nullptr; + } + // Create DMA configuration stc_sdcard_dma_init_t *dmaConf = new stc_sdcard_dma_init_t; dmaConf->DMAx = SDIO_DMA_PERIPHERAL; dmaConf->enDmaCh = SDIO_DMA_CHANNEL; + // Create card configuration + // This should be a fairly safe configuration for most cards + stc_sdcard_init_t *cardConf = new stc_sdcard_init_t; + cardConf->enBusWidth = SdiocBusWidth4Bit; + cardConf->enClkFreq = SdiocClk400K; + cardConf->enSpeedMode = SdiocNormalSpeedMode; + cardConf->pstcInitCfg = nullptr; + // Create handle in DMA mode handle = new stc_sd_handle_t; handle->SDIOCx = SDIO_PERIPHERAL; handle->enDevMode = SdCardDmaMode; handle->pstcDmaInitCfg = dmaConf; - - // Create card configuration - // This should be a fairly safe configuration for most cards - stc_sdcard_init_t cardConf = { - .enBusWidth = SdiocBusWidth4Bit, - .enClkFreq = SdiocClk400K, - .enSpeedMode = SdiocNormalSpeedMode, - //.pstcInitCfg = NULL, - }; + //handle->pstcCardInitCfg = cardConf; // assigned in SDCARD_Init // Initialize sd card - en_result_t rc = SDCARD_Init(handle, &cardConf); + en_result_t rc = SDCARD_Init(handle, cardConf); if (rc != Ok) printf("SDIO_Init() error (rc=%u)\n", rc); return rc == Ok; } bool SDIO_ReadBlock(uint32_t block, uint8_t *dst) { - CORE_ASSERT(handle != NULL, "SDIO not initialized"); - CORE_ASSERT(dst != NULL, "SDIO_ReadBlock dst is NULL"); + CORE_ASSERT(handle != nullptr, "SDIO not initialized", return false); + CORE_ASSERT(dst != nullptr, "SDIO_ReadBlock dst is NULL", return false); WITH_RETRY(SDIO_READ_RETRIES, { en_result_t rc = SDCARD_ReadBlocks(handle, block, 1, dst, SDIO_READ_TIMEOUT); @@ -107,8 +116,8 @@ bool SDIO_ReadBlock(uint32_t block, uint8_t *dst) { } bool SDIO_WriteBlock(uint32_t block, const uint8_t *src) { - CORE_ASSERT(handle != NULL, "SDIO not initialized"); - CORE_ASSERT(src != NULL, "SDIO_WriteBlock src is NULL"); + CORE_ASSERT(handle != nullptr, "SDIO not initialized", return false); + CORE_ASSERT(src != nullptr, "SDIO_WriteBlock src is NULL", return false); WITH_RETRY(SDIO_WRITE_RETRIES, { en_result_t rc = SDCARD_WriteBlocks(handle, block, 1, (uint8_t *)src, SDIO_WRITE_TIMEOUT); @@ -120,12 +129,12 @@ bool SDIO_WriteBlock(uint32_t block, const uint8_t *src) { } bool SDIO_IsReady() { - CORE_ASSERT(handle != NULL, "SDIO not initialized"); + CORE_ASSERT(handle != nullptr, "SDIO not initialized", return false); return bool(handle->stcCardStatus.READY_FOR_DATA); } uint32_t SDIO_GetCardSize() { - CORE_ASSERT(handle != NULL, "SDIO not initialized"); + CORE_ASSERT(handle != nullptr, "SDIO not initialized", return 0); // Multiply number of blocks with block size to get size in bytes const uint64_t cardSizeBytes = uint64_t(handle->stcSdCardInfo.u32LogBlockNbr) * uint64_t(handle->stcSdCardInfo.u32LogBlockSize); diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 392d75675e..5f14c568ae 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -235,9 +235,11 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "SERIAL_XON_XOFF and SERIAL_STATS_* features not supported on USB-native AVR devices." #endif -// Serial DMA is only available for some STM32 MCUs +// Serial DMA is only available for some STM32 MCUs and HC32 #if ENABLED(SERIAL_DMA) - #if !HAL_STM32 || NONE(STM32F0xx, STM32F1xx, STM32F2xx, STM32F4xx, STM32F7xx) + #if defined(ARDUINO_ARCH_HC32) + // checks for HC32 are located in HAL/HC32/inc/SanityCheck.h + #elif !HAL_STM32 || NONE(STM32F0xx, STM32F1xx, STM32F2xx, STM32F4xx, STM32F7xx) #error "SERIAL_DMA is only available for some STM32 MCUs and requires HAL/STM32." #elif !defined(HAL_UART_MODULE_ENABLED) || defined(HAL_UART_MODULE_ONLY) #error "SERIAL_DMA requires STM32 platform HAL UART (without HAL_UART_MODULE_ONLY)." diff --git a/ini/hc32.ini b/ini/hc32.ini index 9bf15447e2..2af761128c 100644 --- a/ini/hc32.ini +++ b/ini/hc32.ini @@ -33,22 +33,14 @@ build_src_filter = ${common.default_src_filter} + + Date: Sun, 14 Apr 2024 21:04:52 +0100 Subject: [PATCH 19/22] =?UTF-8?q?=E2=9C=A8=20Add=20Dagoma=20D6=20as=20foun?= =?UTF-8?q?d=20in=20DiscoUltimate=20v2=20TMC=20(#26874)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Dagoma D6 board as used in their DiscoUltimate v2 TMC. Taken from the Dagoma fork of Marlin DU_MC branch where it is called FYSETC_DAGOMA_F5 and explicitly confirmed by Dagoma as being the D6: "the BOARD_FYSETC_DAGOMA_F5 is effectively the definition for the D6" --------- Co-authored-by: thisiskeithb <13375512+thisiskeithb@users.noreply.github.com> Co-authored-by: Orel <37673727+0r31@users.noreply.github.com> --- Marlin/src/core/boards.h | 1 + Marlin/src/pins/pins.h | 2 + Marlin/src/pins/ramps/pins_DAGOMA_D6.h | 124 +++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 Marlin/src/pins/ramps/pins_DAGOMA_D6.h diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index 1dfcabdefb..cef30c5cd2 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -131,6 +131,7 @@ #define BOARD_PXMALION_CORE_I3 1164 // Pxmalion Core I3 #define BOARD_PANOWIN_CUTLASS 1165 // Panowin Cutlass (as found in the Panowin F1) #define BOARD_KODAMA_BARDO 1166 // Kodama Bardo V1.x (as found in the Kodama Trinus) +#define BOARD_DAGOMA_D6 1167 // Dagoma D6 (as found in the Dagoma DiscoUltimate V2 TMC) // // RAMBo and derivatives diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index 53d31c0168..cdc4fdb7a4 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -224,6 +224,8 @@ #include "ramps/pins_RAMPS_CREALITY.h" // ATmega2560 env:mega2560 #elif MB(DAGOMA_F5) #include "ramps/pins_DAGOMA_F5.h" // ATmega2560 env:mega2560 +#elif MB(DAGOMA_D6) + #include "ramps/pins_DAGOMA_D6.h" // ATmega2560 env:mega2560ext #elif MB(FYSETC_F6_13) #include "ramps/pins_FYSETC_F6_13.h" // ATmega2560 env:FYSETC_F6 #elif MB(FYSETC_F6_14) diff --git a/Marlin/src/pins/ramps/pins_DAGOMA_D6.h b/Marlin/src/pins/ramps/pins_DAGOMA_D6.h new file mode 100644 index 0000000000..de5dbbd9bb --- /dev/null +++ b/Marlin/src/pins/ramps/pins_DAGOMA_D6.h @@ -0,0 +1,124 @@ +/** + * 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 + +#if HOTENDS > 2 || E_STEPPERS > 2 + #error "Dagoma3D D6 supports up to 2 hotends / E-steppers." +#endif + +#define BOARD_INFO_NAME "Dagoma3D D6" + +// +// Trinamic Stallguard pins +// +#define X_DIAG_PIN 43 +#define Y_DIAG_PIN 41 +#define Z_DIAG_PIN 47 +#define E0_DIAG_PIN 21 +#define E1_DIAG_PIN 20 + +// +// Endstops +// +#define X_STOP_PIN 2 +#define Y_STOP_PIN 3 +#define Z_STOP_PIN 15 + +// +// Filament Runout Sensor +// +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN 39 +#endif +#if EXTRUDERS > 1 && !defined(FIL_RUNOUT2_PIN) + #define FIL_RUNOUT2_PIN 14 +#endif + +// Alter timing for graphical display +#if IS_U8GLIB_ST7920 + #ifndef BOARD_ST7920_DELAY_1 + #define BOARD_ST7920_DELAY_1 0 + #endif + #ifndef BOARD_ST7920_DELAY_2 + #define BOARD_ST7920_DELAY_2 250 + #endif + #ifndef BOARD_ST7920_DELAY_3 + #define BOARD_ST7920_DELAY_3 250 + #endif +#endif + +#define KILL_PIN -1 // NC + +#define LCD_CONTRAST_DEFAULT 255 + +// +// Sensorless homing DIAG pin is not directly connected to the MCU. Close +// the jumper next to the limit switch socket when using sensorless homing. +// +#if HAS_TMC_UART + /** + * TMC2208/TMC2209 stepper drivers + */ + #define X_SERIAL_RX_PIN 73 + #define X_SERIAL_TX_PIN 73 + #define Y_SERIAL_RX_PIN 73 + #define Y_SERIAL_TX_PIN 73 + #define Z_SERIAL_RX_PIN 73 + #define Z_SERIAL_TX_PIN 73 + #define E0_SERIAL_RX_PIN 73 + #define E0_SERIAL_TX_PIN 73 + #define E1_SERIAL_RX_PIN 12 + #define E1_SERIAL_TX_PIN 12 + + // Default TMC slave addresses + #ifdef X_SLAVE_ADDRESS + static_assert(X_SLAVE_ADDRESS == 0, "X_SLAVE_ADDRESS must be 0 for BOARD_DAGOMA_D6."); + #else + #define X_SLAVE_ADDRESS 0 + #endif + #ifdef Y_SLAVE_ADDRESS + static_assert(Y_SLAVE_ADDRESS == 1, "Y_SLAVE_ADDRESS must be 1 for BOARD_DAGOMA_D6."); + #else + #define Y_SLAVE_ADDRESS 1 + #endif + #ifdef Z_SLAVE_ADDRESS + static_assert(Z_SLAVE_ADDRESS == 2, "Z_SLAVE_ADDRESS must be 2 for BOARD_DAGOMA_D6."); + #else + #define Z_SLAVE_ADDRESS 2 + #endif + #ifdef E0_SLAVE_ADDRESS + static_assert(E0_SLAVE_ADDRESS == 3, "E0_SLAVE_ADDRESS must be 3 for BOARD_DAGOMA_D6."); + #else + #define E0_SLAVE_ADDRESS 3 + #endif + #ifdef E1_SLAVE_ADDRESS + static_assert(E1_SLAVE_ADDRESS == 3, "E1_SLAVE_ADDRESS must be 3 for BOARD_DAGOMA_D6."); + #else + #define E1_SLAVE_ADDRESS 3 + #endif + +#endif + +// +// Import default RAMPS 1.4 pins +// +#include "pins_RAMPS.h" From 02691060664b1d582ed72c207d0062bd7e5813d4 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 14 Apr 2024 16:24:14 -0500 Subject: [PATCH 20/22] =?UTF-8?q?=F0=9F=8E=A8=20Dagoma=20D6=20followup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/pins/ramps/pins_DAGOMA_D6.h | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Marlin/src/pins/ramps/pins_DAGOMA_D6.h b/Marlin/src/pins/ramps/pins_DAGOMA_D6.h index de5dbbd9bb..2a89647376 100644 --- a/Marlin/src/pins/ramps/pins_DAGOMA_D6.h +++ b/Marlin/src/pins/ramps/pins_DAGOMA_D6.h @@ -90,31 +90,26 @@ #define E1_SERIAL_TX_PIN 12 // Default TMC slave addresses - #ifdef X_SLAVE_ADDRESS - static_assert(X_SLAVE_ADDRESS == 0, "X_SLAVE_ADDRESS must be 0 for BOARD_DAGOMA_D6."); - #else + #ifndef X_SLAVE_ADDRESS #define X_SLAVE_ADDRESS 0 #endif - #ifdef Y_SLAVE_ADDRESS - static_assert(Y_SLAVE_ADDRESS == 1, "Y_SLAVE_ADDRESS must be 1 for BOARD_DAGOMA_D6."); - #else + #ifndef Y_SLAVE_ADDRESS #define Y_SLAVE_ADDRESS 1 #endif - #ifdef Z_SLAVE_ADDRESS - static_assert(Z_SLAVE_ADDRESS == 2, "Z_SLAVE_ADDRESS must be 2 for BOARD_DAGOMA_D6."); - #else + #ifndef Z_SLAVE_ADDRESS #define Z_SLAVE_ADDRESS 2 #endif - #ifdef E0_SLAVE_ADDRESS - static_assert(E0_SLAVE_ADDRESS == 3, "E0_SLAVE_ADDRESS must be 3 for BOARD_DAGOMA_D6."); - #else + #ifndef E0_SLAVE_ADDRESS #define E0_SLAVE_ADDRESS 3 #endif - #ifdef E1_SLAVE_ADDRESS - static_assert(E1_SLAVE_ADDRESS == 3, "E1_SLAVE_ADDRESS must be 3 for BOARD_DAGOMA_D6."); - #else + #ifndef E1_SLAVE_ADDRESS #define E1_SLAVE_ADDRESS 3 #endif + static_assert(X_SLAVE_ADDRESS == 0, "X_SLAVE_ADDRESS must be 0 for BOARD_DAGOMA_D6."); + static_assert(Y_SLAVE_ADDRESS == 1, "Y_SLAVE_ADDRESS must be 1 for BOARD_DAGOMA_D6."); + static_assert(Z_SLAVE_ADDRESS == 2, "Z_SLAVE_ADDRESS must be 2 for BOARD_DAGOMA_D6."); + static_assert(E0_SLAVE_ADDRESS == 3, "E0_SLAVE_ADDRESS must be 3 for BOARD_DAGOMA_D6."); + static_assert(E1_SLAVE_ADDRESS == 3, "E1_SLAVE_ADDRESS must be 3 for BOARD_DAGOMA_D6."); #endif From 3326c749f85ddfab6ba5879526466891f0e598a7 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 14 Apr 2024 16:26:16 -0500 Subject: [PATCH 21/22] =?UTF-8?q?=F0=9F=93=9D=20Minor=20README=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 106 +++++++++++++++++++++--------------------------------- 1 file changed, 41 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index 83614ad9cc..373444a164 100644 --- a/README.md +++ b/README.md @@ -39,16 +39,16 @@ To build and upload Marlin you will use one of these tools: Marlin is optimized to build with the **PlatformIO IDE** extension for **Visual Studio Code**. You can still build Marlin with **Arduino IDE**, and we hope to improve the Arduino build experience, but at this time PlatformIO is the better choice. +## 8-Bit AVR Boards + +We intend to continue supporting 8-bit AVR boards in perpetuity, maintaining a single codebase that can apply to all machines. We want casual hobbyists and tinkerers and owners of older machines to benefit from the community's innovations just as much as those with fancier machines. Plus, those old AVR-based machines are often the best for your testing and feedback! + ## Hardware Abstraction Layer (HAL) Marlin includes an abstraction layer to provide a common API for all the platforms it targets. This allows Marlin code to address the details of motion and user interface tasks at the lowest and highest levels with no system overhead, tying all events directly to the hardware clock. Every new HAL opens up a world of hardware. At this time we need HALs for RP2040 and the Duet3D family of boards. A HAL that wraps an RTOS is an interesting concept that could be explored. Did you know that Marlin includes a Simulator that can run on Windows, macOS, and Linux? Join the Discord to help move these sub-projects forward! -## 8-Bit AVR Boards - -A core tenet of this project is to keep supporting 8-bit AVR boards while also maintaining a single codebase that applies equally to all machines. We want casual hobbyists to benefit from the community's innovations as much as possible just as much as those with fancier machines. Plus, those old AVR-based machines are often the best for your testing and feedback! - ### Supported Platforms Platform|MCU|Example Boards @@ -71,22 +71,9 @@ A core tenet of this project is to keep supporting 8-bit AVR boards while also m [Teensy 4.1](https://www.pjrc.com/store/teensy41.html)|ARMยฎ Cortex-M7| Linux Native|x86/ARM/etc.|Raspberry Pi -## Submitting Patches - -Proposed patches should be submitted as a Pull Request against the ([bugfix-2.1.x](https://github.com/MarlinFirmware/Marlin/tree/bugfix-2.1.x)) branch. - -- This branch is for fixing bugs and integrating any new features for the duration of the Marlin 2.1.x life-cycle. -- Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) to gain points with the maintainers. -- Please submit Feature Requests and Bug Reports to the [Issue Queue](https://github.com/MarlinFirmware/Marlin/issues/new/choose). Support resources are also listed there. -- Whenever you add new features, be sure to add tests to `buildroot/tests` and then run your tests locally, if possible. - - It's optional: Running all the tests on Windows might take a long time, and they will run anyway on GitHub. - - If you're running the tests on Linux (or on WSL with the code on a Linux volume) the speed is much faster. - - You can use `make tests-all-local` or `make tests-single-local TEST_TARGET=...`. - - If you prefer Docker you can use `make tests-all-local-docker` or `make tests-all-local-docker TEST_TARGET=...`. - ## Marlin Support -The Issue Queue is reserved for Bug Reports and Feature Requests. To get help with configuration and troubleshooting, please use the following resources: +The Issue Queue is reserved for Bug Reports and Feature Requests. Please use the following resources for help with configuration and troubleshooting: - [Marlin Documentation](https://marlinfw.org) - Official Marlin documentation - [Marlin Discord](https://discord.gg/n5NJ59y) - Discuss issues with Marlin users and developers @@ -95,59 +82,48 @@ The Issue Queue is reserved for Bug Reports and Feature Requests. To get help wi - Facebook Group ["Marlin Firmware for 3D Printers"](https://www.facebook.com/groups/3Dtechtalk/) - [Marlin Configuration](https://www.youtube.com/results?search_query=marlin+configuration) on YouTube +## Contributing Patches + +You can contribute patches by submitting a Pull Request to the ([bugfix-2.1.x](https://github.com/MarlinFirmware/Marlin/tree/bugfix-2.1.x)) branch. + +- We use branches named with a "bugfix" or "dev" prefix to fix bugs and integrate new features. +- Follow the [Coding Standards](https://marlinfw.org/docs/development/coding_standards.html) to gain points with the maintainers. +- Please submit Feature Requests and Bug Reports to the [Issue Queue](https://github.com/MarlinFirmware/Marlin/issues/new/choose). See above for user support. +- Whenever you add new features, be sure to add one or more build tests to `buildroot/tests`. Any tests added to a PR will be run within that PR on GitHub servers as soon as they are pushed. To minimize iteration be sure to run your new tests locally, if possible. + - Local build tests: + - All: `make tests-config-all-local` + - Single: `make tests-config-single-local TEST_TARGET=...` + - Local build tests in Docker: + - All: `make tests-config-all-local-docker` + - Single: `make tests-config-all-local-docker TEST_TARGET=...` + - To run all unit test suites: + - Using PIO: `platformio run -t test-marlin` + - Using Make: `make unit-test-all-local` + - Using Docker + make: `maker unit-test-all-local-docker` + - To run a single unit test suite: + - Using PIO: `platformio run -t marlin_` + - Using make: `make unit-test-single-local TEST_TARGET=` + - Using Docker + make: `maker unit-test-single-local-docker TEST_TARGET=` +- If your feature can be unit tested, add one or more unit tests. For more information see our documentation on [Unit Tests](test). + ## Contributors Marlin is constantly improving thanks to a huge number of contributors from all over the world bringing their specialties and talents. Huge thanks are due to [all the contributors](https://github.com/MarlinFirmware/Marlin/graphs/contributors) who regularly patch up bugs, help direct traffic, and basically keep Marlin from falling apart. Marlin's continued existence would not be possible without them. -## Administration +## Project Leadership -Regular users can open and close their own issues, but only the administrators can do project-related things like add labels, merge changes, set milestones, and kick trolls. The current Marlin admin team consists of: - - - - -
Project Maintainer
- - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Scott Lahteine** - โ€…โ€…โ€…โ€…โ€…โ€…[@thinkyhead](https://github.com/thinkyhead) - โ€…โ€…โ€…โ€…โ€…โ€…[โ€…โ€…Donate ๐Ÿ’ธโ€…โ€…](https://www.thinkyhead.com/donate-to-marlin) - - - - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Roxanne Neufeld** - โ€…โ€…โ€…โ€…โ€…โ€…[@Roxy-3D](https://github.com/Roxy-3D) - - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Keith Bennett** - โ€…โ€…โ€…โ€…โ€…โ€…[@thisiskeithb](https://github.com/thisiskeithb) - โ€…โ€…โ€…โ€…โ€…โ€…[โ€…โ€…Donate ๐Ÿ’ธโ€…โ€…](https://github.com/sponsors/thisiskeithb) - - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Jason Smith** - โ€…โ€…โ€…โ€…โ€…โ€…[@sjasonsmith](https://github.com/sjasonsmith) - - - - ๐Ÿ‡ง๐Ÿ‡ทโ€…โ€…**Victor Oliveira** - โ€…โ€…โ€…โ€…โ€…โ€…[@rhapsodyv](https://github.com/rhapsodyv) - - ๐Ÿ‡ฌ๐Ÿ‡งโ€…โ€…**Chris Pepper** - โ€…โ€…โ€…โ€…โ€…โ€…[@p3p](https://github.com/p3p) - -๐Ÿ‡ณ๐Ÿ‡ฟโ€…โ€…**Peter Ellens** - โ€…โ€…โ€…โ€…โ€…โ€…[@ellensp](https://github.com/ellensp) - โ€…โ€…โ€…โ€…โ€…โ€…[โ€…โ€…Donate ๐Ÿ’ธโ€…โ€…](https://ko-fi.com/ellensp) - - - - ๐Ÿ‡บ๐Ÿ‡ธโ€…โ€…**Bob Kuhn** - โ€…โ€…โ€…โ€…โ€…โ€…[@Bob-the-Kuhn](https://github.com/Bob-the-Kuhn) - - ๐Ÿ‡ณ๐Ÿ‡ฑโ€…โ€…**Erik van der Zalm** - โ€…โ€…โ€…โ€…โ€…โ€…[@ErikZalm](https://github.com/ErikZalm) - -
+Name|Role|Link|Donate +----|----|----|---- +๐Ÿ‡บ๐Ÿ‡ธ Scott Lahteine|Project Lead|[[@thinkyhead](https://github.com/thinkyhead)]|[๐Ÿ’ธ Donate](https://marlinfw.org/docs/development/contributing.html#donate) +๐Ÿ‡บ๐Ÿ‡ธ Roxanne Neufeld|Admin|[[@Roxy-3D](https://github.com/Roxy-3D)]| +๐Ÿ‡บ๐Ÿ‡ธ Keith Bennett|Admin|[[@thisiskeithb](https://github.com/thisiskeithb)]|[๐Ÿ’ธ Donate](https://github.com/sponsors/thisiskeithb) +๐Ÿ‡บ๐Ÿ‡ธ Jason Smith|Admin|[[@sjasonsmith](https://github.com/sjasonsmith)]| +๐Ÿ‡ง๐Ÿ‡ท Victor Oliveira|Admin|[[@rhapsodyv](https://github.com/rhapsodyv)]| +๐Ÿ‡ฌ๐Ÿ‡ง Chris Pepper|Admin|[[@p3p](https://github.com/p3p)]| +๐Ÿ‡ณ๐Ÿ‡ฟ Peter Ellens|Admin|[[@ellensp](https://github.com/ellensp)]|[๐Ÿ’ธ Donate](https://ko-fi.com/ellensp) +๐Ÿ‡บ๐Ÿ‡ธ Bob Kuhn|Admin|[[@Bob-the-Kuhn](https://github.com/Bob-the-Kuhn)]| +๐Ÿ‡ณ๐Ÿ‡ฑ Erik van der Zalm|Founder|[[@ErikZalm](https://github.com/ErikZalm)]| ## 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. - -While we can't prevent the use of this code in products (3D printers, CNC, etc.) that are closed source or crippled by a patent, we would prefer that you choose another firmware or, better yet, make your own. From 1f84f50fd8a4c80c9ba56f2e61296e5790ff328b Mon Sep 17 00:00:00 2001 From: thinkyhead Date: Mon, 15 Apr 2024 02:38:10 +0000 Subject: [PATCH 22/22] [cron] Bump distribution date (2024-04-15) --- Marlin/Version.h | 2 +- Marlin/src/inc/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Version.h b/Marlin/Version.h index 6612c2f640..1da31c514e 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 "2024-04-14" +//#define STRING_DISTRIBUTION_DATE "2024-04-15" /** * Defines a generic printer name to be output to the LCD after booting Marlin. diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index ad30d74977..42225ed00e 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 "2024-04-14" + #define STRING_DISTRIBUTION_DATE "2024-04-15" #endif /**