Просмотр исходного кода

Merge branch 'feature/rmt_support_user_context_in_translator' into 'master'

rmt: support user context in translator

Closes IDFGH-4135 and IDFGH-3237

See merge request espressif/esp-idf!10894
Michael (XIAO Xufeng) 5 лет назад
Родитель
Сommit
ea996df725
3 измененных файлов с 101 добавлено и 5 удалено
  1. 27 0
      components/driver/include/driver/rmt.h
  2. 28 5
      components/driver/rmt.c
  3. 46 0
      components/driver/test/test_rmt.c

+ 27 - 0
components/driver/include/driver/rmt.h

@@ -762,6 +762,33 @@ esp_err_t rmt_get_ringbuf_handle(rmt_channel_t channel, RingbufHandle_t *buf_han
 */
 esp_err_t rmt_translator_init(rmt_channel_t channel, sample_to_rmt_t fn);
 
+/**
+* @brief Set user context for the translator of specific channel
+*
+* @param channel RMT channel number
+* @param context User context
+*
+* @return
+*     - ESP_FAIL Set context fail
+*     - ESP_OK Set context success
+*/
+esp_err_t rmt_translator_set_context(rmt_channel_t channel, void *context);
+
+/**
+* @brief Get the user context set by 'rmt_translator_set_context'
+*
+* @note This API must be invoked in the RMT translator callback function,
+*       and the first argument must be the actual parameter 'item_num' you got in that callback function.
+*
+* @param item_num Address of the memory which contains the number of translated items (It's from driver's internal memroy)
+* @param context Returned User context
+*
+* @return
+*     - ESP_FAIL Get context fail
+*     - ESP_OK Get context success
+*/
+esp_err_t rmt_translator_get_context(const size_t *item_num, void **context);
+
 /**
 * @brief Translate uint8_t type of data into rmt format and send it out.
 *        Requires rmt_translator_init to init the translator first.

+ 28 - 5
components/driver/rmt.c

@@ -14,6 +14,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/lock.h>
+#include <sys/cdefs.h>
 #include "esp_compiler.h"
 #include "esp_intr_alloc.h"
 #include "esp_log.h"
@@ -99,6 +100,7 @@ typedef struct {
     int rx_item_start_idx;
 #endif
     sample_to_rmt_t sample_to_rmt;
+    void *tx_context;
     size_t sample_size_remain;
     const uint8_t *sample_cur;
 } rmt_obj_t;
@@ -1216,12 +1218,34 @@ esp_err_t rmt_translator_init(rmt_channel_t channel, sample_to_rmt_t fn)
         }
     }
     p_rmt_obj[channel]->sample_to_rmt = fn;
+    p_rmt_obj[channel]->tx_context = NULL;
     p_rmt_obj[channel]->sample_size_remain = 0;
     p_rmt_obj[channel]->sample_cur = NULL;
     ESP_LOGD(RMT_TAG, "RMT translator init done");
     return ESP_OK;
 }
 
+esp_err_t rmt_translator_set_context(rmt_channel_t channel, void *context)
+{
+    RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
+    RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL);
+
+    p_rmt_obj[channel]->tx_context = context;
+    return ESP_OK;
+}
+
+esp_err_t rmt_translator_get_context(const size_t *item_num, void **context)
+{
+    RMT_CHECK(item_num && context, "invalid arguments", ESP_ERR_INVALID_ARG);
+
+    // the address of tx_len_rem is directlly passed to the callback,
+    // so it's possible to get the object address from that
+    rmt_obj_t *obj = __containerof(item_num, rmt_obj_t, tx_len_rem);
+    *context = obj->tx_context;
+
+    return ESP_OK;
+}
+
 esp_err_t rmt_write_sample(rmt_channel_t channel, const uint8_t *src, size_t src_size, bool wait_tx_done)
 {
     RMT_CHECK(RMT_IS_TX_CHANNEL(channel), RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
@@ -1235,17 +1259,16 @@ esp_err_t rmt_write_sample(rmt_channel_t channel, const uint8_t *src, size_t src
         }
     }
 #endif
-    size_t item_num = 0;
     size_t translated_size = 0;
     rmt_obj_t *p_rmt = p_rmt_obj[channel];
     const uint32_t item_block_len = rmt_ll_tx_get_mem_blocks(rmt_contex.hal.regs, channel) * RMT_MEM_ITEM_NUM;
     const uint32_t item_sub_len = item_block_len / 2;
     xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY);
-    p_rmt->sample_to_rmt((void *)src, p_rmt->tx_buf, src_size, item_block_len, &translated_size, &item_num);
+    p_rmt->sample_to_rmt((void *)src, p_rmt->tx_buf, src_size, item_block_len, &translated_size, &p_rmt->tx_len_rem);
     p_rmt->sample_size_remain = src_size - translated_size;
     p_rmt->sample_cur = src + translated_size;
-    rmt_fill_memory(channel, p_rmt->tx_buf, item_num, 0);
-    if (item_num == item_block_len) {
+    rmt_fill_memory(channel, p_rmt->tx_buf, p_rmt->tx_len_rem, 0);
+    if (p_rmt->tx_len_rem == item_block_len) {
         rmt_set_tx_thr_intr_en(channel, 1, item_sub_len);
         p_rmt->tx_data = p_rmt->tx_buf;
         p_rmt->tx_offset = 0;
@@ -1253,7 +1276,7 @@ esp_err_t rmt_write_sample(rmt_channel_t channel, const uint8_t *src, size_t src
         p_rmt->translator = true;
     } else {
         rmt_item32_t stop_data = {0};
-        rmt_ll_write_memory(rmt_contex.hal.mem, channel, &stop_data, 1, item_num);
+        rmt_ll_write_memory(rmt_contex.hal.mem, channel, &stop_data, 1, p_rmt->tx_len_rem);
         p_rmt->tx_len_rem = 0;
         p_rmt->sample_cur = NULL;
         p_rmt->translator = false;

+ 46 - 0
components/driver/test/test_rmt.c

@@ -218,6 +218,52 @@ TEST_CASE("RMT install/uninstall test", "[rmt]")
     }
 }
 
+static void test_rmt_translator(const void *src, rmt_item32_t *dest, size_t src_size,
+                                size_t wanted_num, size_t *translated_size, size_t *item_num)
+{
+    const rmt_item32_t bit0 = {{{ 10, 1, 20, 0 }}}; //Logical 0
+    const rmt_item32_t bit1 = {{{ 20, 1, 10, 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;
+    int *user_data = NULL;
+    rmt_translator_get_context(item_num, (void **)&user_data);
+    esp_rom_printf("user data=%d\r\n", *user_data);
+    *user_data = 100;
+}
+
+TEST_CASE("RMT translator with user context", "[rmt]")
+{
+    rmt_config_t tx_cfg = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 0);
+    TEST_ESP_OK(rmt_config(&tx_cfg));
+    TEST_ESP_OK(rmt_driver_install(tx_cfg.channel, 0, 0));
+    rmt_translator_init(tx_cfg.channel, test_rmt_translator);
+    int user_data = 999;
+    rmt_translator_set_context(tx_cfg.channel, &user_data);
+    uint8_t test_buf[] = {1, 2, 3, 4, 5, 6};
+    rmt_write_sample(tx_cfg.channel, test_buf, sizeof(test_buf), true);
+    vTaskDelay(pdMS_TO_TICKS(100));
+    TEST_ASSERT_EQUAL(100, user_data);
+    TEST_ESP_OK(rmt_driver_uninstall(tx_cfg.channel));
+}
+
 static void do_nec_tx_rx(uint32_t flags)
 {
     RingbufHandle_t rb = NULL;