WS2812FX virtual strip and mixing GRB and BGR
happy77fr opened this issue · comments
Hello,
I couldn't find a way to have a virtual strip mixing GRB and BGR led strips.
The virtual strip works with only one color scheme.
Is there a way to solve this issue?
Here is the code:
`WS2812FX ws2812fx_v1 = WS2812FX(LED_COUNT_P1 + LED_COUNT_P2 + LED_COUNT_P3 + LED_COUNT_P4, LED_PIN_V1, NEO_GRB + NEO_KHZ800, 1, 1);
WS2812FX ws2812fx_p1 = WS2812FX(1, LED_PIN_P1, NEO_GRB + NEO_KHZ800, 1, 1);
WS2812FX ws2812fx_p2 = WS2812FX(1, LED_PIN_P2, NEO_GRB + NEO_KHZ800, 1, 1);
WS2812FX ws2812fx_p3 = WS2812FX(1, LED_PIN_P3, NEO_BGR + NEO_KHZ800, 1, 1);
WS2812FX ws2812fx_p4 = WS2812FX(1, LED_PIN_P4, NEO_BGR + NEO_KHZ800, 1, 1);`
Unfortunately, the virtual strip example sketch doesn't do any translation between virtual and physical strips. It just maps the virtual data array directly to the physical strip's data array.
I played around with it a little and you can do a messy data copy between virtual and physical strips that handles different RGB types. This is what I came up with:
#include <WS2812FX.h>
#define LED_PIN_V1 22 // virtual digital pin used to drive the virtual LED strip
#define LED_PIN_P1 22 // physical digital pin used to drive the first physical LED strip
#define LED_PIN_P2 21 // physical digital pin used to drive the second physical LED strip
#define LED_PIN_P3 19 // physical digital pin used to drive the second physical LED strip
#define LED_PIN_P4 17 // physical digital pin used to drive the second physical LED strip
#define LED_COUNT_P1 16 // number of LEDs on the first physical strip
#define LED_COUNT_P2 16 // number of LEDs on the second physical strip
#define LED_COUNT_P3 16 // number of LEDs on the third physical strip
#define LED_COUNT_P4 16 // number of LEDs on the fourth physical strip
#define LED_TYPE_V1 NEO_GRB + NEO_KHZ800 // LED type of the virtual strip
#define LED_TYPE_P1 NEO_GRB + NEO_KHZ800 // LED type of the first physical strip
#define LED_TYPE_P2 NEO_GRB + NEO_KHZ800 // LED type of the second physical strip
#define LED_TYPE_P3 NEO_BGR + NEO_KHZ800 // LED type of the third physical strip
#define LED_TYPE_P4 NEO_BGR + NEO_KHZ800 // LED type of the fourth physical strip
#define DATA_PIN_MOSFET 23
// create an instance of one virtual strip and four physical strips.
// (Note the instances are created with support of only one segment and one
// segment_runtime, just so the sketch fits in an Arduino's limited SRAM.)
WS2812FX ws2812fx_v1 = WS2812FX(LED_COUNT_P1 + LED_COUNT_P2 + LED_COUNT_P3 + LED_COUNT_P4, LED_PIN_V1, LED_TYPE_V1, 1, 1);
WS2812FX ws2812fx_p1 = WS2812FX(LED_COUNT_P1, LED_PIN_P1, LED_TYPE_P1, 1, 1);
WS2812FX ws2812fx_p2 = WS2812FX(LED_COUNT_P2, LED_PIN_P2, LED_TYPE_P2, 1, 1);
WS2812FX ws2812fx_p3 = WS2812FX(LED_COUNT_P3, LED_PIN_P3, LED_TYPE_P3, 1, 1);
WS2812FX ws2812fx_p4 = WS2812FX(LED_COUNT_P4, LED_PIN_P4, LED_TYPE_P4, 1, 1);
void setup() {
#ifdef DATA_PIN_MOSFET
pinMode(DATA_PIN_MOSFET, OUTPUT); // MOSFET GPIO
digitalWrite(DATA_PIN_MOSFET, LOW); // MOSFET on
delay(10);
#endif
// initialize the virtual strip as you would any normal ws2812fx instance
ws2812fx_v1.init();
ws2812fx_v1.setBrightness(255);
ws2812fx_v1.setSegment(0, 0, ws2812fx_v1.getLength()-1, FX_MODE_COMET, RED, 2000);
ws2812fx_v1.start();
// init the physical strip's GPIOs
ws2812fx_p1.init();
ws2812fx_p2.init();
ws2812fx_p3.init();
ws2812fx_p4.init();
// config a custom show() function for the virtual strip, so pixel
// data gets copied to the physical strip's data array
ws2812fx_v1.setCustomShow(myCustomShow);
}
void loop() {
// update the virtual strip's pixel data by calling service() as you normally would
ws2812fx_v1.service();
}
void myCustomShow(void) {
uint8_t *v_ptr = ws2812fx_v1.getPixels();
// map first physical strip
mapLEDs(ws2812fx_p1.getPixels(), v_ptr, ws2812fx_p1.getNumBytes(), LED_TYPE_P1, LED_TYPE_V1);
// map second physical strip
v_ptr += ws2812fx_p1.getNumBytes();
mapLEDs(ws2812fx_p2.getPixels(), v_ptr, ws2812fx_p2.getNumBytes(), LED_TYPE_P2, LED_TYPE_V1);
// map third physical strip
v_ptr += ws2812fx_p2.getNumBytes();
mapLEDs(ws2812fx_p3.getPixels(), v_ptr, ws2812fx_p3.getNumBytes(), LED_TYPE_P3, LED_TYPE_V1);
// map fourth physical strip
v_ptr += ws2812fx_p3.getNumBytes();
mapLEDs(ws2812fx_p4.getPixels(), v_ptr, ws2812fx_p4.getNumBytes(), LED_TYPE_P4, LED_TYPE_V1);
// Call the physical strip's show() function.
// Note: the virtual strip's show() functions are never called.
ws2812fx_p1.Adafruit_NeoPixel::show();
ws2812fx_p2.Adafruit_NeoPixel::show();
ws2812fx_p3.Adafruit_NeoPixel::show();
ws2812fx_p4.Adafruit_NeoPixel::show();
}
// map the virtual strip data to the physical strip
void mapLEDs(uint8_t *p, uint8_t *v, uint16_t byteCnt, neoPixelType p_type, neoPixelType v_type) {
if(p_type == v_type) {
memmove(p, v, byteCnt); // if the v and p strips are the same type, just do a memcopy
} else {
uint8_t rOffset_p = (p_type >> 4) & 0b11; // types are different, so do the GRB to BGR mapping
uint8_t gOffset_p = (p_type >> 2) & 0b11;
uint8_t bOffset_p = p_type & 0b11;
uint8_t rOffset_v = (v_type >> 4) & 0b11;
uint8_t gOffset_v = (v_type >> 2) & 0b11;
uint8_t bOffset_v = v_type & 0b11;
for(int i=0; i < byteCnt; i += 3) {
p[rOffset_p + i] = v[rOffset_v + i];
p[gOffset_p + i] = v[gOffset_v + i];
p[bOffset_p + i] = v[bOffset_v + i];
}
}
}
The Adafruit_NeoPixel lib doesn't expose the LED type parameter, so it's a bit of a hack to make it work.
Thank you! I couldn't test this tonight but I will come back soon
It works! Thank you