From 83f68b3cf8e53b3d4946df6e4137d9851bbe8947 Mon Sep 17 00:00:00 2001
From: Daranbalt4 <cs.balint98@gmail.com>
Date: Sun, 26 Feb 2023 21:48:33 +0100
Subject: [PATCH 1/2] LCD_BACKLIGHT_TIMEOUT_MINS support for LCDs with NEOPIXEL
 backlight. fixes #25406

---
 Marlin/Configuration.h               |  1 +
 Marlin/src/feature/leds/neopixel.cpp | 12 +++++++
 Marlin/src/feature/leds/neopixel.h   |  5 +++
 Marlin/src/inc/SanityCheck.h         |  8 ++++-
 Marlin/src/lcd/marlinui.cpp          | 50 ++++++++++++++++++++--------
 5 files changed, 62 insertions(+), 14 deletions(-)

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index c163c58704a9..3b0daaf7fe0e 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -3404,6 +3404,7 @@
   //#define NEOPIXEL_BKGD_INDEX_FIRST   0 // Index of the first background LED
   //#define NEOPIXEL_BKGD_INDEX_LAST    5 // Index of the last background LED
   //#define NEOPIXEL_BKGD_COLOR { 255, 255, 255, 0 }  // R, G, B, W
+  //#define NEOPIXEL_BKGD_TIMEOUT_COLOR { 25, 25, 25, 0} // R, G, B, W
   //#define NEOPIXEL_BKGD_ALWAYS_ON       // Keep the backlight on when other NeoPixels are off
 #endif
 
diff --git a/Marlin/src/feature/leds/neopixel.cpp b/Marlin/src/feature/leds/neopixel.cpp
index ab7ffe217796..6816ef23fac4 100644
--- a/Marlin/src/feature/leds/neopixel.cpp
+++ b/Marlin/src/feature/leds/neopixel.cpp
@@ -54,6 +54,18 @@ Adafruit_NeoPixel Marlin_NeoPixel::adaneo1(NEOPIXEL_PIXELS, NEOPIXEL_PIN, NEOPIX
     set_background_color(background_color);
   }
 
+  #ifdef NEOPIXEL_BKGD_TIMEOUT_COLOR
+   void Marlin_NeoPixel::set_background_off() {
+      constexpr uint8_t background_color_off[4] = NEOPIXEL_BKGD_TIMEOUT_COLOR;
+      set_background_color(background_color_off);
+    }
+  #else
+    void Marlin_NeoPixel::set_background_off() {
+      constexpr uint8_t background_color_off[4] = { 0, 0, 0, 0};
+      set_background_color(background_color_off);
+    }
+  #endif
+
 #endif
 
 void Marlin_NeoPixel::set_color(const uint32_t color) {
diff --git a/Marlin/src/feature/leds/neopixel.h b/Marlin/src/feature/leds/neopixel.h
index 2048e2c2eebf..bd610a569ef9 100644
--- a/Marlin/src/feature/leds/neopixel.h
+++ b/Marlin/src/feature/leds/neopixel.h
@@ -91,6 +91,11 @@ class Marlin_NeoPixel {
     static void set_background_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t w);
     static void set_background_color(const uint8_t (&rgbw)[4]) { set_background_color(rgbw[0], rgbw[1], rgbw[2], rgbw[3]); }
     static void reset_background_color();
+
+    #ifdef NEOPIXEL_BKGD_TIMEOUT_COLOR
+      static void set_background_off();
+    #endif
+
   #endif
 
   static void begin() {
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index 11d27d6eaf9c..02e7dba54b90 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -3241,8 +3241,14 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE, "Movement bounds (X_MIN_POS, X_MAX_POS
 #if LCD_BACKLIGHT_TIMEOUT_MINS
   #if !HAS_ENCODER_ACTION
     #error "LCD_BACKLIGHT_TIMEOUT_MINS requires an LCD with encoder or keypad."
+  #elif ENABLED(NEOPIXEL_BKGD_INDEX_FIRST)
+    #if PIN_EXISTS(LCD_BACKLIGHT)
+      #error "LCD_BACKLIGHT_PIN and NEOPIXEL_BKGD_INDEX_FIRST are not supported at the same time."
+    #elif ENABLED(NEOPIXEL_BKGD_ALWAYS_ON)
+      #error "LCD_BACKLIGHT_TIMEOUT is not compatible with NEOPIXEL_BKGD_ALWAYS_ON."
+    #endif
   #elif !PIN_EXISTS(LCD_BACKLIGHT)
-    #error "LCD_BACKLIGHT_TIMEOUT_MINS requires LCD_BACKLIGHT_PIN."
+    #error "LCD_BACKLIGHT_TIMEOUT_MINS requires either LCD_BACKLIGHT_PIN or NEOPIXEL_BKGD_INDEX_FIRST."
   #endif
 #endif
 
diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp
index aa1ccb17c296..f43a6cc8a9bc 100644
--- a/Marlin/src/lcd/marlinui.cpp
+++ b/Marlin/src/lcd/marlinui.cpp
@@ -24,7 +24,7 @@
 
 #include "../MarlinCore.h" // for printingIsPaused
 
-#if LED_POWEROFF_TIMEOUT > 0 || BOTH(HAS_WIRED_LCD, PRINTER_EVENT_LEDS)
+#if LED_POWEROFF_TIMEOUT > 0 || BOTH(HAS_WIRED_LCD, PRINTER_EVENT_LEDS) || BOTH(LCD_BACKLIGHT_TIMEOUT_MINS, NEOPIXEL_BKGD_TIMEOUT_COLOR)
   #include "../feature/leds/leds.h"
 #endif
 
@@ -185,14 +185,29 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP;
 
 #if LCD_BACKLIGHT_TIMEOUT_MINS
 
-  constexpr uint8_t MarlinUI::backlight_timeout_min, MarlinUI::backlight_timeout_max;
-
-  uint8_t MarlinUI::backlight_timeout_minutes; // Initialized by settings.load()
-  millis_t MarlinUI::backlight_off_ms = 0;
-  void MarlinUI::refresh_backlight_timeout() {
-    backlight_off_ms = backlight_timeout_minutes ? millis() + backlight_timeout_minutes * 60UL * 1000UL : 0;
-    WRITE(LCD_BACKLIGHT_PIN, HIGH);
-  }
+  #ifdef NEOPIXEL_BKGD_INDEX_FIRST
+    
+    constexpr uint8_t MarlinUI::backlight_timeout_min, MarlinUI::backlight_timeout_max;
+  
+    uint8_t MarlinUI::backlight_timeout_minutes; // Initialized by settings.load()
+    millis_t MarlinUI::backlight_off_ms = 0;
+    void MarlinUI::refresh_backlight_timeout() {
+      backlight_off_ms = backlight_timeout_minutes ? millis() + backlight_timeout_minutes * 60UL * 1000UL : 0;
+      neo.reset_background_color();
+      neo.show();
+    }
+    
+  #elif PIN_EXISTS(LCD_BACKLIGHT)
+  
+    constexpr uint8_t MarlinUI::backlight_timeout_min, MarlinUI::backlight_timeout_max;
+  
+    uint8_t MarlinUI::backlight_timeout_minutes; // Initialized by settings.load()
+    millis_t MarlinUI::backlight_off_ms = 0;
+    void MarlinUI::refresh_backlight_timeout() {
+      backlight_off_ms = backlight_timeout_minutes ? millis() + backlight_timeout_minutes * 60UL * 1000UL : 0;
+      WRITE(LCD_BACKLIGHT_PIN, HIGH);
+    }
+  #endif
 
 #elif HAS_DISPLAY_SLEEP
 
@@ -1196,10 +1211,19 @@ void MarlinUI::init() {
       #endif
 
       #if LCD_BACKLIGHT_TIMEOUT_MINS
-        if (backlight_off_ms && ELAPSED(ms, backlight_off_ms)) {
-          WRITE(LCD_BACKLIGHT_PIN, LOW); // Backlight off
-          backlight_off_ms = 0;
-        }
+
+        #ifdef NEOPIXEL_BKGD_INDEX_FIRST   
+          if (backlight_off_ms && ELAPSED(ms, backlight_off_ms)) {
+            neo.set_background_off(); // Backlight off
+            neo.show();
+            backlight_off_ms = 0;
+          }
+        #elif PIN_EXIST(LCD_BACKLIGHT)
+          if (backlight_off_ms && ELAPSED(ms, backlight_off_ms)) {
+            WRITE(LCD_BACKLIGHT_PIN, LOW); // Backlight off
+            backlight_off_ms = 0;
+          }
+        #endif  
       #elif HAS_DISPLAY_SLEEP
         if (screen_timeout_millis && ELAPSED(ms, screen_timeout_millis))
           sleep_display();

From 1ba6c0686d974e4bc3dd5f08eb98625e9f131270 Mon Sep 17 00:00:00 2001
From: Scott Lahteine <thinkyhead@users.noreply.github.com>
Date: Sun, 26 Feb 2023 20:44:46 -0600
Subject: [PATCH 2/2] cleanup

---
 Marlin/Configuration.h               |  4 +--
 Marlin/src/feature/leds/neopixel.cpp | 20 +++++-------
 Marlin/src/feature/leds/neopixel.h   |  6 +---
 Marlin/src/lcd/marlinui.cpp          | 49 ++++++++++------------------
 buildroot/tests/LPC1768              |  2 +-
 5 files changed, 30 insertions(+), 51 deletions(-)

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 3b0daaf7fe0e..4d5af97469e6 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -3403,8 +3403,8 @@
   // Use some of the NeoPixel LEDs for static (background) lighting
   //#define NEOPIXEL_BKGD_INDEX_FIRST   0 // Index of the first background LED
   //#define NEOPIXEL_BKGD_INDEX_LAST    5 // Index of the last background LED
-  //#define NEOPIXEL_BKGD_COLOR { 255, 255, 255, 0 }  // R, G, B, W
-  //#define NEOPIXEL_BKGD_TIMEOUT_COLOR { 25, 25, 25, 0} // R, G, B, W
+  //#define NEOPIXEL_BKGD_COLOR         { 255, 255, 255, 0 }  // R, G, B, W
+  //#define NEOPIXEL_BKGD_TIMEOUT_COLOR {  25,  25,  25, 0 }  // R, G, B, W
   //#define NEOPIXEL_BKGD_ALWAYS_ON       // Keep the backlight on when other NeoPixels are off
 #endif
 
diff --git a/Marlin/src/feature/leds/neopixel.cpp b/Marlin/src/feature/leds/neopixel.cpp
index 6816ef23fac4..2193217df055 100644
--- a/Marlin/src/feature/leds/neopixel.cpp
+++ b/Marlin/src/feature/leds/neopixel.cpp
@@ -54,19 +54,15 @@ Adafruit_NeoPixel Marlin_NeoPixel::adaneo1(NEOPIXEL_PIXELS, NEOPIXEL_PIN, NEOPIX
     set_background_color(background_color);
   }
 
-  #ifdef NEOPIXEL_BKGD_TIMEOUT_COLOR
-   void Marlin_NeoPixel::set_background_off() {
-      constexpr uint8_t background_color_off[4] = NEOPIXEL_BKGD_TIMEOUT_COLOR;
-      set_background_color(background_color_off);
-    }
-  #else
-    void Marlin_NeoPixel::set_background_off() {
-      constexpr uint8_t background_color_off[4] = { 0, 0, 0, 0};
-      set_background_color(background_color_off);
-    }
-  #endif
+  void Marlin_NeoPixel::set_background_off() {
+    #ifndef NEOPIXEL_BKGD_TIMEOUT_COLOR
+      #define NEOPIXEL_BKGD_TIMEOUT_COLOR { 0, 0, 0, 0 }
+    #endif
+    constexpr uint8_t background_color_off[4] = NEOPIXEL_BKGD_TIMEOUT_COLOR;
+    set_background_color(background_color_off);
+  }
 
-#endif
+#endif // NEOPIXEL_BKGD_INDEX_FIRST
 
 void Marlin_NeoPixel::set_color(const uint32_t color) {
   if (neoindex >= 0) {
diff --git a/Marlin/src/feature/leds/neopixel.h b/Marlin/src/feature/leds/neopixel.h
index bd610a569ef9..7c8d018013fa 100644
--- a/Marlin/src/feature/leds/neopixel.h
+++ b/Marlin/src/feature/leds/neopixel.h
@@ -91,11 +91,7 @@ class Marlin_NeoPixel {
     static void set_background_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t w);
     static void set_background_color(const uint8_t (&rgbw)[4]) { set_background_color(rgbw[0], rgbw[1], rgbw[2], rgbw[3]); }
     static void reset_background_color();
-
-    #ifdef NEOPIXEL_BKGD_TIMEOUT_COLOR
-      static void set_background_off();
-    #endif
-
+    static void set_background_off();
   #endif
 
   static void begin() {
diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp
index f43a6cc8a9bc..d3f01e6d2322 100644
--- a/Marlin/src/lcd/marlinui.cpp
+++ b/Marlin/src/lcd/marlinui.cpp
@@ -24,7 +24,7 @@
 
 #include "../MarlinCore.h" // for printingIsPaused
 
-#if LED_POWEROFF_TIMEOUT > 0 || BOTH(HAS_WIRED_LCD, PRINTER_EVENT_LEDS) || BOTH(LCD_BACKLIGHT_TIMEOUT_MINS, NEOPIXEL_BKGD_TIMEOUT_COLOR)
+#if LED_POWEROFF_TIMEOUT > 0 || BOTH(HAS_WIRED_LCD, PRINTER_EVENT_LEDS) || (defined(LCD_BACKLIGHT_TIMEOUT_MINS) && defined(NEOPIXEL_BKGD_INDEX_FIRST))
   #include "../feature/leds/leds.h"
 #endif
 
@@ -185,29 +185,19 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP;
 
 #if LCD_BACKLIGHT_TIMEOUT_MINS
 
-  #ifdef NEOPIXEL_BKGD_INDEX_FIRST
-    
-    constexpr uint8_t MarlinUI::backlight_timeout_min, MarlinUI::backlight_timeout_max;
-  
-    uint8_t MarlinUI::backlight_timeout_minutes; // Initialized by settings.load()
-    millis_t MarlinUI::backlight_off_ms = 0;
-    void MarlinUI::refresh_backlight_timeout() {
-      backlight_off_ms = backlight_timeout_minutes ? millis() + backlight_timeout_minutes * 60UL * 1000UL : 0;
+  constexpr uint8_t MarlinUI::backlight_timeout_min, MarlinUI::backlight_timeout_max;
+  uint8_t MarlinUI::backlight_timeout_minutes; // Initialized by settings.load()
+  millis_t MarlinUI::backlight_off_ms = 0;
+
+  void MarlinUI::refresh_backlight_timeout() {
+    backlight_off_ms = backlight_timeout_minutes ? millis() + backlight_timeout_minutes * 60UL * 1000UL : 0;
+    #ifdef NEOPIXEL_BKGD_INDEX_FIRST
       neo.reset_background_color();
       neo.show();
-    }
-    
-  #elif PIN_EXISTS(LCD_BACKLIGHT)
-  
-    constexpr uint8_t MarlinUI::backlight_timeout_min, MarlinUI::backlight_timeout_max;
-  
-    uint8_t MarlinUI::backlight_timeout_minutes; // Initialized by settings.load()
-    millis_t MarlinUI::backlight_off_ms = 0;
-    void MarlinUI::refresh_backlight_timeout() {
-      backlight_off_ms = backlight_timeout_minutes ? millis() + backlight_timeout_minutes * 60UL * 1000UL : 0;
+    #elif PIN_EXISTS(LCD_BACKLIGHT)
       WRITE(LCD_BACKLIGHT_PIN, HIGH);
-    }
-  #endif
+    #endif
+  }
 
 #elif HAS_DISPLAY_SLEEP
 
@@ -1212,18 +1202,15 @@ void MarlinUI::init() {
 
       #if LCD_BACKLIGHT_TIMEOUT_MINS
 
-        #ifdef NEOPIXEL_BKGD_INDEX_FIRST   
-          if (backlight_off_ms && ELAPSED(ms, backlight_off_ms)) {
-            neo.set_background_off(); // Backlight off
+        if (backlight_off_ms && ELAPSED(ms, backlight_off_ms)) {
+          #ifdef NEOPIXEL_BKGD_INDEX_FIRST
+            neo.set_background_off();
             neo.show();
-            backlight_off_ms = 0;
-          }
-        #elif PIN_EXIST(LCD_BACKLIGHT)
-          if (backlight_off_ms && ELAPSED(ms, backlight_off_ms)) {
+          #elif PIN_EXIST(LCD_BACKLIGHT)
             WRITE(LCD_BACKLIGHT_PIN, LOW); // Backlight off
-            backlight_off_ms = 0;
-          }
-        #endif  
+          #endif
+          backlight_off_ms = 0;
+        }
       #elif HAS_DISPLAY_SLEEP
         if (screen_timeout_millis && ELAPSED(ms, screen_timeout_millis))
           sleep_display();
diff --git a/buildroot/tests/LPC1768 b/buildroot/tests/LPC1768
index 37cc705c0cb9..ee01bb621fcf 100755
--- a/buildroot/tests/LPC1768
+++ b/buildroot/tests/LPC1768
@@ -17,7 +17,7 @@ restore_configs
 opt_set MOTHERBOARD BOARD_RAMPS_14_RE_ARM_EFB SERIAL_PORT_3 3 \
         NEOPIXEL_TYPE NEO_RGB RGB_LED_R_PIN P2_12 RGB_LED_G_PIN P1_23 RGB_LED_B_PIN P1_22 RGB_LED_W_PIN P1_24
 opt_enable FYSETC_MINI_12864_2_1 SDSUPPORT SDCARD_READONLY SERIAL_PORT_2 RGBW_LED E_DUAL_STEPPER_DRIVERS \
-           NEOPIXEL_LED NEOPIXEL_IS_SEQUENTIAL NEOPIXEL_STARTUP_TEST NEOPIXEL_BKGD_INDEX_FIRST NEOPIXEL_BKGD_INDEX_LAST NEOPIXEL_BKGD_COLOR NEOPIXEL_BKGD_ALWAYS_ON
+           NEOPIXEL_LED NEOPIXEL_IS_SEQUENTIAL NEOPIXEL_STARTUP_TEST NEOPIXEL_BKGD_INDEX_FIRST NEOPIXEL_BKGD_INDEX_LAST NEOPIXEL_BKGD_COLOR NEOPIXEL_BKGD_TIMEOUT_COLOR NEOPIXEL_BKGD_ALWAYS_ON
 exec_test $1 $2 "ReARM EFB VIKI2, SDSUPPORT, 2 Serial ports (USB CDC + UART0), NeoPixel" "$3"
 
 #restore_configs