Browse Source

add addressable led on led API including green/red + make rmt properly shared accross services

philippe44 1 year ago
parent
commit
c7e4d9711c

+ 5 - 9
components/led_strip/led_vu.c

@@ -21,6 +21,7 @@
 #include <math.h>
 #include "esp_log.h"
 
+#include "globdefs.h"
 #include "led_strip.h"
 #include "platform_config.h"
 #include "led_vu.h"
@@ -28,7 +29,6 @@
 static const char *TAG = "led_vu";
 
 #define LED_VU_STACK_SIZE 	(3*1024)
-#define LED_VU_RMT_INTR_NUM 20U
 
 #define LED_VU_PEAK_HOLD 6U
 
@@ -39,12 +39,6 @@ static const char *TAG = "led_vu";
 #define max(a,b) (((a) > (b)) ? (a) : (b))
 
 struct led_strip_t* led_display = NULL;
-static EXT_RAM_ATTR struct led_strip_t  led_strip_config = {
-    .rgb_led_type      = RGB_LED_TYPE_WS2812,
-    .rmt_channel       = RMT_CHANNEL_1,
-    .rmt_interrupt_num = LED_VU_RMT_INTR_NUM,
-    .gpio              = -1,
-};
 
 static EXT_RAM_ATTR struct {
     int gpio;
@@ -96,24 +90,26 @@ void led_vu_init()
     strip.vu_odd = strip.length - 1;
 
     // create driver configuration
+    struct led_strip_t led_strip_config = { .rgb_led_type = RGB_LED_TYPE_WS2812 };
     led_strip_config.access_semaphore = xSemaphoreCreateBinary();
     led_strip_config.led_strip_length = strip.length;
     led_strip_config.led_strip_working = heap_caps_malloc(strip.length * sizeof(struct led_color_t), MALLOC_CAP_8BIT);
     led_strip_config.led_strip_showing = heap_caps_malloc(strip.length * sizeof(struct led_color_t), MALLOC_CAP_8BIT);
     led_strip_config.gpio = strip.gpio;
+    led_strip_config.rmt_channel = rmt_system_base_channel++;
 
     // initialize driver 
     bool led_init_ok = led_strip_init(&led_strip_config);
     if (led_init_ok) {
         led_display = &led_strip_config;
-        ESP_LOGI(TAG, "led_vu using gpio:%d length:%d", strip.gpio, strip.length);
+        ESP_LOGI(TAG, "led_vu using gpio:%d length:%d on channek:%d", strip.gpio, strip.length, led_strip_config.rmt_channel);
     } else {
         ESP_LOGE(TAG, "led_vu init failed");
         goto done;
     }
 
     // reserver max memory for remote management systems
-    rmt_set_mem_block_num(RMT_CHANNEL_1, 7);
+    rmt_set_mem_block_num(led_strip_config.rmt_channel, 7);
 
     led_vu_clear(led_display);
 

+ 1 - 0
components/services/globdefs.h

@@ -17,6 +17,7 @@ extern int i2c_system_port;
 extern int i2c_system_speed;
 extern int spi_system_host;
 extern int spi_system_dc_gpio;
+extern int rmt_system_base_channel;
 typedef struct {
 	int timer, base_channel, max;
 } pwm_system_t;

+ 8 - 8
components/services/infrared.c

@@ -14,6 +14,7 @@
 #include "esp_err.h"
 #include "esp_log.h"
 #include "driver/rmt.h"
+#include "globdefs.h"
 #include "infrared.h"
 
 static const char* TAG = "IR";
@@ -83,8 +84,6 @@ typedef struct {
 
 ir_parser_t *ir_parser = NULL;
 
-#define RMT_RX_CHANNEL    0     /*!< RMT channel for receiver */
-
 #define RMT_CHECK(a, str, goto_tag, ret_value, ...)                               \
     do                                                                            \
     {                                                                             \
@@ -481,10 +480,9 @@ void infrared_receive(RingbufHandle_t rb, infrared_handler handler) {
 /****************************************************************************************
  * 
  */
-void infrared_init(RingbufHandle_t *rb, int gpio, infrared_mode_t mode) { 
-    ESP_LOGI(TAG, "Starting Infrared Receiver mode %s on gpio %d", mode == IR_NEC ? "nec" : "rc5", gpio);
-    
-    rmt_config_t rmt_rx_config = RMT_DEFAULT_CONFIG_RX(gpio, RMT_RX_CHANNEL);
+void infrared_init(RingbufHandle_t *rb, int gpio, infrared_mode_t mode) {  
+    int rmt_channel = rmt_system_base_channel++;
+    rmt_config_t rmt_rx_config = RMT_DEFAULT_CONFIG_RX(gpio, rmt_channel);
     rmt_config(&rmt_rx_config);
     rmt_driver_install(rmt_rx_config.channel, 1000, 0);
     ir_parser_config_t ir_parser_config = IR_PARSER_DEFAULT_CONFIG((ir_dev_t) rmt_rx_config.channel);
@@ -493,6 +491,8 @@ void infrared_init(RingbufHandle_t *rb, int gpio, infrared_mode_t mode) {
     ir_parser = (mode == IR_NEC) ? ir_parser_rmt_new_nec(&ir_parser_config) : ir_parser_rmt_new_rc5(&ir_parser_config);
     
     // get RMT RX ringbuffer
-    rmt_get_ringbuf_handle(RMT_RX_CHANNEL, rb);
-    rmt_rx_start(RMT_RX_CHANNEL, 1);
+    rmt_get_ringbuf_handle(rmt_channel, rb);
+    rmt_rx_start(rmt_channel, 1);
+    
+    ESP_LOGI(TAG, "Starting Infrared Receiver mode %s on gpio %d and channel %d", mode == IR_NEC ? "nec" : "rc5", gpio, rmt_channel);
 }

+ 160 - 82
components/services/led.c

@@ -18,6 +18,7 @@
 #include "esp_log.h"
 #include "driver/gpio.h"
 #include "driver/ledc.h"
+#include "driver/rmt.h"
 #include "platform_config.h"
 #include "gpio_exp.h"
 #include "led.h"
@@ -31,90 +32,130 @@
 #define LEDC_SPEED_MODE LEDC_LOW_SPEED_MODE
 #else
 #define LEDC_SPEED_MODE LEDC_HIGH_SPEED_MODE
-#endif                
+#endif
 
 static const char *TAG = "led";
 
+#define RMT_CLK (40/2)
+
+static int8_t led_rmt_channel = -1;
+static uint32_t scale24(uint32_t bright, uint8_t);
+
+static const struct rmt_led_param_s {
+    led_type_t type;
+    uint8_t bits;
+    // number of ticks in nanoseconds converted in RMT_CLK ticks
+    rmt_item32_t bit_0;
+    rmt_item32_t bit_1;
+    uint32_t green, red;
+    uint32_t (*scale)(uint32_t, uint8_t);
+} rmt_led_param[] =  {
+    { LED_WS2812, 24, {{{350 / RMT_CLK, 1, 1000 / RMT_CLK, 0}}}, {{{1000 / RMT_CLK, 1, 350 / RMT_CLK, 0}}}, 0xff0000, 0x00ff00, scale24 },
+    { .type = -1 } };
+
 static EXT_RAM_ATTR struct led_s {
 	gpio_num_t gpio;
 	bool on;
-	int onstate;
+	uint32_t color;
 	int ontime, offtime;
-	int pwm;
+	int bright;
 	int channel;
+    const struct rmt_led_param_s *rmt;
 	int pushedon, pushedoff;
 	bool pushed;
 	TimerHandle_t timer;
 } leds[MAX_LED];
 
 // can't use EXT_RAM_ATTR for initialized structure
-static struct {
+static struct led_config_s {
 	int gpio;
-	int active;
-	int pwm;
-} green = { .gpio = CONFIG_LED_GREEN_GPIO, .active = 0, .pwm = -1 },
-  red = { .gpio = CONFIG_LED_RED_GPIO, .active = 0, .pwm = -1 };
-  
+	int color;
+	int bright;
+    led_type_t type;
+} green = { .gpio = CONFIG_LED_GREEN_GPIO, .color = 0, .bright = -1, .type = LED_GPIO },
+  red = { .gpio = CONFIG_LED_RED_GPIO, .color = 0, .bright = -1, .type = LED_GPIO };
+
 static int led_max = 2;
 
 /****************************************************************************************
- * 
+ *
+ */
+static uint32_t scale24(uint32_t color, uint8_t scale) {
+    uint32_t scaled = (((color & 0xff0000) >> 16) * scale / 100) << 16;
+    scaled |= (((color & 0xff00) >> 8) * scale / 100) << 8;
+    scaled |= (color & 0xff) * scale / 100;
+    return scaled;
+}
+
+/****************************************************************************************
+ *
  */
 static void set_level(struct led_s *led, bool on) {
-	if (led->pwm < 0 || led->gpio >= GPIO_NUM_MAX) gpio_set_level_x(led->gpio, on ? led->onstate : !led->onstate);
-	else {
-		ledc_set_duty(LEDC_SPEED_MODE, led->channel, on ? led->pwm : (led->onstate ? 0 : pwm_system.max));
+    if (led->rmt) {
+        uint32_t data = on ? led->rmt->scale(led->color, led->bright) : 0;
+        uint32_t mask = 1 << (led->rmt->bits - 1);
+        rmt_item32_t buffer[led->rmt->bits];
+        for (uint32_t bit = 0; bit < led->rmt->bits; bit++) {
+            uint32_t set = data & mask;
+            buffer[bit] = set ? led->rmt->bit_1 : led->rmt->bit_0;
+            mask >>= 1;
+        }
+        rmt_write_items(led->channel, buffer, led->rmt->bits, false);
+    } else if (led->bright < 0 || led->gpio >= GPIO_NUM_MAX) {
+        gpio_set_level_x(led->gpio, on ? led->color : !led->color);
+	} else {
+		ledc_set_duty(LEDC_SPEED_MODE, led->channel, on ? led->bright : (led->color ? 0 : pwm_system.max));
 		ledc_update_duty(LEDC_SPEED_MODE, led->channel);
-	}		
+	}
 }
 
 /****************************************************************************************
- * 
+ *
  */
 static void vCallbackFunction( TimerHandle_t xTimer ) {
 	struct led_s *led = (struct led_s*) pvTimerGetTimerID (xTimer);
-	
+
 	if (!led->timer) return;
-	
+
 	led->on = !led->on;
-	ESP_EARLY_LOGD(TAG,"led vCallbackFunction setting gpio %d level %d (pwm:%d)", led->gpio, led->on, led->pwm);
+	ESP_EARLY_LOGD(TAG,"led vCallbackFunction setting gpio %d level %d (bright:%d)", led->gpio, led->on, led->bright);
 	set_level(led, led->on);
-		
+
 	// was just on for a while
 	if (!led->on && led->offtime == -1) return;
-	
+
 	// regular blinking
 	xTimerChangePeriod(xTimer, (led->on ? led->ontime : led->offtime) / portTICK_RATE_MS, BLOCKTIME);
 }
 
 /****************************************************************************************
- * 
+ *
  */
 bool led_blink_core(int idx, int ontime, int offtime, bool pushed) {
 	if (!leds[idx].gpio || leds[idx].gpio < 0 ) return false;
-	
+
 	ESP_LOGD(TAG,"led_blink_core %d on:%d off:%d, pushed:%u", idx, ontime, offtime, pushed);
 	if (leds[idx].timer) {
 		// normal requests waits if a pop is pending
 		if (!pushed && leds[idx].pushed) {
-			leds[idx].pushedon = ontime; 
-			leds[idx].pushedoff = offtime; 
+			leds[idx].pushedon = ontime;
+			leds[idx].pushedoff = offtime;
 			return true;
 		}
 		xTimerStop(leds[idx].timer, BLOCKTIME);
 	}
-	
+
 	// save current state if not already pushed
 	if (!leds[idx].pushed) {
 		leds[idx].pushedon = leds[idx].ontime;
-		leds[idx].pushedoff = leds[idx].offtime;	
+		leds[idx].pushedoff = leds[idx].offtime;
 		leds[idx].pushed = pushed;
-	}	
-	
+	}
+
 	// then set new one
 	leds[idx].ontime = ontime;
-	leds[idx].offtime = offtime;	
-			
+	leds[idx].offtime = offtime;
+
 	if (ontime == 0) {
 		ESP_LOGD(TAG,"led %d, setting reverse level", idx);
 		set_level(leds + idx, false);
@@ -132,39 +173,44 @@ bool led_blink_core(int idx, int ontime, int offtime, bool pushed) {
         ESP_LOGD(TAG,"led %d, Setting gpio %d and starting timer", idx, leds[idx].gpio);
 		if (xTimerStart(leds[idx].timer, BLOCKTIME) == pdFAIL) return false;
 	}
-	
-	
+
+
 	return true;
-} 
+}
 
 /****************************************************************************************
- * 
+ *
  */
-bool led_brightness(int idx, int pwm) {
-	if (pwm > 100) pwm = 100;
-	leds[idx].pwm = pwm_system.max * powf(pwm / 100.0, 3);
-	if (!leds[idx].onstate) leds[idx].pwm = pwm_system.max - leds[idx].pwm;
-	
-	ledc_set_duty(LEDC_SPEED_MODE, leds[idx].channel, leds[idx].pwm);
-	ledc_update_duty(LEDC_SPEED_MODE, leds[idx].channel);
-	
+bool led_brightness(int idx, int bright) {
+	if (bright > 100) bright = 100;
+
+    if (leds[idx].rmt) {
+        leds[idx].bright = bright;
+    } else {
+        leds[idx].bright = pwm_system.max * powf(bright / 100.0, 3);
+        if (!leds[idx].color) leds[idx].bright = pwm_system.max - leds[idx].bright;
+
+        ledc_set_duty(LEDC_SPEED_MODE, leds[idx].channel, leds[idx].bright);
+        ledc_update_duty(LEDC_SPEED_MODE, leds[idx].channel);
+    }
+
 	return true;
 }
 
 /****************************************************************************************
- * 
+ *
  */
 bool led_unpush(int idx) {
 	if (!leds[idx].gpio || leds[idx].gpio<0) return false;
-	
+
 	led_blink_core(idx, leds[idx].pushedon, leds[idx].pushedoff, true);
 	leds[idx].pushed = false;
-	
+
 	return true;
-}	
+}
 
 /****************************************************************************************
- * 
+ *
  */
 int led_allocate(void) {
 	 if (led_max < MAX_LED) return led_max++;
@@ -172,83 +218,115 @@ int led_allocate(void) {
 }
 
 /****************************************************************************************
- * 
+ *
  */
-bool led_config(int idx, gpio_num_t gpio, int onstate, int pwm) {
+bool led_config(int idx, gpio_num_t gpio, int color, int bright, led_type_t type) {
 	if (gpio < 0) {
 		ESP_LOGW(TAG,"LED GPIO -1 ignored");
 		return false;
 	}
-	
-	ESP_LOGD(TAG,"Index %d, GPIO %d, on state %s", idx, gpio, onstate>0?"On":"Off");
+
 	if (idx >= MAX_LED) return false;
-	
+
+    if (bright > 100) bright = 100;
+
 	leds[idx].gpio = gpio;
-	leds[idx].onstate = onstate;
-	leds[idx].pwm = -1;
+	leds[idx].color = color;
+    leds[idx].rmt = NULL;
+    leds[idx].bright = -1;
 
-	if (pwm < 0 || gpio >= GPIO_NUM_MAX) {	
+    if (type != LED_GPIO) {
+        // first make sure we have a known addressable led
+        for (const struct rmt_led_param_s *p = rmt_led_param; !leds[idx].rmt && p->type >= 0; p++) if (p->type == type) leds[idx].rmt = p;
+        if (!leds[idx].rmt) return false;
+
+        if (led_rmt_channel < 0) led_rmt_channel = rmt_system_base_channel++;
+        leds[idx].channel = led_rmt_channel;
+		leds[idx].bright = bright > 0 ? bright : 100;
+
+        // set counter clock to 40MHz
+        rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio, leds[idx].channel);
+        config.clk_div = 2;
+
+        rmt_config(&config);
+        rmt_driver_install(config.channel, 0, 0);
+	} else if (bright < 0 || gpio >= GPIO_NUM_MAX) {
 		gpio_pad_select_gpio_x(gpio);
 		gpio_set_direction_x(gpio, GPIO_MODE_OUTPUT);
-	} else {	
+    } else {
 		leds[idx].channel = pwm_system.base_channel++;
-		leds[idx].pwm = pwm_system.max * powf(pwm / 100.0, 3);
-		if (!onstate) leds[idx].pwm = pwm_system.max - leds[idx].pwm;
-		
+		leds[idx].bright = pwm_system.max * powf(bright / 100.0, 3);
+		if (!color) leds[idx].bright = pwm_system.max - leds[idx].bright;
+
 		ledc_channel_config_t ledc_channel = {
             .channel    = leds[idx].channel,
-            .duty       = leds[idx].pwm,
+            .duty       = leds[idx].bright,
             .gpio_num   = gpio,
             .speed_mode = LEDC_SPEED_MODE,
             .hpoint     = 0,
             .timer_sel  = pwm_system.timer,
         };
-		
+
 		ledc_channel_config(&ledc_channel);
 	}
-	
+
 	set_level(leds + idx, false);
-	ESP_LOGD(TAG,"PWM Index %d, GPIO %d, on state %s, pwm %d%%", idx, gpio, onstate > 0 ? "On" : "Off", pwm);		
+	ESP_LOGD(TAG,"Index %d, GPIO %d, color/onstate %d / RMT %d, bright %d%%", idx, gpio, color, type, bright);
 
 	return true;
 }
 
 /****************************************************************************************
- * 
+ *
  */
 void set_led_gpio(int gpio, char *value) {
-	char *p;
-	
-	if (strcasestr(value, "green")) {
-		green.gpio = gpio;
-		if ((p = strchr(value, ':')) != NULL) green.active = atoi(p + 1);
-	} else 	if (strcasestr(value, "red")) {
-		red.gpio = gpio;
-		if ((p = strchr(value, ':')) != NULL) red.active = atoi(p + 1);
-	}	
+    struct led_config_s *config;
+
+	if (strcasestr(value, "green")) config = &green;
+    else config = &red;
+
+    config->gpio = gpio;
+    char *p = value;
+    while ((p = strchr(p, ':')) != NULL) {
+        p++;
+        if ((strcasestr(p, "ws2812")) != NULL) config->type = LED_WS2812;
+        else config->color = atoi(p);
+    }
+
+    if (config->type != LED_GPIO) {
+        for (const struct rmt_led_param_s *p = rmt_led_param; p->type >= 0; p++) {
+            if (p->type == config->type) {
+                if (config == &green) config->color = p->green;
+                else config->color = p->red;
+                break;
+            }
+        }
+    }
 }
 
 void led_svc_init(void) {
 #ifdef CONFIG_LED_GREEN_GPIO_LEVEL
-	green.active = CONFIG_LED_GREEN_GPIO_LEVEL;
+	green.color = CONFIG_LED_GREEN_GPIO_LEVEL;
 #endif
 #ifdef CONFIG_LED_RED_GPIO_LEVEL
-	red.active = CONFIG_LED_RED_GPIO_LEVEL;
+	red.color = CONFIG_LED_RED_GPIO_LEVEL;
 #endif
 
 #ifndef CONFIG_LED_LOCKED
 	parse_set_GPIO(set_led_gpio);
 #endif
 
-	char *nvs_item = config_alloc_get(NVS_TYPE_STR, "led_brightness"); 
+	char *nvs_item = config_alloc_get(NVS_TYPE_STR, "led_brightness");
 	if (nvs_item) {
-		PARSE_PARAM(nvs_item, "green", '=', green.pwm);
-		PARSE_PARAM(nvs_item, "red", '=', red.pwm);
+		PARSE_PARAM(nvs_item, "green", '=', green.bright);
+		PARSE_PARAM(nvs_item, "red", '=', red.bright);
 		free(nvs_item);
 	}
 
-	led_config(LED_GREEN, green.gpio, green.active, green.pwm);
-	led_config(LED_RED, red.gpio, red.active, red.pwm);
-	
-	ESP_LOGI(TAG,"Configuring LEDs green:%d (active:%d %d%%), red:%d (active:%d %d%%)", green.gpio, green.active, green.pwm, red.gpio, red.active, red.pwm );
+	led_config(LED_GREEN, green.gpio, green.color, green.bright, green.type);
+	led_config(LED_RED, red.gpio, red.color, red.bright, red.type);
+
+	ESP_LOGI(TAG,"Configuring LEDs green:%d (on:%d rmt:%d %d%% ), red:%d (on:%d rmt:%d %d%% )",
+                 green.gpio, green.color, green.type, green.bright,
+                 red.gpio, red.color, red.type, red.bright);
 }

+ 6 - 4
components/services/led.h

@@ -1,4 +1,4 @@
-/* 
+/*
  *  Squeezelite for esp32
  *
  *  (c) Sebastien 2019
@@ -8,20 +8,22 @@
  *  https://opensource.org/licenses/MIT
  *
  */
- 
+
 #ifndef LED_H
 #define LED_H
 #include "driver/gpio.h"
 
 enum { LED_GREEN = 0, LED_RED };
+typedef enum { LED_GPIO = -1, LED_WS2812 } led_type_t;
 
 #define led_on(idx)						led_blink_core(idx, 1, 0, false)
 #define led_off(idx)					led_blink_core(idx, 0, 0, false)
 #define led_blink(idx, on, off)			led_blink_core(idx, on, off, false)
 #define led_blink_pushed(idx, on, off)	led_blink_core(idx, on, off, true)
 
-bool led_config(int idx, gpio_num_t gpio, int onstate, int pwm);	
-bool led_brightness(int idx, int percent); 
+// if type is LED_GPIO then color set the GPIO logic value for "on"
+bool led_config(int idx, gpio_num_t gpio, int color, int bright, led_type_t type);
+bool led_brightness(int idx, int percent);
 bool led_blink_core(int idx, int ontime, int offtime, bool push);
 bool led_unpush(int idx);
 int  led_allocate(void);

+ 2 - 0
components/services/services.c

@@ -11,6 +11,7 @@
 #include "driver/gpio.h"
 #include "driver/ledc.h"
 #include "driver/i2c.h"
+#include "driver/rmt.h"
 #include "platform_config.h"
 #include "gpio_exp.h"
 #include "battery.h"
@@ -28,6 +29,7 @@ int i2c_system_port = I2C_SYSTEM_PORT;
 int i2c_system_speed = 400000;
 int spi_system_host = SPI_SYSTEM_HOST;
 int spi_system_dc_gpio = -1;
+int rmt_system_base_channel = RMT_CHANNEL_0;
 pwm_system_t pwm_system = { 
 		.timer = LEDC_TIMER_0,
 		.base_channel = LEDC_CHANNEL_0,

+ 8 - 3
components/targets/muse/muse.c

@@ -8,6 +8,7 @@
 #include <freertos/FreeRTOS.h>
 #include <freertos/task.h>
 #include "driver/rmt.h"
+#include "globdefs.h"
 #include "monitor.h"
 #include "targets.h"
 
@@ -15,7 +16,6 @@
 //*********************** NeoPixels  ***************************
 ////////////////////////////////////////////////////////////////
 #define NUM_LEDS  1
-#define LED_RMT_TX_CHANNEL   0
 #define LED_RMT_TX_GPIO      22
 
 #define BITS_PER_LED_CMD 24 
@@ -39,6 +39,8 @@ struct led_state {
     uint32_t leds[NUM_LEDS];
 };
 
+static int rmt_channel;
+
 void ws2812_control_init(void);
 void ws2812_write_leds(struct led_state new_state);
 
@@ -93,9 +95,10 @@ void setup_rmt_data_buffer(struct led_state new_state);
 
 void ws2812_control_init(void)
 {
+  rmt_channel = rmt_system_base_channel++;  
   rmt_config_t config;
   config.rmt_mode = RMT_MODE_TX;
-  config.channel = LED_RMT_TX_CHANNEL;
+  config.channel = rmt_channel;
   config.gpio_num = LED_RMT_TX_GPIO;
   config.mem_block_num = 3;
   config.tx_config.loop_en = false;
@@ -106,11 +109,13 @@ void ws2812_control_init(void)
 
   ESP_ERROR_CHECK(rmt_config(&config));
   ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
+  
+  ESP_LOGI(TAG, "LED wth ws2812 using gpio %d and channel %d", LED_RMT_TX_GPIO, rmt_channel);
 }
 
 void ws2812_write_leds(struct led_state new_state) {
   setup_rmt_data_buffer(new_state);
-  rmt_write_items(LED_RMT_TX_CHANNEL, led_data_buffer, LED_BUFFER_ITEMS, false);
+  rmt_write_items(rmt_channel, led_data_buffer, LED_BUFFER_ITEMS, false);
 }
 
 void setup_rmt_data_buffer(struct led_state new_state)