diff --git a/src/led_color_order.c b/src/led_color_order.c
new file mode 100644
index 00000000..37fca313
--- /dev/null
+++ b/src/led_color_order.c
@@ -0,0 +1,59 @@
+// Copyright 2026 Michael Conrad
+//
+// This file is part of the Refloat VESC package.
+//
+// Refloat VESC package 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.
+//
+// Refloat VESC package 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 "led_color_order.h"
+
+static uint32_t color_grb(uint8_t w, uint8_t r, uint8_t g, uint8_t b) {
+ (void) w;
+ return ((uint32_t) g << 16) | ((uint32_t) r << 8) | b;
+}
+
+static uint32_t color_grbw(uint8_t w, uint8_t r, uint8_t g, uint8_t b) {
+ return ((uint32_t) g << 24) | ((uint32_t) r << 16) | ((uint32_t) b << 8) | w;
+}
+
+static uint32_t color_rgb(uint8_t w, uint8_t r, uint8_t g, uint8_t b) {
+ (void) w;
+ return ((uint32_t) r << 16) | ((uint32_t) g << 8) | b;
+}
+
+static uint32_t color_wrgb(uint8_t w, uint8_t r, uint8_t g, uint8_t b) {
+ return ((uint32_t) w << 24) | ((uint32_t) r << 16) | ((uint32_t) g << 8) | b;
+}
+
+bool led_color_order_resolve(LedColorOrder order, uint8_t *bits, LedColorConverter *converter) {
+ switch (order) {
+ case LED_COLOR_GRB:
+ *bits = 24;
+ *converter = color_grb;
+ return true;
+ case LED_COLOR_GRBW:
+ *bits = 32;
+ *converter = color_grbw;
+ return true;
+ case LED_COLOR_RGB:
+ *bits = 24;
+ *converter = color_rgb;
+ return true;
+ case LED_COLOR_WRGB:
+ *bits = 32;
+ *converter = color_wrgb;
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/led_color_order.h b/src/led_color_order.h
new file mode 100644
index 00000000..926075dc
--- /dev/null
+++ b/src/led_color_order.h
@@ -0,0 +1,27 @@
+// Copyright 2026 Michael Conrad
+//
+// This file is part of the Refloat VESC package.
+//
+// Refloat VESC package 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.
+//
+// Refloat VESC package 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 "conf/datatypes.h"
+
+#include
+#include
+
+typedef uint32_t (*LedColorConverter)(uint8_t w, uint8_t r, uint8_t g, uint8_t b);
+
+bool led_color_order_resolve(LedColorOrder order, uint8_t *bits, LedColorConverter *converter);
diff --git a/src/led_driver.c b/src/led_driver.c
index c1492ab6..eb7f95e4 100644
--- a/src/led_driver.c
+++ b/src/led_driver.c
@@ -166,20 +166,6 @@ static void deinit_hw(const PinHwConfig *cfg) {
disable_dma_stream(cfg);
}
-inline static uint8_t color_order_bits(LedColorOrder order) {
- switch (order) {
- case LED_COLOR_GRBW:
- case LED_COLOR_WRGB:
- return 32;
- case LED_COLOR_GRB:
- case LED_COLOR_RGB:
- return 24;
- }
-
- // the switch above should be exhaustive, just silence the warning
- return 24;
-}
-
void led_driver_init(LedDriver *driver) {
driver->bitbuffer_length = 0;
driver->bitbuffer = NULL;
@@ -192,6 +178,7 @@ bool led_driver_setup(
log_error("Invalid LED pin configured: %u", pin);
return false;
}
+
driver->pin_hw_config = &pin_hw_configs[pin];
driver->bitbuffer_length = 0;
@@ -207,7 +194,7 @@ bool led_driver_setup(
driver->strips[i] = strip;
offsets[i] = driver->bitbuffer_length;
- driver->bitbuffer_length += color_order_bits(strip->color_order) * strip->length;
+ driver->bitbuffer_length += strip->color_bits * strip->length;
}
// An extra array item to set the output to 0 PWM
@@ -239,24 +226,6 @@ inline static uint8_t cgamma(uint8_t c) {
return (c * c + c) / 256;
}
-static uint32_t color_grb(uint8_t w, uint8_t r, uint8_t g, uint8_t b) {
- unused(w);
- return (g << 16) | (r << 8) | b;
-}
-
-static uint32_t color_grbw(uint8_t w, uint8_t r, uint8_t g, uint8_t b) {
- return (g << 24) | (r << 16) | (b << 8) | w;
-}
-
-static uint32_t color_rgb(uint8_t w, uint8_t r, uint8_t g, uint8_t b) {
- unused(w);
- return (r << 16) | (g << 8) | b;
-}
-
-static uint32_t color_wrgb(uint8_t w, uint8_t r, uint8_t g, uint8_t b) {
- return (w << 24) | (r << 16) | (g << 8) | b;
-}
-
void led_driver_paint(LedDriver *driver) {
if (!driver->bitbuffer) {
return;
@@ -268,23 +237,6 @@ void led_driver_paint(LedDriver *driver) {
break;
}
- uint32_t (*color_conv)(uint8_t, uint8_t, uint8_t, uint8_t);
- switch (strip->color_order) {
- case LED_COLOR_GRB:
- color_conv = color_grb;
- break;
- case LED_COLOR_GRBW:
- color_conv = color_grbw;
- break;
- case LED_COLOR_RGB:
- color_conv = color_rgb;
- break;
- case LED_COLOR_WRGB:
- color_conv = color_wrgb;
- break;
- }
-
- uint8_t bits = color_order_bits(strip->color_order);
uint16_t *strip_bitbuffer = driver->strip_bitbuffs[i];
for (uint32_t j = 0; j < strip->length; ++j) {
@@ -294,10 +246,11 @@ void led_driver_paint(LedDriver *driver) {
uint8_t g = cgamma((color >> 8) & 0xFF);
uint8_t b = cgamma(color & 0xFF);
- color = color_conv(w, r, g, b);
+ color = strip->color_conv(w, r, g, b);
- for (int8_t bit = bits - 1; bit >= 0; --bit) {
- strip_bitbuffer[bit + j * bits] = color & 0x1 ? WS2812_ONE : WS2812_ZERO;
+ for (int8_t bit = strip->color_bits - 1; bit >= 0; --bit) {
+ strip_bitbuffer[bit + j * strip->color_bits] =
+ color & 0x1 ? WS2812_ONE : WS2812_ZERO;
color >>= 1;
}
}
diff --git a/src/led_strip.c b/src/led_strip.c
index 83782c4b..5d32e941 100644
--- a/src/led_strip.c
+++ b/src/led_strip.c
@@ -22,12 +22,20 @@
void led_strip_init(LedStrip *strip) {
strip->data = NULL;
strip->length = 0;
- strip->color_order = LED_COLOR_GRB;
+ led_color_order_resolve(LED_COLOR_GRB, &strip->color_bits, &strip->color_conv);
strip->reverse = false;
}
-void led_strip_configure(LedStrip *strip, const CfgLedStrip *cfg) {
+bool led_strip_configure(LedStrip *strip, const CfgLedStrip *cfg) {
+ uint8_t color_bits;
+ LedColorConverter color_conv;
+ if (!led_color_order_resolve(cfg->color_order, &color_bits, &color_conv)) {
+ return false;
+ }
+
strip->length = cfg->count;
- strip->color_order = cfg->color_order;
+ strip->color_bits = color_bits;
+ strip->color_conv = color_conv;
strip->reverse = cfg->reverse;
+ return true;
}
diff --git a/src/led_strip.h b/src/led_strip.h
index ec4125f0..cecce0b3 100644
--- a/src/led_strip.h
+++ b/src/led_strip.h
@@ -17,8 +17,9 @@
#pragma once
-#include "conf/datatypes.h"
+#include "led_color_order.h"
+#include
#include
#define STRIP_COUNT 3
@@ -35,7 +36,8 @@ typedef union {
typedef struct {
uint32_t *data;
uint8_t length;
- LedColorOrder color_order;
+ uint8_t color_bits;
+ LedColorConverter color_conv;
bool reverse;
float brightness;
TransitionData trans_data;
@@ -43,4 +45,4 @@ typedef struct {
void led_strip_init(LedStrip *strip);
-void led_strip_configure(LedStrip *strip, const CfgLedStrip *cfg);
+bool led_strip_configure(LedStrip *strip, const CfgLedStrip *cfg);
diff --git a/src/leds.c b/src/leds.c
index a998edac..c3d18088 100644
--- a/src/leds.c
+++ b/src/leds.c
@@ -836,6 +836,15 @@ void leds_init(Leds *leds) {
led_driver_init(&leds->led_driver);
}
+static bool configure_strip(LedStrip *strip, const CfgLedStrip *cfg, const char *name) {
+ if (led_strip_configure(strip, cfg)) {
+ return true;
+ }
+
+ log_error("Invalid %s LED color order: %u.", name, cfg->color_order);
+ return false;
+}
+
void leds_setup(Leds *leds, CfgHwLeds *hw_cfg, const CfgLeds *cfg) {
uint8_t status_offset = 0;
uint8_t front_offset = 0;
@@ -846,17 +855,23 @@ void leds_setup(Leds *leds, CfgHwLeds *hw_cfg, const CfgLeds *cfg) {
size_t strip_i = 0;
for (uint8_t i = 1; i <= STRIP_COUNT; ++i) {
if (hw_cfg->status.order == i && hw_cfg->status.count > 0) {
- led_strip_configure(&leds->status_strip, &hw_cfg->status);
+ if (!configure_strip(&leds->status_strip, &hw_cfg->status, "status")) {
+ return;
+ }
status_offset = current_offset;
current_offset += leds->status_strip.length;
strip_array[strip_i++] = &leds->status_strip;
} else if (hw_cfg->front.order == i && hw_cfg->front.count > 0) {
- led_strip_configure(&leds->front_strip, &hw_cfg->front);
+ if (!configure_strip(&leds->front_strip, &hw_cfg->front, "front")) {
+ return;
+ }
front_offset = current_offset;
current_offset += leds->front_strip.length;
strip_array[strip_i++] = &leds->front_strip;
} else if (hw_cfg->rear.order == i && hw_cfg->rear.count > 0) {
- led_strip_configure(&leds->rear_strip, &hw_cfg->rear);
+ if (!configure_strip(&leds->rear_strip, &hw_cfg->rear, "rear")) {
+ return;
+ }
rear_offset = current_offset;
current_offset += leds->rear_strip.length;
strip_array[strip_i++] = &leds->rear_strip;