From 7196f1312508bdb04d8e943572773a5f23c8509e Mon Sep 17 00:00:00 2001
From: qwertymodo <qwertymodo@gmail.com>
Date: Fri, 5 Aug 2022 22:07:30 -0700
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20M150=20K=20=E2=80=93=20Keep=20unspe?=
 =?UTF-8?q?cified=20components=20(#24315)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 Marlin/src/feature/leds/neopixel.h     |  8 ++++++++
 Marlin/src/gcode/feature/leds/M150.cpp | 21 +++++++++++++--------
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/Marlin/src/feature/leds/neopixel.h b/Marlin/src/feature/leds/neopixel.h
index d71aa25770f..2048e2c2eeb 100644
--- a/Marlin/src/feature/leds/neopixel.h
+++ b/Marlin/src/feature/leds/neopixel.h
@@ -131,6 +131,13 @@ public:
   // Accessors
   static uint16_t pixels() { return adaneo1.numPixels() * TERN1(NEOPIXEL2_INSERIES, 2); }
 
+  static uint32_t pixel_color(const uint16_t n) {
+    #if ENABLED(NEOPIXEL2_INSERIES)
+      if (n >= NEOPIXEL_PIXELS) return adaneo2.getPixelColor(n - (NEOPIXEL_PIXELS));
+    #endif
+    return adaneo1.getPixelColor(n);
+  }
+
   static uint8_t brightness() { return adaneo1.getBrightness(); }
 
   static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w)) {
@@ -174,6 +181,7 @@ extern Marlin_NeoPixel neo;
 
     // Accessors
     static uint16_t pixels() { return adaneo.numPixels();}
+    static uint32_t pixel_color(const uint16_t n) { return adaneo.getPixelColor(n); }
     static uint8_t brightness() { return adaneo.getBrightness(); }
     static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED2, uint8_t w)) {
       return adaneo.Color(r, g, b OPTARG(HAS_WHITE_LED2, w));
diff --git a/Marlin/src/gcode/feature/leds/M150.cpp b/Marlin/src/gcode/feature/leds/M150.cpp
index 95e7367b6e2..77c58411a37 100644
--- a/Marlin/src/gcode/feature/leds/M150.cpp
+++ b/Marlin/src/gcode/feature/leds/M150.cpp
@@ -31,11 +31,13 @@
  * M150: Set Status LED Color - Use R-U-B-W for R-G-B-W
  *       and Brightness       - Use P (for NEOPIXEL only)
  *
- * Always sets all 3 or 4 components. If a component is left out, set to 0.
- *                                    If brightness is left out, no value changed
+ * Always sets all 3 or 4 components unless the K flag is specified.
+ *                              If a component is left out, set to 0.
+ *                              If brightness is left out, no value changed.
  *
  * With NEOPIXEL_LED:
  *  I<index>  Set the NeoPixel index to affect. Default: All
+ *  K         Keep all unspecified values unchanged instead of setting to 0.
  *
  * With NEOPIXEL2_SEPARATE:
  *  S<index>  The NeoPixel strip to set. Default: All.
@@ -51,16 +53,19 @@
  *   M150 P          ; Set LED full brightness
  *   M150 I1 R       ; Set NEOPIXEL index 1 to red
  *   M150 S1 I1 R    ; Set SEPARATE index 1 to red
+ *   M150 K R127     ; Set LED red to 50% without changing blue or green
  */
 void GcodeSuite::M150() {
+  int32_t old_color = 0;
+
   #if ENABLED(NEOPIXEL_LED)
     const pixel_index_t index = parser.intval('I', -1);
     #if ENABLED(NEOPIXEL2_SEPARATE)
       int8_t brightness = neo.brightness(), unit = parser.intval('S', -1);
       switch (unit) {
         case -1: neo2.neoindex = index; // fall-thru
-        case  0:  neo.neoindex = index; break;
-        case  1: neo2.neoindex = index; brightness = neo2.brightness(); break;
+        case  0:  neo.neoindex = index; old_color = parser.seen('K') ? neo.pixel_color(index >= 0 ? index : 0) : 0; break;
+        case  1: neo2.neoindex = index; brightness = neo2.brightness(); old_color = parser.seen('K') ? neo2.pixel_color(index >= 0 ? index : 0) : 0; break;
       }
     #else
       const uint8_t brightness = neo.brightness();
@@ -69,10 +74,10 @@ void GcodeSuite::M150() {
   #endif
 
   const LEDColor color = LEDColor(
-    parser.seen('R') ? (parser.has_value() ? parser.value_byte() : 255) : 0,
-    parser.seen('U') ? (parser.has_value() ? parser.value_byte() : 255) : 0,
-    parser.seen('B') ? (parser.has_value() ? parser.value_byte() : 255) : 0
-    OPTARG(HAS_WHITE_LED, parser.seen('W') ? (parser.has_value() ? parser.value_byte() : 255) : 0)
+    parser.seen('R') ? (parser.has_value() ? parser.value_byte() : 255) : (old_color >> 16) & 0xFF,
+    parser.seen('U') ? (parser.has_value() ? parser.value_byte() : 255) : (old_color >>  8) & 0xFF,
+    parser.seen('B') ? (parser.has_value() ? parser.value_byte() : 255) : old_color & 0xFF
+    OPTARG(HAS_WHITE_LED, parser.seen('W') ? (parser.has_value() ? parser.value_byte() : 255) : (old_color >> 24) & 0xFF)
     OPTARG(NEOPIXEL_LED, parser.seen('P') ? (parser.has_value() ? parser.value_byte() : 255) : brightness)
   );