| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- /*
- * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include "esp_check.h"
- #include "led_strip_encoder.h"
- static const char *TAG = "led_encoder";
- 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_led_strip_encoder_t;
- 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 = RMT_ENCODING_RESET;
- rmt_encode_state_t state = RMT_ENCODING_RESET;
- 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
- 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 = RMT_ENCODING_RESET; // 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;
- }
- 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 = RMT_ENCODING_RESET;
- return ESP_OK;
- }
- esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
- {
- esp_err_t ret = ESP_OK;
- rmt_led_strip_encoder_t *led_encoder = NULL;
- ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
- led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t));
- ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
- 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 * config->resolution / 1000000, // T0H=0.3us
- .level1 = 0,
- .duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
- },
- .bit1 = {
- .level0 = 1,
- .duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us
- .level1 = 0,
- .duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us
- },
- .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0
- };
- ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
- rmt_copy_encoder_config_t copy_encoder_config = {};
- ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
- uint32_t reset_ticks = config->resolution / 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;
- err:
- if (led_encoder) {
- if (led_encoder->bytes_encoder) {
- rmt_del_encoder(led_encoder->bytes_encoder);
- }
- if (led_encoder->copy_encoder) {
- rmt_del_encoder(led_encoder->copy_encoder);
- }
- free(led_encoder);
- }
- return ret;
- }
|