From e24b6579fff04e59e5bfde7e222a93165383d5e5 Mon Sep 17 00:00:00 2001
From: Erwin Boskma <erwin@datarift.nl>
Date: Sun, 8 Oct 2017 20:02:39 +0200
Subject: [PATCH] Added support for RGBW NeoPixels (#449)

---
 examples/ws2812_i2s/ws2812_i2s_colour_loop.c | 18 +++++++++++++-----
 extras/ws2812_i2s/ws2812_i2s.c               | 16 +++++++++++-----
 extras/ws2812_i2s/ws2812_i2s.h               | 10 ++++++++--
 3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/examples/ws2812_i2s/ws2812_i2s_colour_loop.c b/examples/ws2812_i2s/ws2812_i2s_colour_loop.c
index 05f47c4..c5b5411 100644
--- a/examples/ws2812_i2s/ws2812_i2s_colour_loop.c
+++ b/examples/ws2812_i2s/ws2812_i2s_colour_loop.c
@@ -17,7 +17,7 @@
 
 #include "ws2812_i2s/ws2812_i2s.h"
 
-const uint32_t led_number = 60;
+const uint32_t led_number = 12;
 const uint32_t tail_fade_factor = 2;
 const uint32_t tail_length = 8;
 
@@ -41,7 +41,7 @@ static int fix_index(int index)
 
 static ws2812_pixel_t next_colour()
 {
-    ws2812_pixel_t colour = {0, 0, 0};
+    ws2812_pixel_t colour = {0, 0, 0, 0};
     colour.red = rand() % 256;
     colour.green = rand() % 256;
     colour.blue = rand() % 256;
@@ -54,7 +54,7 @@ static void demo(void *pvParameters)
     ws2812_pixel_t pixels[led_number];
     int head_index = 0;
 
-    ws2812_i2s_init(led_number);
+    ws2812_i2s_init(led_number, PIXEL_RGB);
 
     memset(pixels, 0, sizeof(ws2812_pixel_t) * led_number);    
 
@@ -69,8 +69,8 @@ static void demo(void *pvParameters)
             memset(&pixels[fix_index(head_index - tail_length)], 0, 
                     sizeof(ws2812_pixel_t));
 
-            ws2812_i2s_update(pixels);
-            vTaskDelay(20 / portTICK_PERIOD_MS);
+            ws2812_i2s_update(pixels, PIXEL_RGB);
+            vTaskDelay(50 / portTICK_PERIOD_MS);
         }
     }
 }
@@ -78,6 +78,14 @@ static void demo(void *pvParameters)
 void user_init(void)
 {
     uart_set_baud(0, 115200);
+    struct sdk_station_config config = {
+        .ssid = "Loading...",
+        .password = "morays59924_howitzer",
+    };
+
+    /* required to call wifi_set_opmode before station_set_config */
+    sdk_wifi_set_opmode(STATION_MODE);
+    sdk_wifi_station_set_config(&config);
 
     xTaskCreate(&demo, "ws2812_i2s", 256, NULL, 10, NULL);
 }
diff --git a/extras/ws2812_i2s/ws2812_i2s.c b/extras/ws2812_i2s/ws2812_i2s.c
index 712c894..62dc496 100644
--- a/extras/ws2812_i2s/ws2812_i2s.c
+++ b/extras/ws2812_i2s/ws2812_i2s.c
@@ -37,7 +37,7 @@
 #endif
 
 #define MAX_DMA_BLOCK_SIZE      4095
-#define DMA_PIXEL_SIZE          12    // each colour takes 4 bytes
+// #define DMA_PIXEL_SIZE          16    // each colour takes 4 bytes
 
 /**
  * Amount of zero data to produce WS2812 reset condition.
@@ -117,9 +117,9 @@ static inline void init_descriptors_list(uint8_t *buf, uint32_t total_dma_data_s
     }
 }
 
-void ws2812_i2s_init(uint32_t pixels_number)
+void ws2812_i2s_init(uint32_t pixels_number, pixeltype_t type)
 {
-    dma_buffer_size = pixels_number * DMA_PIXEL_SIZE;
+    dma_buffer_size = pixels_number * type;
     dma_block_list_size = dma_buffer_size / MAX_DMA_BLOCK_SIZE;
 
     if (dma_buffer_size % MAX_DMA_BLOCK_SIZE) {
@@ -156,13 +156,13 @@ const IRAM_DATA int16_t bitpatterns[16] =
     0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
 };
 
-void ws2812_i2s_update(ws2812_pixel_t *pixels)
+void ws2812_i2s_update(ws2812_pixel_t *pixels, pixeltype_t type)
 {
     while (i2s_dma_processing) {};
 
     uint16_t *p_dma_buf = dma_buffer;
 
-    for (uint32_t i = 0; i < (dma_buffer_size / DMA_PIXEL_SIZE); i++) {
+    for (uint32_t i = 0; i < (dma_buffer_size / type); i++) {
         // green
         *p_dma_buf++ =  bitpatterns[pixels[i].green & 0x0F];
         *p_dma_buf++ =  bitpatterns[pixels[i].green >> 4];
@@ -174,6 +174,12 @@ void ws2812_i2s_update(ws2812_pixel_t *pixels)
         // blue
         *p_dma_buf++ =  bitpatterns[pixels[i].blue & 0x0F];
         *p_dma_buf++ =  bitpatterns[pixels[i].blue >> 4];
+        
+        if(type == PIXEL_RGBW) {
+          // white
+          *p_dma_buf++ =  bitpatterns[pixels[i].white & 0x0F];
+          *p_dma_buf++ =  bitpatterns[pixels[i].white >> 4];
+        }
     }
 
     i2s_dma_processing = true;
diff --git a/extras/ws2812_i2s/ws2812_i2s.h b/extras/ws2812_i2s/ws2812_i2s.h
index f6ebc82..16956dc 100644
--- a/extras/ws2812_i2s/ws2812_i2s.h
+++ b/extras/ws2812_i2s/ws2812_i2s.h
@@ -35,8 +35,14 @@ typedef struct {
     uint8_t red;
     uint8_t green;
     uint8_t blue;
+    uint8_t white;
 } ws2812_pixel_t;
 
+typedef enum {
+  PIXEL_RGB = 12,
+  PIXEL_RGBW = 16
+} pixeltype_t;
+
 /**
  * Initialize i2s and dma subsystems to work with ws2812 led strip.
  *
@@ -44,7 +50,7 @@ typedef struct {
  *
  * @param pixels_number Number of pixels in the strip.
  */
-void ws2812_i2s_init(uint32_t pixels_number);
+void ws2812_i2s_init(uint32_t pixels_number, pixeltype_t type);
 
 /**
  * Update ws2812 pixels.
@@ -52,7 +58,7 @@ void ws2812_i2s_init(uint32_t pixels_number);
  * @param pixels Array of 'pixels_number' pixels. The array must contain all
  * the pixels.
  */
-void ws2812_i2s_update(ws2812_pixel_t *pixels);
+void ws2812_i2s_update(ws2812_pixel_t *pixels, pixeltype_t type);
 
 #ifdef	__cplusplus
 }