led_strip_encoder.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "esp_check.h"
  7. #include "led_strip_encoder.h"
  8. static const char *TAG = "led_encoder";
  9. typedef struct {
  10. rmt_encoder_t base;
  11. rmt_encoder_t *bytes_encoder;
  12. rmt_encoder_t *copy_encoder;
  13. int state;
  14. rmt_symbol_word_t reset_code;
  15. } rmt_led_strip_encoder_t;
  16. 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)
  17. {
  18. rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
  19. rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
  20. rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
  21. rmt_encode_state_t session_state = RMT_ENCODING_RESET;
  22. rmt_encode_state_t state = RMT_ENCODING_RESET;
  23. size_t encoded_symbols = 0;
  24. switch (led_encoder->state) {
  25. case 0: // send RGB data
  26. encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
  27. if (session_state & RMT_ENCODING_COMPLETE) {
  28. led_encoder->state = 1; // switch to next state when current encoding session finished
  29. }
  30. if (session_state & RMT_ENCODING_MEM_FULL) {
  31. state |= RMT_ENCODING_MEM_FULL;
  32. goto out; // yield if there's no free space for encoding artifacts
  33. }
  34. // fall-through
  35. case 1: // send reset code
  36. encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,
  37. sizeof(led_encoder->reset_code), &session_state);
  38. if (session_state & RMT_ENCODING_COMPLETE) {
  39. led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session
  40. state |= RMT_ENCODING_COMPLETE;
  41. }
  42. if (session_state & RMT_ENCODING_MEM_FULL) {
  43. state |= RMT_ENCODING_MEM_FULL;
  44. goto out; // yield if there's no free space for encoding artifacts
  45. }
  46. }
  47. out:
  48. *ret_state = state;
  49. return encoded_symbols;
  50. }
  51. static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)
  52. {
  53. rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
  54. rmt_del_encoder(led_encoder->bytes_encoder);
  55. rmt_del_encoder(led_encoder->copy_encoder);
  56. free(led_encoder);
  57. return ESP_OK;
  58. }
  59. static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
  60. {
  61. rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
  62. rmt_encoder_reset(led_encoder->bytes_encoder);
  63. rmt_encoder_reset(led_encoder->copy_encoder);
  64. led_encoder->state = RMT_ENCODING_RESET;
  65. return ESP_OK;
  66. }
  67. esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
  68. {
  69. esp_err_t ret = ESP_OK;
  70. rmt_led_strip_encoder_t *led_encoder = NULL;
  71. ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
  72. led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t));
  73. ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
  74. led_encoder->base.encode = rmt_encode_led_strip;
  75. led_encoder->base.del = rmt_del_led_strip_encoder;
  76. led_encoder->base.reset = rmt_led_strip_encoder_reset;
  77. // different led strip might have its own timing requirements, following parameter is for WS2812
  78. rmt_bytes_encoder_config_t bytes_encoder_config = {
  79. .bit0 = {
  80. .level0 = 1,
  81. .duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us
  82. .level1 = 0,
  83. .duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
  84. },
  85. .bit1 = {
  86. .level0 = 1,
  87. .duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us
  88. .level1 = 0,
  89. .duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us
  90. },
  91. .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0
  92. };
  93. ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
  94. rmt_copy_encoder_config_t copy_encoder_config = {};
  95. ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
  96. uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us
  97. led_encoder->reset_code = (rmt_symbol_word_t) {
  98. .level0 = 0,
  99. .duration0 = reset_ticks,
  100. .level1 = 0,
  101. .duration1 = reset_ticks,
  102. };
  103. *ret_encoder = &led_encoder->base;
  104. return ESP_OK;
  105. err:
  106. if (led_encoder) {
  107. if (led_encoder->bytes_encoder) {
  108. rmt_del_encoder(led_encoder->bytes_encoder);
  109. }
  110. if (led_encoder->copy_encoder) {
  111. rmt_del_encoder(led_encoder->copy_encoder);
  112. }
  113. free(led_encoder);
  114. }
  115. return ret;
  116. }