Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WS2812FX virtual strip and mixing GRB and BGR #345

Closed
happy77fr opened this issue Jan 9, 2024 · 3 comments
Closed

WS2812FX virtual strip and mixing GRB and BGR #345

happy77fr opened this issue Jan 9, 2024 · 3 comments

Comments

@happy77fr
Copy link

happy77fr commented Jan 9, 2024

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);`

@moose4lord
Copy link
Collaborator

moose4lord commented Jan 9, 2024

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.

@happy77fr
Copy link
Author

Thank you! I couldn't test this tonight but I will come back soon

@happy77fr
Copy link
Author

It works! Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants