From 26aabd2d740b8ebbc35c4bd95530a48907cba4f5 Mon Sep 17 00:00:00 2001 From: Relys <2224238+Relys@users.noreply.github.com> Date: Wed, 13 Mar 2024 23:50:21 -0700 Subject: [PATCH 1/5] Added support to use multiple pins for LEDs. --- main/lispif_vesc_extensions.c | 564 +++++++++++++++++++--------------- 1 file changed, 323 insertions(+), 241 deletions(-) diff --git a/main/lispif_vesc_extensions.c b/main/lispif_vesc_extensions.c index cb499b33..29b12b65 100644 --- a/main/lispif_vesc_extensions.c +++ b/main/lispif_vesc_extensions.c @@ -2899,266 +2899,348 @@ static lbm_value ext_buf_resize(lbm_value *args, lbm_uint argn) { #define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) typedef struct { - rmt_encoder_t base; - rmt_encoder_t *bytes_encoder; - rmt_encoder_t *copy_encoder; - int state; - rmt_symbol_word_t reset_code; + rmt_encoder_t base; + rmt_encoder_t *bytes_encoder; + rmt_encoder_t *copy_encoder; + int state; + rmt_symbol_word_t reset_code; } rmt_led_strip_encoder_t; -static rmt_channel_handle_t led_chan = NULL; -static rmt_encoder_handle_t led_encoder = NULL; -static uint8_t *led_pixels = NULL; -static int led_num = -1; -static int led_colors = 3; -static unsigned int led_type = 0; +typedef struct { + rmt_channel_handle_t chan; + rmt_encoder_handle_t encoder; + uint8_t *pixels; + int num_leds; + int colors_per_led; + int gpio_num; + int led_type; +} led_strip_t; + +static led_strip_t led_strips[SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS] = {0}; +static int led_strip_used[SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS] = {0}; +static int num_led_strips = 0; static rmt_transmit_config_t tx_config = { - .loop_count = 0, // no transfer loop + .loop_count = 0, // no transfer loop }; static size_t rmt_encode_led_strip( - rmt_encoder_t *encoder, rmt_channel_handle_t channel, - const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) { - rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); - rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; - rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; - rmt_encode_state_t session_state = 0; - rmt_encode_state_t state = 0; - size_t encoded_symbols = 0; - switch (led_encoder->state) { - case 0: // send RGB data - encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state); - if (session_state & RMT_ENCODING_COMPLETE) { - led_encoder->state = 1; // switch to next state when current encoding session finished - } - if (session_state & RMT_ENCODING_MEM_FULL) { - state |= RMT_ENCODING_MEM_FULL; - goto out; // yield if there's no free space for encoding artifacts - } - // fall-through - //no break - case 1: // send reset code - encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, - sizeof(led_encoder->reset_code), &session_state); - if (session_state & RMT_ENCODING_COMPLETE) { - led_encoder->state = 0; // back to the initial encoding session - state |= RMT_ENCODING_COMPLETE; - } - if (session_state & RMT_ENCODING_MEM_FULL) { - state |= RMT_ENCODING_MEM_FULL; - goto out; // yield if there's no free space for encoding artifacts - } - } - out: - *ret_state = state; - return encoded_symbols; + rmt_encoder_t *encoder, rmt_channel_handle_t channel, + const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) { + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; + rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; + rmt_encode_state_t session_state = 0; + rmt_encode_state_t state = 0; + size_t encoded_symbols = 0; + switch (led_encoder->state) { + case 0: // send RGB data + encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 1; // switch to next state when current encoding session finished + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + // fall-through + //no break + case 1: // send reset code + encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, + sizeof(led_encoder->reset_code), &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 0; // back to the initial encoding session + state |= RMT_ENCODING_COMPLETE; + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + } +out: + *ret_state = state; + return encoded_symbols; } static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) { - rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); - rmt_del_encoder(led_encoder->bytes_encoder); - rmt_del_encoder(led_encoder->copy_encoder); - free(led_encoder); - return ESP_OK; + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_del_encoder(led_encoder->bytes_encoder); + rmt_del_encoder(led_encoder->copy_encoder); + free(led_encoder); + return ESP_OK; } static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) { - rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); - rmt_encoder_reset(led_encoder->bytes_encoder); - rmt_encoder_reset(led_encoder->copy_encoder); - led_encoder->state = 0; - return ESP_OK; + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_reset(led_encoder->bytes_encoder); + rmt_encoder_reset(led_encoder->copy_encoder); + led_encoder->state = 0; + return ESP_OK; } esp_err_t rmt_new_led_strip_encoder(rmt_encoder_handle_t *ret_encoder) { - rmt_led_strip_encoder_t *led_encoder = NULL; - led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t)); - led_encoder->base.encode = rmt_encode_led_strip; - led_encoder->base.del = rmt_del_led_strip_encoder; - led_encoder->base.reset = rmt_led_strip_encoder_reset; - - // different led strip might have its own timing requirements, following parameter is for WS2812 - rmt_bytes_encoder_config_t bytes_encoder_config = { - .bit0 = { - .level0 = 1, - .duration0 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T0H=0.3us - .level1 = 0, - .duration1 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T0L=0.9us - }, - .bit1 = { - .level0 = 1, - .duration0 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T1H=0.9us - .level1 = 0, - .duration1 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T1L=0.3us - }, - .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 - }; - - rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder); - rmt_copy_encoder_config_t copy_encoder_config = {}; - rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder); - - uint32_t reset_ticks = RMT_LED_STRIP_RESOLUTION_HZ / 1000000 * 50 / 2; // reset code duration defaults to 50us - led_encoder->reset_code = (rmt_symbol_word_t) { - .level0 = 0, - .duration0 = reset_ticks, - .level1 = 0, - .duration1 = reset_ticks, - }; - - *ret_encoder = &led_encoder->base; - return ESP_OK; -} - + rmt_led_strip_encoder_t *led_encoder = NULL; + led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t)); + led_encoder->base.encode = rmt_encode_led_strip; + led_encoder->base.del = rmt_del_led_strip_encoder; + led_encoder->base.reset = rmt_led_strip_encoder_reset; + + // different led strip might have its own timing requirements, following parameter is for WS2812 + rmt_bytes_encoder_config_t bytes_encoder_config = { + .bit0 = { + .level0 = 1, + .duration0 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T0H=0.3us + .level1 = 0, + .duration1 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T0L=0.9us + }, + .bit1 = { + .level0 = 1, + .duration0 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T1H=0.9us + .level1 = 0, + .duration1 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T1L=0.3us + }, + .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 + }; + + rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder); + rmt_copy_encoder_config_t copy_encoder_config = {}; + rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder); + + uint32_t reset_ticks = RMT_LED_STRIP_RESOLUTION_HZ / 1000000 * 50 / 2; // reset code duration defaults to 50us + led_encoder->reset_code = (rmt_symbol_word_t) { + .level0 = 0, + .duration0 = reset_ticks, + .level1 = 0, + .duration1 = reset_ticks, + }; + + *ret_encoder = &led_encoder->base; + return ESP_OK; +} + +// (rgbled-deinit optPIN) -> t, nil static lbm_value ext_rgbled_deinit(lbm_value *args, lbm_uint argn) { - (void)args; (void)argn; - - if (led_pixels != NULL) { - free(led_pixels); - led_pixels = NULL; - } - - if (led_chan != NULL) { - rmt_disable(led_chan); - rmt_del_channel(led_chan); - led_chan = NULL; - } - - if (led_encoder != NULL) { - rmt_del_encoder(led_encoder); - led_encoder = NULL; - } - - led_num = -1; - - return ENC_SYM_TRUE; -} - + if (argn > 1) { + lbm_set_error_reason((char*)lbm_error_str_num_args); + return ENC_SYM_TERROR; + } + + int pin = -1; + if (argn == 1) { + pin = lbm_dec_as_i32(args[0]); + } + + if (pin == -1) { + for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { + if (led_strip_used[i]) { + led_strip_t *strip = &led_strips[i]; + if (strip->pixels != NULL) { + free(strip->pixels); + strip->pixels = NULL; + } + if (strip->chan != NULL) { + rmt_disable(strip->chan); + rmt_del_channel(strip->chan); + strip->chan = NULL; + } + if (strip->encoder != NULL) { + rmt_del_encoder(strip->encoder); + strip->encoder = NULL; + } + led_strip_used[i] = 0; + num_led_strips--; + } + } + } else { + int i; + for (i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { + if (led_strip_used[i] && led_strips[i].gpio_num == pin) { + led_strip_t *strip = &led_strips[i]; + if (strip->pixels != NULL) { + free(strip->pixels); + strip->pixels = NULL; + } + if (strip->chan != NULL) { + rmt_disable(strip->chan); + rmt_del_channel(strip->chan); + strip->chan = NULL; + } + if (strip->encoder != NULL) { + rmt_del_encoder(strip->encoder); + strip->encoder = NULL; + } + led_strip_used[i] = 0; + num_led_strips--; + break; + } + } + if (i == SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS) { + lbm_set_error_reason("Invalid pin number"); + return ENC_SYM_TERROR; + } + } + + return ENC_SYM_TRUE; +} + +// (rgbled-init pin num-leds optLedType) -> t, nil static lbm_value ext_rgbled_init(lbm_value *args, lbm_uint argn) { - LBM_CHECK_NUMBER_ALL(); - - if (argn != 2 && argn != 3) { - lbm_set_error_reason((char*)lbm_error_str_num_args); - return ENC_SYM_TERROR; - } - - int pin = lbm_dec_as_i32(args[0]); - if (!gpio_is_valid(pin)) { - lbm_set_error_reason(pin_invalid_msg); - return ENC_SYM_TERROR; - } - - int num_leds = lbm_dec_as_u32(args[1]); - - if (num_leds == 0) { - lbm_set_error_reason("At least one led must be used"); - return ENC_SYM_TERROR; - } - - unsigned int type_led = 0; - if (argn >= 3) { - type_led = lbm_dec_as_u32(args[2]); - if (type_led >= 4) { - lbm_set_error_reason("Invalid LED type"); - return ENC_SYM_TERROR; - } - } - - if (type_led >= 2) { - led_colors = 4; - } else { - led_colors = 3; - } - - ext_rgbled_deinit(0, 0); - - led_pixels = calloc(num_leds * led_colors, sizeof(led_pixels)); - - if (!led_pixels) { - lbm_set_error_reason("Not enough memory"); - return ENC_SYM_EERROR; - } - - led_type = type_led; - led_num = num_leds; - - rmt_tx_channel_config_t tx_chan_config = { - .clk_src = RMT_CLK_SRC_DEFAULT, // select source clock - .gpio_num = pin, - .mem_block_symbols = 64, // increase the block size can make the LED less flickering - .resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ, - .trans_queue_depth = 4, // set the number of transactions that can be pending in the background - }; - rmt_new_tx_channel(&tx_chan_config, &led_chan); - - rmt_new_led_strip_encoder(&led_encoder); - rmt_enable(led_chan); - - return ENC_SYM_TRUE; -} - + LBM_CHECK_NUMBER_ALL(); + + if (argn != 2 && argn != 3) { + lbm_set_error_reason((char*)lbm_error_str_num_args); + return ENC_SYM_TERROR; + } + + int pin = lbm_dec_as_i32(args[0]); + if (!gpio_is_valid(pin)) { + lbm_set_error_reason(pin_invalid_msg); + return ENC_SYM_TERROR; + } + + int num_leds = lbm_dec_as_u32(args[1]); + + if (num_leds == 0) { + lbm_set_error_reason("At least one LED must be used"); + return ENC_SYM_TERROR; + } + + unsigned int led_type = 0; + if (argn >= 3) { + led_type = lbm_dec_as_u32(args[2]); + if (led_type >= 4) { + lbm_set_error_reason("Invalid LED type"); + return ENC_SYM_TERROR; + } + } + + // Check if the pin is already initialized + for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { + if (led_strip_used[i] && led_strips[i].gpio_num == pin) { + lbm_set_error_reason("Pin is already initialized"); + return ENC_SYM_TERROR; + } + } + + int slot = -1; + for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { + if (!led_strip_used[i]) { + slot = i; + break; + } + } + + if (slot == -1) { + lbm_set_error_reason("Maximum number of LED strips reached"); + return ENC_SYM_TERROR; + } + + led_strip_t *strip = &led_strips[slot]; + strip->num_leds = num_leds; + strip->colors_per_led = (led_type >= 2) ? 4 : 3; + strip->gpio_num = pin; + strip->led_type = led_type; + + strip->pixels = calloc(num_leds * strip->colors_per_led, sizeof(uint8_t)); + if (!strip->pixels) { + lbm_set_error_reason("Not enough memory"); + return ENC_SYM_EERROR; + } + + rmt_tx_channel_config_t tx_chan_config = { + .clk_src = RMT_CLK_SRC_DEFAULT, // select source clock + .gpio_num = pin, + .mem_block_symbols = 64, // increase the block size can make the LED less flickering + .resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ, + .trans_queue_depth = 4, // set the number of transactions that can be pending in the background + }; + rmt_new_tx_channel(&tx_chan_config, &strip->chan); + + rmt_new_led_strip_encoder(&strip->encoder); + rmt_enable(strip->chan); + + led_strip_used[slot] = 1; + num_led_strips++; + + return ENC_SYM_TRUE; +} + +// (rgbled-color led-num color optPIN) -> t, nil static lbm_value ext_rgbled_color(lbm_value *args, lbm_uint argn) { - LBM_CHECK_ARGN_NUMBER(2); - - if (led_encoder == NULL || led_chan == NULL || led_pixels == NULL) { - lbm_set_error_reason("Please run (rgbled-init pin num-leds) first"); - if (led_encoder == NULL) { - commands_printf_lisp("led_encoder null"); - } - - if (led_chan == NULL) { - commands_printf_lisp("led_chan null"); - } - return ENC_SYM_EERROR; - } - - int led = lbm_dec_as_u32(args[0]); - - if (led >= led_num) { - lbm_set_error_reason("Invalid LED number"); - return ENC_SYM_TERROR; - } - - uint32_t color = lbm_dec_as_u32(args[1]); - - uint8_t w = (color >> 24) & 0xFF; - uint8_t r = (color >> 16) & 0xFF; - uint8_t g = (color >> 8) & 0xFF; - uint8_t b = color & 0xFF; - - switch (led_type) { - case 0: // GRB - led_pixels[led * 3 + 0] = g; - led_pixels[led * 3 + 1] = r; - led_pixels[led * 3 + 2] = b; - break; - - case 1: // RGB - led_pixels[led * 3 + 0] = r; - led_pixels[led * 3 + 1] = g; - led_pixels[led * 3 + 2] = b; - break; - - case 2: // GRBW - led_pixels[led * 4 + 0] = g; - led_pixels[led * 4 + 1] = r; - led_pixels[led * 4 + 2] = b; - led_pixels[led * 4 + 3] = w; - break; - - case 3: // RGBW - led_pixels[led * 4 + 0] = r; - led_pixels[led * 4 + 1] = g; - led_pixels[led * 4 + 2] = b; - led_pixels[led * 4 + 3] = w; - break; - - default: - break; - } - - rmt_transmit(led_chan, led_encoder, led_pixels, led_num * led_colors, &tx_config); + LBM_CHECK_NUMBER_ALL(); + + if (argn != 2 && argn != 3) { + lbm_set_error_reason((char*)lbm_error_str_num_args); + return ENC_SYM_TERROR; + } + + int led_num = lbm_dec_as_u32(args[0]); + uint32_t color = lbm_dec_as_u32(args[1]); + + int pin = -1; + if (argn >= 3) { + pin = lbm_dec_as_i32(args[2]); + } + + led_strip_t *strip = NULL; + if (pin == -1) { + if (num_led_strips == 0) { + lbm_set_error_reason("Please run (rgbled-init pin num-leds) first"); + return ENC_SYM_EERROR; + } + strip = &led_strips[0]; + } else { + int i; + for (i = 0; i < num_led_strips; i++) { + if (led_strips[i].gpio_num == pin) { + strip = &led_strips[i]; + break; + } + } + if (i == num_led_strips) { + lbm_set_error_reason("Invalid pin number"); + return ENC_SYM_TERROR; + } + } + + if (led_num >= strip->num_leds) { + lbm_set_error_reason("Invalid LED number"); + return ENC_SYM_TERROR; + } + + uint8_t w = (color >> 24) & 0xFF; + uint8_t r = (color >> 16) & 0xFF; + uint8_t g = (color >> 8) & 0xFF; + uint8_t b = color & 0xFF; + + switch (strip->led_type) { + case 0: // GRB + strip->pixels[led_num * 3 + 0] = g; + strip->pixels[led_num * 3 + 1] = r; + strip->pixels[led_num * 3 + 2] = b; + break; + case 1: // RGB + strip->pixels[led_num * 3 + 0] = r; + strip->pixels[led_num * 3 + 1] = g; + strip->pixels[led_num * 3 + 2] = b; + break; + case 2: // GRBW + strip->pixels[led_num * 4 + 0] = g; + strip->pixels[led_num * 4 + 1] = r; + strip->pixels[led_num * 4 + 2] = b; + strip->pixels[led_num * 4 + 3] = w; + break; + case 3: // RGBW + strip->pixels[led_num * 4 + 0] = r; + strip->pixels[led_num * 4 + 1] = g; + strip->pixels[led_num * 4 + 2] = b; + strip->pixels[led_num * 4 + 3] = w; + break; + default: + break; + } + + rmt_transmit(strip->chan, strip->encoder, strip->pixels, strip->num_leds * strip->colors_per_led, &tx_config); return ENC_SYM_TRUE; } From 687a4d0f9d3b4fce78ff362f393f33016d9370cc Mon Sep 17 00:00:00 2001 From: Relys <2224238+Relys@users.noreply.github.com> Date: Thu, 14 Mar 2024 23:43:51 -0700 Subject: [PATCH 2/5] Added optBrightness to rgbled-color --- main/lispif_vesc_extensions.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/main/lispif_vesc_extensions.c b/main/lispif_vesc_extensions.c index 29b12b65..3a70dd84 100644 --- a/main/lispif_vesc_extensions.c +++ b/main/lispif_vesc_extensions.c @@ -3165,11 +3165,11 @@ static lbm_value ext_rgbled_init(lbm_value *args, lbm_uint argn) { return ENC_SYM_TRUE; } -// (rgbled-color led-num color optPIN) -> t, nil +// (rgbled-color led-num color optBrightness optPIN) -> t, nil static lbm_value ext_rgbled_color(lbm_value *args, lbm_uint argn) { LBM_CHECK_NUMBER_ALL(); - if (argn != 2 && argn != 3) { + if (argn != 2 && argn != 3 && argn != 4) { lbm_set_error_reason((char*)lbm_error_str_num_args); return ENC_SYM_TERROR; } @@ -3177,9 +3177,17 @@ static lbm_value ext_rgbled_color(lbm_value *args, lbm_uint argn) { int led_num = lbm_dec_as_u32(args[0]); uint32_t color = lbm_dec_as_u32(args[1]); - int pin = -1; + uint8_t brightness = 255; // Default brightness is 255 (maximum) if (argn >= 3) { - pin = lbm_dec_as_i32(args[2]); + brightness = lbm_dec_as_u32(args[2]); + if (brightness > 255) { + brightness = 255; + } + } + + int pin = -1; + if (argn >= 4) { + pin = lbm_dec_as_i32(args[3]); } led_strip_t *strip = NULL; @@ -3208,10 +3216,10 @@ static lbm_value ext_rgbled_color(lbm_value *args, lbm_uint argn) { return ENC_SYM_TERROR; } - uint8_t w = (color >> 24) & 0xFF; - uint8_t r = (color >> 16) & 0xFF; - uint8_t g = (color >> 8) & 0xFF; - uint8_t b = color & 0xFF; + uint8_t w = (color >> 24) & 0xFF * brightness / 255; + uint8_t r = ((color >> 16) & 0xFF) * brightness / 255; + uint8_t g = ((color >> 8) & 0xFF) * brightness / 255; + uint8_t b = (color & 0xFF) * brightness / 255; switch (strip->led_type) { case 0: // GRB @@ -3242,7 +3250,7 @@ static lbm_value ext_rgbled_color(lbm_value *args, lbm_uint argn) { rmt_transmit(strip->chan, strip->encoder, strip->pixels, strip->num_leds * strip->colors_per_led, &tx_config); - return ENC_SYM_TRUE; + return ENC_SYM_TRUE; } // Logging From 635c5e5c0961e9b8c95ae75ecb46628fbafd3eb0 Mon Sep 17 00:00:00 2001 From: Relys <2224238+Relys@users.noreply.github.com> Date: Fri, 15 Mar 2024 00:10:24 -0700 Subject: [PATCH 3/5] Removed pointless check --- main/lispif_vesc_extensions.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/main/lispif_vesc_extensions.c b/main/lispif_vesc_extensions.c index 3a70dd84..ad01b0ed 100644 --- a/main/lispif_vesc_extensions.c +++ b/main/lispif_vesc_extensions.c @@ -3180,9 +3180,6 @@ static lbm_value ext_rgbled_color(lbm_value *args, lbm_uint argn) { uint8_t brightness = 255; // Default brightness is 255 (maximum) if (argn >= 3) { brightness = lbm_dec_as_u32(args[2]); - if (brightness > 255) { - brightness = 255; - } } int pin = -1; From 81bb659924b9c07ebd94a7b8945e88d81665417d Mon Sep 17 00:00:00 2001 From: Relys <2224238+Relys@users.noreply.github.com> Date: Sun, 17 Mar 2024 18:50:43 -0700 Subject: [PATCH 4/5] changed spaces to tabs and other formatting --- main/lispif_vesc_extensions.c | 657 ++++++++++++++++++---------------- 1 file changed, 340 insertions(+), 317 deletions(-) diff --git a/main/lispif_vesc_extensions.c b/main/lispif_vesc_extensions.c index ad01b0ed..efd37f05 100644 --- a/main/lispif_vesc_extensions.c +++ b/main/lispif_vesc_extensions.c @@ -2896,358 +2896,381 @@ static lbm_value ext_buf_resize(lbm_value *args, lbm_uint argn) { // WS2812-driver using RMT -#define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) +#define RMT_LED_STRIP_RESOLUTION_HZ \ +10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) typedef struct { - rmt_encoder_t base; - rmt_encoder_t *bytes_encoder; - rmt_encoder_t *copy_encoder; - int state; - rmt_symbol_word_t reset_code; + rmt_encoder_t base; + rmt_encoder_t *bytes_encoder; + rmt_encoder_t *copy_encoder; + int state; + rmt_symbol_word_t reset_code; } rmt_led_strip_encoder_t; typedef struct { - rmt_channel_handle_t chan; - rmt_encoder_handle_t encoder; - uint8_t *pixels; - int num_leds; - int colors_per_led; - int gpio_num; - int led_type; + rmt_channel_handle_t chan; + rmt_encoder_handle_t encoder; + uint8_t *pixels; + int num_leds; + int colors_per_led; + int gpio_num; + int led_type; } led_strip_t; -static led_strip_t led_strips[SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS] = {0}; +static led_strip_t led_strips[SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS] = {0 +}; static int led_strip_used[SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS] = {0}; -static int num_led_strips = 0; +static int num_led_strips = 0; static rmt_transmit_config_t tx_config = { - .loop_count = 0, // no transfer loop + .loop_count = 0, // no transfer loop }; static size_t rmt_encode_led_strip( - rmt_encoder_t *encoder, rmt_channel_handle_t channel, - const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) { - rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); - rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; - rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; - rmt_encode_state_t session_state = 0; - rmt_encode_state_t state = 0; - size_t encoded_symbols = 0; - switch (led_encoder->state) { - case 0: // send RGB data - encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state); - if (session_state & RMT_ENCODING_COMPLETE) { - led_encoder->state = 1; // switch to next state when current encoding session finished - } - if (session_state & RMT_ENCODING_MEM_FULL) { - state |= RMT_ENCODING_MEM_FULL; - goto out; // yield if there's no free space for encoding artifacts - } - // fall-through - //no break - case 1: // send reset code - encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, - sizeof(led_encoder->reset_code), &session_state); - if (session_state & RMT_ENCODING_COMPLETE) { - led_encoder->state = 0; // back to the initial encoding session - state |= RMT_ENCODING_COMPLETE; - } - if (session_state & RMT_ENCODING_MEM_FULL) { - state |= RMT_ENCODING_MEM_FULL; - goto out; // yield if there's no free space for encoding artifacts - } - } + rmt_encoder_t *encoder, rmt_channel_handle_t channel, + const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state +) { + rmt_led_strip_encoder_t *led_encoder = + __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; + rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; + rmt_encode_state_t session_state = 0; + rmt_encode_state_t state = 0; + size_t encoded_symbols = 0; + switch (led_encoder->state) { + case 0: // send RGB data + encoded_symbols += bytes_encoder->encode( + bytes_encoder, channel, primary_data, data_size, &session_state + ); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = + 1; // switch to next state when current encoding session finished + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + // fall-through + //no break + case 1: // send reset code + encoded_symbols += copy_encoder->encode( + copy_encoder, channel, &led_encoder->reset_code, + sizeof(led_encoder->reset_code), &session_state + ); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 0; // back to the initial encoding session + state |= RMT_ENCODING_COMPLETE; + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + } out: - *ret_state = state; - return encoded_symbols; + *ret_state = state; + return encoded_symbols; } static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) { - rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); - rmt_del_encoder(led_encoder->bytes_encoder); - rmt_del_encoder(led_encoder->copy_encoder); - free(led_encoder); - return ESP_OK; + rmt_led_strip_encoder_t *led_encoder = + __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_del_encoder(led_encoder->bytes_encoder); + rmt_del_encoder(led_encoder->copy_encoder); + free(led_encoder); + return ESP_OK; } static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) { - rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); - rmt_encoder_reset(led_encoder->bytes_encoder); - rmt_encoder_reset(led_encoder->copy_encoder); - led_encoder->state = 0; - return ESP_OK; + rmt_led_strip_encoder_t *led_encoder = + __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_reset(led_encoder->bytes_encoder); + rmt_encoder_reset(led_encoder->copy_encoder); + led_encoder->state = 0; + return ESP_OK; } esp_err_t rmt_new_led_strip_encoder(rmt_encoder_handle_t *ret_encoder) { - rmt_led_strip_encoder_t *led_encoder = NULL; - led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t)); - led_encoder->base.encode = rmt_encode_led_strip; - led_encoder->base.del = rmt_del_led_strip_encoder; - led_encoder->base.reset = rmt_led_strip_encoder_reset; - - // different led strip might have its own timing requirements, following parameter is for WS2812 - rmt_bytes_encoder_config_t bytes_encoder_config = { - .bit0 = { - .level0 = 1, - .duration0 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T0H=0.3us - .level1 = 0, - .duration1 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T0L=0.9us - }, - .bit1 = { - .level0 = 1, - .duration0 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T1H=0.9us - .level1 = 0, - .duration1 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T1L=0.3us - }, - .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 - }; - - rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder); - rmt_copy_encoder_config_t copy_encoder_config = {}; - rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder); - - uint32_t reset_ticks = RMT_LED_STRIP_RESOLUTION_HZ / 1000000 * 50 / 2; // reset code duration defaults to 50us - led_encoder->reset_code = (rmt_symbol_word_t) { - .level0 = 0, - .duration0 = reset_ticks, - .level1 = 0, - .duration1 = reset_ticks, - }; - - *ret_encoder = &led_encoder->base; - return ESP_OK; + rmt_led_strip_encoder_t *led_encoder = NULL; + led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t)); + led_encoder->base.encode = rmt_encode_led_strip; + led_encoder->base.del = rmt_del_led_strip_encoder; + led_encoder->base.reset = rmt_led_strip_encoder_reset; + + // different led strip might have its own timing requirements, following parameter is for WS2812 + rmt_bytes_encoder_config_t bytes_encoder_config = { + .bit0 = + { + .level0 = 1, + .duration0 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ + / 1000000, // T0H=0.3us + .level1 = 0, + .duration1 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ + / 1000000, // T0L=0.9us + }, + .bit1 = + { + .level0 = 1, + .duration0 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ + / 1000000, // T1H=0.9us + .level1 = 0, + .duration1 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ + / 1000000, // T1L=0.3us + }, + .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 + }; + + rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder); + rmt_copy_encoder_config_t copy_encoder_config = {}; + rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder); + + uint32_t reset_ticks = RMT_LED_STRIP_RESOLUTION_HZ / 1000000 * 50 + / 2; // reset code duration defaults to 50us + led_encoder->reset_code = (rmt_symbol_word_t){ + .level0 = 0, + .duration0 = reset_ticks, + .level1 = 0, + .duration1 = reset_ticks, + }; + + *ret_encoder = &led_encoder->base; + return ESP_OK; } // (rgbled-deinit optPIN) -> t, nil static lbm_value ext_rgbled_deinit(lbm_value *args, lbm_uint argn) { - if (argn > 1) { - lbm_set_error_reason((char*)lbm_error_str_num_args); - return ENC_SYM_TERROR; - } - - int pin = -1; - if (argn == 1) { - pin = lbm_dec_as_i32(args[0]); - } - - if (pin == -1) { - for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { - if (led_strip_used[i]) { - led_strip_t *strip = &led_strips[i]; - if (strip->pixels != NULL) { - free(strip->pixels); - strip->pixels = NULL; - } - if (strip->chan != NULL) { - rmt_disable(strip->chan); - rmt_del_channel(strip->chan); - strip->chan = NULL; - } - if (strip->encoder != NULL) { - rmt_del_encoder(strip->encoder); - strip->encoder = NULL; - } - led_strip_used[i] = 0; - num_led_strips--; - } - } - } else { - int i; - for (i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { - if (led_strip_used[i] && led_strips[i].gpio_num == pin) { - led_strip_t *strip = &led_strips[i]; - if (strip->pixels != NULL) { - free(strip->pixels); - strip->pixels = NULL; - } - if (strip->chan != NULL) { - rmt_disable(strip->chan); - rmt_del_channel(strip->chan); - strip->chan = NULL; - } - if (strip->encoder != NULL) { - rmt_del_encoder(strip->encoder); - strip->encoder = NULL; - } - led_strip_used[i] = 0; - num_led_strips--; - break; - } - } - if (i == SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS) { - lbm_set_error_reason("Invalid pin number"); - return ENC_SYM_TERROR; - } - } - - return ENC_SYM_TRUE; + if (argn > 1) { + lbm_set_error_reason((char *)lbm_error_str_num_args); + return ENC_SYM_TERROR; + } + + int pin = -1; + if (argn == 1) { + pin = lbm_dec_as_i32(args[0]); + } + + if (pin == -1) { + for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { + if (led_strip_used[i]) { + led_strip_t *strip = &led_strips[i]; + if (strip->pixels != NULL) { + free(strip->pixels); + strip->pixels = NULL; + } + if (strip->chan != NULL) { + rmt_disable(strip->chan); + rmt_del_channel(strip->chan); + strip->chan = NULL; + } + if (strip->encoder != NULL) { + rmt_del_encoder(strip->encoder); + strip->encoder = NULL; + } + led_strip_used[i] = 0; + num_led_strips--; + } + } + } else { + int i; + for (i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { + if (led_strip_used[i] && led_strips[i].gpio_num == pin) { + led_strip_t *strip = &led_strips[i]; + if (strip->pixels != NULL) { + free(strip->pixels); + strip->pixels = NULL; + } + if (strip->chan != NULL) { + rmt_disable(strip->chan); + rmt_del_channel(strip->chan); + strip->chan = NULL; + } + if (strip->encoder != NULL) { + rmt_del_encoder(strip->encoder); + strip->encoder = NULL; + } + led_strip_used[i] = 0; + num_led_strips--; + break; + } + } + if (i == SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS) { + lbm_set_error_reason("Invalid pin number"); + return ENC_SYM_TERROR; + } + } + + return ENC_SYM_TRUE; } // (rgbled-init pin num-leds optLedType) -> t, nil static lbm_value ext_rgbled_init(lbm_value *args, lbm_uint argn) { - LBM_CHECK_NUMBER_ALL(); - - if (argn != 2 && argn != 3) { - lbm_set_error_reason((char*)lbm_error_str_num_args); - return ENC_SYM_TERROR; - } - - int pin = lbm_dec_as_i32(args[0]); - if (!gpio_is_valid(pin)) { - lbm_set_error_reason(pin_invalid_msg); - return ENC_SYM_TERROR; - } - - int num_leds = lbm_dec_as_u32(args[1]); - - if (num_leds == 0) { - lbm_set_error_reason("At least one LED must be used"); - return ENC_SYM_TERROR; - } - - unsigned int led_type = 0; - if (argn >= 3) { - led_type = lbm_dec_as_u32(args[2]); - if (led_type >= 4) { - lbm_set_error_reason("Invalid LED type"); - return ENC_SYM_TERROR; - } - } - - // Check if the pin is already initialized - for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { - if (led_strip_used[i] && led_strips[i].gpio_num == pin) { - lbm_set_error_reason("Pin is already initialized"); - return ENC_SYM_TERROR; - } - } - - int slot = -1; - for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { - if (!led_strip_used[i]) { - slot = i; - break; - } - } - - if (slot == -1) { - lbm_set_error_reason("Maximum number of LED strips reached"); - return ENC_SYM_TERROR; - } - - led_strip_t *strip = &led_strips[slot]; - strip->num_leds = num_leds; - strip->colors_per_led = (led_type >= 2) ? 4 : 3; - strip->gpio_num = pin; - strip->led_type = led_type; - - strip->pixels = calloc(num_leds * strip->colors_per_led, sizeof(uint8_t)); - if (!strip->pixels) { - lbm_set_error_reason("Not enough memory"); - return ENC_SYM_EERROR; - } - - rmt_tx_channel_config_t tx_chan_config = { - .clk_src = RMT_CLK_SRC_DEFAULT, // select source clock - .gpio_num = pin, - .mem_block_symbols = 64, // increase the block size can make the LED less flickering - .resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ, - .trans_queue_depth = 4, // set the number of transactions that can be pending in the background - }; - rmt_new_tx_channel(&tx_chan_config, &strip->chan); - - rmt_new_led_strip_encoder(&strip->encoder); - rmt_enable(strip->chan); - - led_strip_used[slot] = 1; - num_led_strips++; - - return ENC_SYM_TRUE; + LBM_CHECK_NUMBER_ALL(); + + if (argn != 2 && argn != 3) { + lbm_set_error_reason((char *)lbm_error_str_num_args); + return ENC_SYM_TERROR; + } + + int pin = lbm_dec_as_i32(args[0]); + if (!gpio_is_valid(pin)) { + lbm_set_error_reason(pin_invalid_msg); + return ENC_SYM_TERROR; + } + + int num_leds = lbm_dec_as_u32(args[1]); + + if (num_leds == 0) { + lbm_set_error_reason("At least one LED must be used"); + return ENC_SYM_TERROR; + } + + unsigned int led_type = 0; + if (argn >= 3) { + led_type = lbm_dec_as_u32(args[2]); + if (led_type >= 4) { + lbm_set_error_reason("Invalid LED type"); + return ENC_SYM_TERROR; + } + } + + // Check if the pin is already initialized + for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { + if (led_strip_used[i] && led_strips[i].gpio_num == pin) { + lbm_set_error_reason("Pin is already initialized"); + return ENC_SYM_TERROR; + } + } + + int slot = -1; + for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { + if (!led_strip_used[i]) { + slot = i; + break; + } + } + + if (slot == -1) { + lbm_set_error_reason("Maximum number of LED strips reached"); + return ENC_SYM_TERROR; + } + + led_strip_t *strip = &led_strips[slot]; + strip->num_leds = num_leds; + strip->colors_per_led = (led_type >= 2) ? 4 : 3; + strip->gpio_num = pin; + strip->led_type = led_type; + + strip->pixels = calloc(num_leds * strip->colors_per_led, sizeof(uint8_t)); + if (!strip->pixels) { + lbm_set_error_reason("Not enough memory"); + return ENC_SYM_EERROR; + } + + rmt_tx_channel_config_t tx_chan_config = { + .clk_src = RMT_CLK_SRC_DEFAULT, // select source clock + .gpio_num = pin, + .mem_block_symbols = + 64, // increase the block size can make the LED less flickering + .resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ, + .trans_queue_depth = + 4, // set the number of transactions that can be pending in the background + }; + rmt_new_tx_channel(&tx_chan_config, &strip->chan); + + rmt_new_led_strip_encoder(&strip->encoder); + rmt_enable(strip->chan); + + led_strip_used[slot] = 1; + num_led_strips++; + + return ENC_SYM_TRUE; } // (rgbled-color led-num color optBrightness optPIN) -> t, nil static lbm_value ext_rgbled_color(lbm_value *args, lbm_uint argn) { - LBM_CHECK_NUMBER_ALL(); - - if (argn != 2 && argn != 3 && argn != 4) { - lbm_set_error_reason((char*)lbm_error_str_num_args); - return ENC_SYM_TERROR; - } - - int led_num = lbm_dec_as_u32(args[0]); - uint32_t color = lbm_dec_as_u32(args[1]); - - uint8_t brightness = 255; // Default brightness is 255 (maximum) - if (argn >= 3) { - brightness = lbm_dec_as_u32(args[2]); - } - - int pin = -1; - if (argn >= 4) { - pin = lbm_dec_as_i32(args[3]); - } - - led_strip_t *strip = NULL; - if (pin == -1) { - if (num_led_strips == 0) { - lbm_set_error_reason("Please run (rgbled-init pin num-leds) first"); - return ENC_SYM_EERROR; - } - strip = &led_strips[0]; - } else { - int i; - for (i = 0; i < num_led_strips; i++) { - if (led_strips[i].gpio_num == pin) { - strip = &led_strips[i]; - break; - } - } - if (i == num_led_strips) { - lbm_set_error_reason("Invalid pin number"); - return ENC_SYM_TERROR; - } - } - - if (led_num >= strip->num_leds) { - lbm_set_error_reason("Invalid LED number"); - return ENC_SYM_TERROR; - } - - uint8_t w = (color >> 24) & 0xFF * brightness / 255; - uint8_t r = ((color >> 16) & 0xFF) * brightness / 255; - uint8_t g = ((color >> 8) & 0xFF) * brightness / 255; - uint8_t b = (color & 0xFF) * brightness / 255; - - switch (strip->led_type) { - case 0: // GRB - strip->pixels[led_num * 3 + 0] = g; - strip->pixels[led_num * 3 + 1] = r; - strip->pixels[led_num * 3 + 2] = b; - break; - case 1: // RGB - strip->pixels[led_num * 3 + 0] = r; - strip->pixels[led_num * 3 + 1] = g; - strip->pixels[led_num * 3 + 2] = b; - break; - case 2: // GRBW - strip->pixels[led_num * 4 + 0] = g; - strip->pixels[led_num * 4 + 1] = r; - strip->pixels[led_num * 4 + 2] = b; - strip->pixels[led_num * 4 + 3] = w; - break; - case 3: // RGBW - strip->pixels[led_num * 4 + 0] = r; - strip->pixels[led_num * 4 + 1] = g; - strip->pixels[led_num * 4 + 2] = b; - strip->pixels[led_num * 4 + 3] = w; - break; - default: - break; - } - - rmt_transmit(strip->chan, strip->encoder, strip->pixels, strip->num_leds * strip->colors_per_led, &tx_config); - - return ENC_SYM_TRUE; + LBM_CHECK_NUMBER_ALL(); + + if (argn != 2 && argn != 3 && argn != 4) { + lbm_set_error_reason((char *)lbm_error_str_num_args); + return ENC_SYM_TERROR; + } + + int led_num = lbm_dec_as_u32(args[0]); + uint32_t color = lbm_dec_as_u32(args[1]); + + uint8_t brightness = 255; // Default brightness is 255 (maximum) + if (argn >= 3) { + brightness = lbm_dec_as_u32(args[2]); + } + + int pin = -1; + if (argn >= 4) { + pin = lbm_dec_as_i32(args[3]); + } + + led_strip_t *strip = NULL; + if (pin == -1) { + if (num_led_strips == 0) { + lbm_set_error_reason("Please run (rgbled-init pin num-leds) first"); + return ENC_SYM_EERROR; + } + strip = &led_strips[0]; + } else { + int i; + for (i = 0; i < num_led_strips; i++) { + if (led_strips[i].gpio_num == pin) { + strip = &led_strips[i]; + break; + } + } + if (i == num_led_strips) { + lbm_set_error_reason("Invalid pin number"); + return ENC_SYM_TERROR; + } + } + + if (led_num >= strip->num_leds) { + lbm_set_error_reason("Invalid LED number"); + return ENC_SYM_TERROR; + } + + uint8_t w = (color >> 24) & 0xFF * brightness / 255; + uint8_t r = ((color >> 16) & 0xFF) * brightness / 255; + uint8_t g = ((color >> 8) & 0xFF) * brightness / 255; + uint8_t b = (color & 0xFF) * brightness / 255; + + switch (strip->led_type) { + case 0: // GRB + strip->pixels[led_num * 3 + 0] = g; + strip->pixels[led_num * 3 + 1] = r; + strip->pixels[led_num * 3 + 2] = b; + break; + case 1: // RGB + strip->pixels[led_num * 3 + 0] = r; + strip->pixels[led_num * 3 + 1] = g; + strip->pixels[led_num * 3 + 2] = b; + break; + case 2: // GRBW + strip->pixels[led_num * 4 + 0] = g; + strip->pixels[led_num * 4 + 1] = r; + strip->pixels[led_num * 4 + 2] = b; + strip->pixels[led_num * 4 + 3] = w; + break; + case 3: // RGBW + strip->pixels[led_num * 4 + 0] = r; + strip->pixels[led_num * 4 + 1] = g; + strip->pixels[led_num * 4 + 2] = b; + strip->pixels[led_num * 4 + 3] = w; + break; + default: + break; + } + + rmt_transmit( + strip->chan, strip->encoder, strip->pixels, + strip->num_leds * strip->colors_per_led, &tx_config + ); + + return ENC_SYM_TRUE; } // Logging From e81d3c2090e556f4655afdf71b944b7249a0b848 Mon Sep 17 00:00:00 2001 From: Relys <2224238+Relys@users.noreply.github.com> Date: Sun, 17 Mar 2024 19:15:20 -0700 Subject: [PATCH 5/5] Add timing support for SK6812 --- main/lispif_vesc_extensions.c | 92 +++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/main/lispif_vesc_extensions.c b/main/lispif_vesc_extensions.c index efd37f05..c802aa6d 100644 --- a/main/lispif_vesc_extensions.c +++ b/main/lispif_vesc_extensions.c @@ -2894,10 +2894,10 @@ static lbm_value ext_buf_resize(lbm_value *args, lbm_uint argn) { } } -// WS2812-driver using RMT +// WS2812 and SK6812 driver using RMT #define RMT_LED_STRIP_RESOLUTION_HZ \ -10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) + 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) typedef struct { rmt_encoder_t base; @@ -2989,7 +2989,9 @@ static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) { return ESP_OK; } -esp_err_t rmt_new_led_strip_encoder(rmt_encoder_handle_t *ret_encoder) { +esp_err_t rmt_new_led_strip_encoder( + rmt_encoder_handle_t *ret_encoder, int strip_type +) { rmt_led_strip_encoder_t *led_encoder = NULL; led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t)); led_encoder->base.encode = rmt_encode_led_strip; @@ -2997,34 +2999,55 @@ esp_err_t rmt_new_led_strip_encoder(rmt_encoder_handle_t *ret_encoder) { led_encoder->base.reset = rmt_led_strip_encoder_reset; // different led strip might have its own timing requirements, following parameter is for WS2812 - rmt_bytes_encoder_config_t bytes_encoder_config = { - .bit0 = - { - .level0 = 1, - .duration0 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ - / 1000000, // T0H=0.3us - .level1 = 0, - .duration1 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ - / 1000000, // T0L=0.9us - }, - .bit1 = - { - .level0 = 1, - .duration0 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ - / 1000000, // T1H=0.9us - .level1 = 0, - .duration1 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ - / 1000000, // T1L=0.3us - }, - .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 - }; - + rmt_bytes_encoder_config_t bytes_encoder_config; + uint32_t reset_ticks; + if (strip_type == 1) { //SK6812 + bytes_encoder_config = (rmt_bytes_encoder_config_t){ + .bit0 = + { + .level0 = 1, + .duration0 = 3, // T0H = 0.3µs + .level1 = 0, + .duration1 = 9, // T0L = 0.9µs + }, + .bit1 = + { + .level0 = 1, + .duration0 = 6, // T1H = 0.6µs + .level1 = 0, + .duration1 = 6, // T1L = 0.6µs + }, + .flags.msb_first = + 1 // SK6812 transfer bit order: G7...G0R7...R0B7...B0 + }; + reset_ticks = RMT_LED_STRIP_RESOLUTION_HZ / 1000000 * 80 + / 2; // reset code duration set to 80us for SK6812 + } else { //WS2812 + bytes_encoder_config = (rmt_bytes_encoder_config_t){ + .bit0 = + { + .level0 = 1, + .duration0 = 3, // T0H = 0.3µs + .level1 = 0, + .duration1 = 9, // T0L = 0.9µs + }, + .bit1 = + { + .level0 = 1, + .duration0 = 9, // T1H = 0.9µs + .level1 = 0, + .duration1 = 3, // T1L = 0.3µs + }, + .flags.msb_first = + 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 + }; + reset_ticks = RMT_LED_STRIP_RESOLUTION_HZ / 1000000 * 50 + / 2; // reset code duration set to 50us for WS2812 + } rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder); rmt_copy_encoder_config_t copy_encoder_config = {}; rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder); - uint32_t reset_ticks = RMT_LED_STRIP_RESOLUTION_HZ / 1000000 * 50 - / 2; // reset code duration defaults to 50us led_encoder->reset_code = (rmt_symbol_word_t){ .level0 = 0, .duration0 = reset_ticks, @@ -3101,11 +3124,11 @@ static lbm_value ext_rgbled_deinit(lbm_value *args, lbm_uint argn) { return ENC_SYM_TRUE; } -// (rgbled-init pin num-leds optLedType) -> t, nil +// (rgbled-init pin num-leds optLedType optStripType) -> t, nil static lbm_value ext_rgbled_init(lbm_value *args, lbm_uint argn) { LBM_CHECK_NUMBER_ALL(); - if (argn != 2 && argn != 3) { + if (argn != 2 && argn != 3 && argn != 4) { lbm_set_error_reason((char *)lbm_error_str_num_args); return ENC_SYM_TERROR; } @@ -3132,6 +3155,15 @@ static lbm_value ext_rgbled_init(lbm_value *args, lbm_uint argn) { } } + unsigned int strip_type = 0; + if (argn >= 4) { + strip_type = lbm_dec_as_u32(args[3]); + if (strip_type > 1) { + lbm_set_error_reason("Invalid LED strip type"); + return ENC_SYM_TERROR; + } + } + // Check if the pin is already initialized for (int i = 0; i < SOC_RMT_CHANNELS_PER_GROUP * SOC_RMT_GROUPS; i++) { if (led_strip_used[i] && led_strips[i].gpio_num == pin) { @@ -3176,7 +3208,7 @@ static lbm_value ext_rgbled_init(lbm_value *args, lbm_uint argn) { }; rmt_new_tx_channel(&tx_chan_config, &strip->chan); - rmt_new_led_strip_encoder(&strip->encoder); + rmt_new_led_strip_encoder(&strip->encoder, strip_type); rmt_enable(strip->chan); led_strip_used[slot] = 1;