From f60914c7d09a7bca8b603d7940c677e9bdd95f32 Mon Sep 17 00:00:00 2001
From: moon2 <moon2protonmail@protonmail.com>
Date: Thu, 18 May 2023 23:52:19 +0200
Subject: [PATCH] added led support kinda

---
 components/badge23/CMakeLists.txt             |   1 +
 components/badge23/espan.c                    |   2 +-
 components/badge23/include/badge23/leds.h     |   1 -
 components/badge23/leds.c                     | 274 ++++++------------
 .../espressif__led_strip/CMakeLists.txt       |   4 +
 components/espressif__led_strip/README.md     |  16 +
 .../espressif__led_strip/idf_component.yml    |   7 +
 .../espressif__led_strip/include/led_strip.h  | 147 ++++++++++
 .../led_strip_rmt_ws2812.c                    | 208 +++++++++++++
 components/espressif__led_strip/license.txt   | 202 +++++++++++++
 10 files changed, 676 insertions(+), 186 deletions(-)
 create mode 100644 components/espressif__led_strip/CMakeLists.txt
 create mode 100644 components/espressif__led_strip/README.md
 create mode 100644 components/espressif__led_strip/idf_component.yml
 create mode 100644 components/espressif__led_strip/include/led_strip.h
 create mode 100644 components/espressif__led_strip/led_strip_rmt_ws2812.c
 create mode 100644 components/espressif__led_strip/license.txt

diff --git a/components/badge23/CMakeLists.txt b/components/badge23/CMakeLists.txt
index 31354d5922..60c1009dc4 100644
--- a/components/badge23/CMakeLists.txt
+++ b/components/badge23/CMakeLists.txt
@@ -12,4 +12,5 @@ idf_component_register(
         include
     REQUIRES
         gc9a01
+        espressif__led_strip
 )
diff --git a/components/badge23/espan.c b/components/badge23/espan.c
index d510579826..7d7afcf889 100644
--- a/components/badge23/espan.c
+++ b/components/badge23/espan.c
@@ -57,7 +57,7 @@ void os_app_main(void)
 
     set_global_vol_dB(-90);
     audio_init();
-    //leds_init();
+    leds_init();
     captouch_init();
 
     vTaskDelay(2000 / portTICK_PERIOD_MS);
diff --git a/components/badge23/include/badge23/leds.h b/components/badge23/include/badge23/leds.h
index f86056cb74..361f4ab1ae 100644
--- a/components/badge23/include/badge23/leds.h
+++ b/components/badge23/include/badge23/leds.h
@@ -2,7 +2,6 @@
 
 #include <stdint.h>
 void leds_init();
-void leds_animate(int leaf);
 void leds_set_single_rgb(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
 void leds_set_single_hsv(uint8_t index, float hue, float sat, float value);
 void leds_update();
diff --git a/components/badge23/leds.c b/components/badge23/leds.c
index 5148e44c67..7f8d09ea15 100644
--- a/components/badge23/leds.c
+++ b/components/badge23/leds.c
@@ -1,15 +1,20 @@
-#include "badge23/leds.h"
-
-#include "driver/spi_master.h"
-
 #include <freertos/FreeRTOS.h>
 #include <freertos/task.h>
 #include <freertos/queue.h>
 #include <stdio.h>
 #include <string.h>
 #include <math.h>
-
 #include "esp_system.h"
+#include "badge23/leds.h"
+#include "../../../revision_config.h"
+
+#ifdef HARDWARE_REVISION_01
+#define LED_SPI_PORT
+#endif
+
+#ifdef HARDWARE_REVISION_04
+#define LED_ASYNC_PORT
+#endif
 
 typedef struct leds_cfg {
     int             leaf;
@@ -19,25 +24,7 @@ typedef struct leds_cfg {
     int             timer;
 } leds_cfg_t;
 
-static QueueHandle_t leds_queue = NULL;
 static leds_cfg_t active_leds[11];
-static void leds_task(void* arg);
-
-#include "badge23/apa102LEDStrip.h"
-static struct apa102LEDStrip leds;
-
-//SPI Vars
-static spi_device_handle_t spi_led;
-static spi_transaction_t spiTransObject;
-static esp_err_t ret;
-static spi_bus_config_t buscfg;
-static spi_device_interface_config_t devcfg;
-
-#define totalPixels 40
-#define bytesPerPixel 4
-#define maxValuePerColour 255
-#define maxSPIFrameInBytes 8000
-#define maxSPIFrequency 10000000
 
 struct RGB
 {
@@ -128,6 +115,23 @@ struct RGB HSVToRGB(struct HSV hsv) {
     return rgb;
 }
 
+#ifdef LED_SPI_PORT
+#include "driver/spi_master.h"
+#include "badge23/apa102LEDStrip.h"
+
+#define totalPixels 40
+#define bytesPerPixel 4
+
+static struct apa102LEDStrip leds;
+static spi_device_handle_t spi_led;
+static spi_transaction_t spiTransObject;
+static esp_err_t ret;
+static spi_bus_config_t buscfg;
+static spi_device_interface_config_t devcfg;
+
+#define maxSPIFrameInBytes 8000
+#define maxSPIFrequency 10000000
+
 void renderLEDs()
 {
     spi_device_queue_trans(spi_led, &spiTransObject, portMAX_DELAY);
@@ -158,75 +162,9 @@ static int setupSPI()
     return ret;
 }
 
-static uint8_t black[] = {0,0,0};
-
-static const uint8_t pl[][9] = {
-                          {39,  0,  1,  2,  3,  4,  5,  6,  7},
-                          {3,   4,  5,  6,  7,  8,  9, 10, 11},
-                          {7,   8,  9, 10, 11, 12, 13, 14, 15},
-                          {11, 12, 13, 14, 15, 16, 17, 18, 19},
-                          {15, 16, 17, 18, 19, 20, 21, 22, 23},
-                          {19, 20, 21, 22, 23, 24, 25, 26, 27},
-                          {23, 24, 25, 26, 27, 28, 29, 30, 31},
-                          {27, 28, 29, 30, 31, 32, 33, 34, 35},
-                          {31, 32, 33, 34, 35, 36, 37, 38, 39},
-                          {35, 36, 37, 38, 39, 0,   1,  2,  3}
-                          };
-
-static const int8_t pan_leds[][11][2] = {
-                          {
-                                {pl[0][4], pl[0][4]}, {pl[0][3], pl[0][5]}, {pl[0][2], pl[0][6]}, {pl[0][1], pl[0][7]}, {pl[0][0], pl[0][8]},
-                                    {pl[4][0], pl[6][8]}, {pl[4][1], pl[6][7]}, {pl[4][2], pl[6][6]}, {pl[4][3], pl[6][5]}, {pl[4][4], pl[6][4]}
-                                ,{-1, -1}
-                          },
-                          {
-                                {pl[2][4], pl[0][4]}, {pl[2][3], pl[0][5]}, {pl[2][2], pl[0][6]}, {pl[2][1], pl[0][7]}, {pl[2][0], pl[0][8]},
-                                    {pl[6][8], pl[6][0]}, {pl[6][6], pl[6][1]}, {pl[6][6], pl[6][2]}, {pl[6][5], pl[6][3]}, {pl[6][4], pl[6][4]}
-                                ,{-1, -1}
-                          },
-                          {
-                                {pl[2][4], pl[2][4]}, {pl[2][3], pl[2][5]}, {pl[2][2], pl[2][6]}, {pl[2][1], pl[2][7]}, {pl[2][0], pl[2][8]},
-                                    {pl[6][0], pl[8][8]}, {pl[6][1], pl[8][7]}, {pl[6][2], pl[8][6]}, {pl[6][3], pl[8][5]}, {pl[6][4], pl[8][4]}
-                                ,{-1, -1}
-                          },
-                          {
-                                {pl[4][4], pl[2][4]}, {pl[4][3], pl[2][5]}, {pl[4][2], pl[2][6]}, {pl[4][1], pl[2][7]}, {pl[4][0], pl[2][8]},
-                                    {pl[8][8], pl[8][0]}, {pl[8][6], pl[8][1]}, {pl[8][6], pl[8][2]}, {pl[8][5], pl[8][3]}, {pl[8][4], pl[8][4]}
-                                ,{-1, -1}
-                          },
-                          {
-                                {pl[4][4], pl[4][4]}, {pl[4][3], pl[4][5]}, {pl[4][2], pl[4][6]}, {pl[4][1], pl[4][7]}, {pl[4][0], pl[4][8]},
-                                    {pl[8][0], pl[0][8]}, {pl[8][1], pl[0][7]}, {pl[8][2], pl[0][6]}, {pl[8][3], pl[0][5]}, {pl[8][4], pl[0][4]}
-                                ,{-1, -1}
-                          },
-                          {
-                                {pl[6][4], pl[4][4]}, {pl[6][3], pl[4][5]}, {pl[6][2], pl[4][6]}, {pl[6][1], pl[4][7]}, {pl[6][0], pl[4][8]},
-                                    {pl[0][8], pl[0][0]}, {pl[0][6], pl[0][1]}, {pl[0][6], pl[0][2]}, {pl[0][5], pl[0][3]}, {pl[0][4], pl[0][4]}
-                                ,{-1, -1}
-                          },
-                          {
-                                {pl[6][4], pl[6][4]}, {pl[6][3], pl[6][5]}, {pl[6][2], pl[6][6]}, {pl[6][1], pl[6][7]}, {pl[6][0], pl[6][8]},
-                                    {pl[0][0], pl[6][2]}, {pl[0][1], pl[2][7]}, {pl[0][2], pl[2][6]}, {pl[0][3], pl[2][5]}, {pl[0][4], pl[2][4]}
-                                ,{-1, -1}
-                          },
-                          {
-                                {pl[8][4], pl[6][4]}, {pl[8][3], pl[6][5]}, {pl[8][2], pl[6][6]}, {pl[8][1], pl[6][7]}, {pl[8][0], pl[6][8]},
-                                    {pl[2][8], pl[2][0]}, {pl[2][6], pl[2][1]}, {pl[2][6], pl[2][2]}, {pl[2][5], pl[2][3]}, {pl[2][4], pl[2][4]}
-                                ,{-1, -1}
-                          },
-                          {
-                                {pl[8][4], pl[8][4]}, {pl[8][3], pl[8][5]}, {pl[8][2], pl[8][6]}, {pl[8][1], pl[8][7]}, {pl[8][0], pl[8][8]},
-                                    {pl[2][0], pl[4][4]}, {pl[2][1], pl[4][7]}, {pl[2][2], pl[4][6]}, {pl[2][3], pl[4][5]}, {pl[2][4], pl[4][4]}
-                                ,{-1, -1}
-                          },
-                          {
-                                {pl[0][4], pl[8][4]}, {pl[0][3], pl[8][5]}, {pl[0][2], pl[8][6]}, {pl[0][1], pl[8][7]}, {pl[0][0], pl[8][8]},
-                                    {pl[4][8], pl[4][0]}, {pl[4][6], pl[4][1]}, {pl[4][6], pl[4][2]}, {pl[4][5], pl[4][3]}, {pl[4][4], pl[4][4]}
-                                ,{-1, -1}
-                          },
-
-                          };
-
+static void set_single_led(uint8_t index, uint8_t[3] c){
+    setPixel(&leds, index, c);
+}
 
 static void _leds_init() {
     leds_queue = xQueueCreate(10, sizeof(leds_cfg_t));
@@ -244,105 +182,82 @@ static void _leds_init() {
     TaskHandle_t handle;
     //xTaskCreate(&leds_task, "LEDs player", 4096, NULL, configMAX_PRIORITIES - 2, &handle);
 }
+#endif
+
+#ifdef LED_ASYNC_PORT
+#include "../../espressif__led_strip/include/led_strip.h"
+led_strip_t *led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num);
+
+#define LED_GPIO_NUM 14
+#define LED_RMT_CHAN 0
+
+#if 0
+//ESP-IDF 5.0 for reference
+led_strip_handle_t led_strip;
+
+/* LED strip initialization with the GPIO and pixels number*/
+led_strip_config_t strip_config = {
+    .strip_gpio_num = 14, // The GPIO that connected to the LED strip's data line
+    .max_leds = 40, // The number of LEDs in the strip,
+    .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip
+    .led_model = LED_MODEL_WS2812, // LED strip model
+    .flags.invert_out = false, // whether to invert the output signal (useful when your hardware has a level inverter)
+};
 
-static bool leds_active(void)
-{
-    for(size_t i=0; i<sizeof(active_leds) / sizeof(active_leds[0]); i++) {
-        if(active_leds[i].size != active_leds[i].position) {
-            return true;
-        }
-    }
-    return false;
-}
-
-
-static void leds_task(void* arg) {
-    leds_cfg_t  leds_;
-
-    static int timer = 0;
-
-    while(true) {
-        if(xQueueReceive(leds_queue, &leds_, 1)) {
-            leds_.position = 0;
-            active_leds[leds_.slot] = leds_;
-        }
-
-        if(leds_active()) {
-            for(int i=0; i<40; i++) {
-                setPixel(&leds, i, black);
-            }
-
-            for(size_t i=0; i<sizeof(active_leds) / sizeof(active_leds[0]); i++) {
-                if(active_leds[i].size == active_leds[i].position) continue;
-
-                int leaf = active_leds[i].leaf;
-                int position = active_leds[i].position;
-
-                uint8_t c[] = {0,0,0};
-                if(leaf % 2 == 0)
-                    c[0] = 32;
-                else
-                    c[2] = 32;
-
-                struct RGB rgb = HSVToRGB((struct HSV){leaf/9.*360,1,1});
-                c[0] = rgb.R / 4;
-                c[1] = rgb.G / 4;
-                c[2] = rgb.B / 4;
-
-                if(pan_leds[leaf][position][0] >= 0)
-                    setPixel(&leds, pan_leds[leaf][position][0], c);
-                if(pan_leds[leaf][position][1] >= 0)
-                    setPixel(&leds, pan_leds[leaf][position][1], c);
+led_strip_rmt_config_t rmt_config = {
+    .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption
+    .resolution_hz = 10 * 1000 * 1000, // 10MHz
+    .flags.with_dma = true, // whether to enable the DMA feature
+};
 
-                if(active_leds[i].timer-- == 0) {
-                    active_leds[i].timer = 2;
-                    active_leds[i].position += 1;
-                }
+static void renderLEDs()
+{
+    ESP_ERROR_CHECK(led_strip_refresh(led_strip));
 
-            }
+}
 
-            renderLEDs();
-            timer = 30;
-        }
+void set_single_led(int led, uint8_t c[3])
+{
+    led = ((39-led) + 1 + 32)%40;
+    ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, led, c[0], c[1], c[2]));
+}
 
-        static int phase = 0;
+static void _leds_init() {
+    memset(active_leds, 0 , sizeof(active_leds));
 
-        if(!leds_active()) {
-            // background anim
+    ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
 
-            if(timer-- == 0) {
-                timer = 60;
-                for(int i=0; i<40; i++) {
-                    setPixel(&leds, i, black);
-                }
+    TaskHandle_t handle;
+    xTaskCreate(&leds_task, "LEDs player", 4096, NULL, configMAX_PRIORITIES - 2, &handle);
+}
+#endif
 
-                if(phase++ == 360) {
-                    phase = 0;
-                }
+led_strip_t * led_strip;
 
-                uint8_t c[] = {0,0,0};
+static void _leds_init(){
+    memset(active_leds, 0 , sizeof(active_leds));
+    led_strip = led_strip_init(LED_RMT_CHAN, LED_GPIO_NUM, 40);
+}
 
-                for(int i=0; i<40; i++) {
-                    struct RGB rgb = HSVToRGB((struct HSV){(phase+i*3) % 360,1,0.125});
-                    c[0] = rgb.R / 1;
-                    c[1] = rgb.G / 1;
-                    c[2] = rgb.B / 1;
-                    setPixel(&leds, i, c);
-                }
+void set_single_led(uint8_t index, uint8_t c[3]){
+    index = ((39-index) + 1 + 32)%40;
+    led_strip->set_pixel(led_strip, index, c[0], c[1], c[2]);
+}
 
-                renderLEDs();
-            }
-        }
-    }
+static void renderLEDs(){
+    led_strip->refresh(led_strip, 1000);
 }
 
+#endif
+
 void leds_set_single_rgb(uint8_t index, uint8_t red, uint8_t green, uint8_t blue){
     uint8_t c[3];
     c[0] = red;
     c[1] = green;
     c[2] = blue;
-    setPixel(&leds, index, c);
+    set_single_led(index, c);
 }
+ 
 void leds_set_single_hsv(uint8_t index, float hue, float sat, float val){
     struct RGB rgb;
     struct HSV hsv;
@@ -356,22 +271,13 @@ void leds_set_single_hsv(uint8_t index, float hue, float sat, float val){
     c[0] = rgb.R;
     c[1] = rgb.G;
     c[2] = rgb.B;
-    setPixel(&leds, index, c);
+    set_single_led(index, c);
 }
 
 void leds_update(){
-    vTaskDelay(10 / portTICK_PERIOD_MS);
+    vTaskDelay(10 / portTICK_PERIOD_MS); //do we...
     renderLEDs();
-    vTaskDelay(10 / portTICK_PERIOD_MS);
+    vTaskDelay(10 / portTICK_PERIOD_MS); //...need these?
 }
 
 void leds_init() { _leds_init(); }
-
-void leds_animate(int leaf) {
-    leds_cfg_t leds = {0,};
-
-    leds.leaf = leaf;
-    leds.slot = leaf;
-    leds.size = 11;
-    xQueueSend(leds_queue, &leds, 0);
-}
diff --git a/components/espressif__led_strip/CMakeLists.txt b/components/espressif__led_strip/CMakeLists.txt
new file mode 100644
index 0000000000..fe4ca413a2
--- /dev/null
+++ b/components/espressif__led_strip/CMakeLists.txt
@@ -0,0 +1,4 @@
+idf_component_register(SRCS "led_strip_rmt_ws2812.c"
+                    INCLUDE_DIRS "include"
+                    PRIV_REQUIRES "driver"
+                    )
diff --git a/components/espressif__led_strip/README.md b/components/espressif__led_strip/README.md
new file mode 100644
index 0000000000..abf07898a5
--- /dev/null
+++ b/components/espressif__led_strip/README.md
@@ -0,0 +1,16 @@
+# LED Strip Component
+
+This directory contains an implementation for addressable LEDs using the RMT peripheral.
+
+It's compatible with:
+
+* [WS2812](http://www.world-semi.com/Certifications/WS2812B.html)
+* SK68XX
+
+This component is used as part of the following ESP-IDF examples:
+- [Blink Example](../../get-started/blink).
+- [LED Strip Example](../../peripherals/rmt/led_strip).
+
+To learn more about how to use this component, please check API Documentation from header file [led_strip.h](./include/led_strip.h).
+
+Please note that this component is not considered to be a part of ESP-IDF stable API. It may change and it may be removed in the future releases.
diff --git a/components/espressif__led_strip/idf_component.yml b/components/espressif__led_strip/idf_component.yml
new file mode 100644
index 0000000000..8d2fc65337
--- /dev/null
+++ b/components/espressif__led_strip/idf_component.yml
@@ -0,0 +1,7 @@
+version: "1.1.0-alpha"
+description: C driver, based on RMT peripheral, for WS2812 and SK6812 smart RGB diodes
+
+dependencies:
+  # Required IDF version
+  idf:
+    version: ">=4.0"
diff --git a/components/espressif__led_strip/include/led_strip.h b/components/espressif__led_strip/include/led_strip.h
new file mode 100644
index 0000000000..dcf7a62f8a
--- /dev/null
+++ b/components/espressif__led_strip/include/led_strip.h
@@ -0,0 +1,147 @@
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "esp_err.h"
+
+/**
+* @brief LED Strip Type
+*
+*/
+typedef struct led_strip_s led_strip_t;
+
+/**
+* @brief LED Strip Device Type
+*
+*/
+typedef void *led_strip_dev_t;
+
+/**
+* @brief Declare of LED Strip Type
+*
+*/
+struct led_strip_s {
+    /**
+    * @brief Set RGB for a specific pixel
+    *
+    * @param strip: LED strip
+    * @param index: index of pixel to set
+    * @param red: red part of color
+    * @param green: green part of color
+    * @param blue: blue part of color
+    *
+    * @return
+    *      - ESP_OK: Set RGB for a specific pixel successfully
+    *      - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters
+    *      - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred
+    */
+    esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
+
+    /**
+    * @brief Refresh memory colors to LEDs
+    *
+    * @param strip: LED strip
+    * @param timeout_ms: timeout value for refreshing task
+    *
+    * @return
+    *      - ESP_OK: Refresh successfully
+    *      - ESP_ERR_TIMEOUT: Refresh failed because of timeout
+    *      - ESP_FAIL: Refresh failed because some other error occurred
+    *
+    * @note:
+    *      After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.
+    */
+    esp_err_t (*refresh)(led_strip_t *strip, uint32_t timeout_ms);
+
+    /**
+    * @brief Clear LED strip (turn off all LEDs)
+    *
+    * @param strip: LED strip
+    * @param timeout_ms: timeout value for clearing task
+    *
+    * @return
+    *      - ESP_OK: Clear LEDs successfully
+    *      - ESP_ERR_TIMEOUT: Clear LEDs failed because of timeout
+    *      - ESP_FAIL: Clear LEDs failed because some other error occurred
+    */
+    esp_err_t (*clear)(led_strip_t *strip, uint32_t timeout_ms);
+
+    /**
+    * @brief Free LED strip resources
+    *
+    * @param strip: LED strip
+    *
+    * @return
+    *      - ESP_OK: Free resources successfully
+    *      - ESP_FAIL: Free resources failed because error occurred
+    */
+    esp_err_t (*del)(led_strip_t *strip);
+};
+
+/**
+* @brief LED Strip Configuration Type
+*
+*/
+typedef struct {
+    uint32_t max_leds;   /*!< Maximum LEDs in a single strip */
+    led_strip_dev_t dev; /*!< LED strip device (e.g. RMT channel, PWM channel, etc) */
+} led_strip_config_t;
+
+/**
+ * @brief Default configuration for LED strip
+ *
+ */
+#define LED_STRIP_DEFAULT_CONFIG(number, dev_hdl) \
+    {                                             \
+        .max_leds = number,                       \
+        .dev = dev_hdl,                           \
+    }
+
+/**
+* @brief Install a new ws2812 driver (based on RMT peripheral)
+*
+* @param config: LED strip configuration
+* @return
+*      LED strip instance or NULL
+*/
+led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config);
+
+/**
+ * @brief Init the RMT peripheral and LED strip configuration.
+ *
+ * @param[in] channel: RMT peripheral channel number.
+ * @param[in] gpio: GPIO number for the RMT data output.
+ * @param[in] led_num: number of addressable LEDs.
+ * @return
+ *      LED strip instance or NULL
+ */
+led_strip_t *led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num);
+
+/**
+ * @brief Denit the RMT peripheral.
+ *
+ * @param[in] strip: LED strip
+ * @return
+ *     - ESP_OK
+ *     - ESP_FAIL
+ */
+esp_err_t led_strip_denit(led_strip_t *strip);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/components/espressif__led_strip/led_strip_rmt_ws2812.c b/components/espressif__led_strip/led_strip_rmt_ws2812.c
new file mode 100644
index 0000000000..08c3dab499
--- /dev/null
+++ b/components/espressif__led_strip/led_strip_rmt_ws2812.c
@@ -0,0 +1,208 @@
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <stdlib.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include "esp_log.h"
+#include "esp_attr.h"
+#include "led_strip.h"
+#include "driver/rmt.h"
+
+#define RMT_TX_CHANNEL RMT_CHANNEL_0
+
+static const char *TAG = "ws2812";
+#define STRIP_CHECK(a, str, goto_tag, ret_value, ...)                             \
+    do                                                                            \
+    {                                                                             \
+        if (!(a))                                                                 \
+        {                                                                         \
+            ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+            ret = ret_value;                                                      \
+            goto goto_tag;                                                        \
+        }                                                                         \
+    } while (0)
+
+#define WS2812_T0H_NS (350)
+#define WS2812_T0L_NS (1000)
+#define WS2812_T1H_NS (1000)
+#define WS2812_T1L_NS (350)
+#define WS2812_RESET_US (280)
+
+static uint32_t ws2812_t0h_ticks = 0;
+static uint32_t ws2812_t1h_ticks = 0;
+static uint32_t ws2812_t0l_ticks = 0;
+static uint32_t ws2812_t1l_ticks = 0;
+
+typedef struct {
+    led_strip_t parent;
+    rmt_channel_t rmt_channel;
+    uint32_t strip_len;
+    uint8_t buffer[0];
+} ws2812_t;
+
+/**
+ * @brief Conver RGB data to RMT format.
+ *
+ * @note For WS2812, R,G,B each contains 256 different choices (i.e. uint8_t)
+ *
+ * @param[in] src: source data, to converted to RMT format
+ * @param[in] dest: place where to store the convert result
+ * @param[in] src_size: size of source data
+ * @param[in] wanted_num: number of RMT items that want to get
+ * @param[out] translated_size: number of source data that got converted
+ * @param[out] item_num: number of RMT items which are converted from source data
+ */
+static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size,
+        size_t wanted_num, size_t *translated_size, size_t *item_num)
+{
+    if (src == NULL || dest == NULL) {
+        *translated_size = 0;
+        *item_num = 0;
+        return;
+    }
+    const rmt_item32_t bit0 = {{{ ws2812_t0h_ticks, 1, ws2812_t0l_ticks, 0 }}}; //Logical 0
+    const rmt_item32_t bit1 = {{{ ws2812_t1h_ticks, 1, ws2812_t1l_ticks, 0 }}}; //Logical 1
+    size_t size = 0;
+    size_t num = 0;
+    uint8_t *psrc = (uint8_t *)src;
+    rmt_item32_t *pdest = dest;
+    while (size < src_size && num < wanted_num) {
+        for (int i = 0; i < 8; i++) {
+            // MSB first
+            if (*psrc & (1 << (7 - i))) {
+                pdest->val =  bit1.val;
+            } else {
+                pdest->val =  bit0.val;
+            }
+            num++;
+            pdest++;
+        }
+        size++;
+        psrc++;
+    }
+    *translated_size = size;
+    *item_num = num;
+}
+
+static esp_err_t ws2812_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
+{
+    esp_err_t ret = ESP_OK;
+    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
+    STRIP_CHECK(index < ws2812->strip_len, "index out of the maximum number of leds", err, ESP_ERR_INVALID_ARG);
+    uint32_t start = index * 3;
+    // In thr order of GRB
+    ws2812->buffer[start + 0] = green & 0xFF;
+    ws2812->buffer[start + 1] = red & 0xFF;
+    ws2812->buffer[start + 2] = blue & 0xFF;
+    return ESP_OK;
+err:
+    return ret;
+}
+
+static esp_err_t ws2812_refresh(led_strip_t *strip, uint32_t timeout_ms)
+{
+    esp_err_t ret = ESP_OK;
+    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
+    STRIP_CHECK(rmt_write_sample(ws2812->rmt_channel, ws2812->buffer, ws2812->strip_len * 3, true) == ESP_OK,
+                "transmit RMT samples failed", err, ESP_FAIL);
+    return rmt_wait_tx_done(ws2812->rmt_channel, pdMS_TO_TICKS(timeout_ms));
+err:
+    return ret;
+}
+
+static esp_err_t ws2812_clear(led_strip_t *strip, uint32_t timeout_ms)
+{
+    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
+    // Write zero to turn off all leds
+    memset(ws2812->buffer, 0, ws2812->strip_len * 3);
+    return ws2812_refresh(strip, timeout_ms);
+}
+
+static esp_err_t ws2812_del(led_strip_t *strip)
+{
+    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
+    free(ws2812);
+    return ESP_OK;
+}
+
+led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config)
+{
+    led_strip_t *ret = NULL;
+    STRIP_CHECK(config, "configuration can't be null", err, NULL);
+
+    // 24 bits per led
+    uint32_t ws2812_size = sizeof(ws2812_t) + config->max_leds * 3;
+    ws2812_t *ws2812 = calloc(1, ws2812_size);
+    STRIP_CHECK(ws2812, "request memory for ws2812 failed", err, NULL);
+
+    uint32_t counter_clk_hz = 0;
+    STRIP_CHECK(rmt_get_counter_clock((rmt_channel_t)config->dev, &counter_clk_hz) == ESP_OK,
+                "get rmt counter clock failed", err, NULL);
+    // ns -> ticks
+    float ratio = (float)counter_clk_hz / 1e9;
+    ws2812_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS);
+    ws2812_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS);
+    ws2812_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS);
+    ws2812_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS);
+
+    // set ws2812 to rmt adapter
+    rmt_translator_init((rmt_channel_t)config->dev, ws2812_rmt_adapter);
+
+    ws2812->rmt_channel = (rmt_channel_t)config->dev;
+    ws2812->strip_len = config->max_leds;
+
+    ws2812->parent.set_pixel = ws2812_set_pixel;
+    ws2812->parent.refresh = ws2812_refresh;
+    ws2812->parent.clear = ws2812_clear;
+    ws2812->parent.del = ws2812_del;
+
+    return &ws2812->parent;
+err:
+    return ret;
+}
+
+led_strip_t *led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num)
+{
+    static led_strip_t *pStrip;
+
+    rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio, channel);
+    // set counter clock to 40MHz
+    config.clk_div = 2;
+
+    ESP_ERROR_CHECK(rmt_config(&config));
+    ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
+
+    // install ws2812 driver
+    led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(led_num, (led_strip_dev_t)config.channel);
+
+    pStrip = led_strip_new_rmt_ws2812(&strip_config);
+
+    if ( !pStrip ) {
+        ESP_LOGE(TAG, "install WS2812 driver failed");
+        return NULL;
+    }
+
+    // Clear LED strip (turn off all LEDs)
+    // This will fail for inverted output
+    //ESP_ERROR_CHECK(pStrip->clear(pStrip, 100));
+
+    return pStrip;
+}
+
+esp_err_t led_strip_denit(led_strip_t *strip)
+{
+    ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
+    ESP_ERROR_CHECK(rmt_driver_uninstall(ws2812->rmt_channel));
+    return strip->del(strip);
+}
diff --git a/components/espressif__led_strip/license.txt b/components/espressif__led_strip/license.txt
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/components/espressif__led_strip/license.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
-- 
GitLab