diff --git a/components/driver/include/driver/rmt.h b/components/driver/include/driver/rmt.h index 7d32eeb393..210bddc073 100644 --- a/components/driver/include/driver/rmt.h +++ b/components/driver/include/driver/rmt.h @@ -171,22 +171,6 @@ typedef struct { */ typedef void (*sample_to_rmt_t)(const void *src, rmt_item32_t *dest, size_t src_size, size_t wanted_num, size_t *translated_size, size_t *item_num); -/** -* @brief IDF 4.x Workaround callback function for sample_to_rmt_t that lets user pass in context for rmt_write_sample -* -* @param src Pointer to the buffer storing the raw data that needs to be converted to rmt format. -* @param[out] dest Pointer to the buffer storing the rmt format data. -* @param src_size The raw data size. -* @param wanted_num The number of rmt format data that wanted to get. -* @param[out] translated_size The size of the raw data that has been converted to rmt format, -* it should return 0 if no data is converted in user callback. -* @param[out] item_num The number of the rmt format data that actually converted to, -* it can be less than wanted_num if there is not enough raw data, but cannot exceed wanted_num. -* it should return 0 if no data was converted. -* @param context User context pointer -*/ -typedef void (*sample_with_context_to_rmt_t)(const void *src, rmt_item32_t *dest, size_t src_size, size_t wanted_num, size_t *translated_size, size_t *item_num, void *context); - /** * @brief Set RMT clock divider, channel clock is divided from source clock. * @@ -779,27 +763,31 @@ 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 Workaround for IDF 4.x -* TODO: Add context to sample_to_rmt_t callback signature and allow user to pass in context -* on rmt_translator_init +* @brief Set user context for the translator of specific channel * -* @param channel RMT channel . -* @param fn Point to the data conversion function. +* @param channel RMT channel number +* @param context User context * * @return -* - ESP_FAIL Init fail. -* - ESP_OK Init success. -*/ -esp_err_t rmt_translator_init_with_context(rmt_channel_t channel, sample_with_context_to_rmt_t fn, void* context); - -/** -* @brief Sets the user context for the translator -* Requires rmt_translator_init_with_context to init the translator first -* @return * - ESP_FAIL Set context fail * - ESP_OK Set context success */ -esp_err_t rmt_set_translator_context(rmt_channel_t channel, void* context); +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. diff --git a/components/driver/rmt.c b/components/driver/rmt.c index 4cc230ea95..1b266a3249 100644 --- a/components/driver/rmt.c +++ b/components/driver/rmt.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "esp_compiler.h" #include "esp_intr_alloc.h" #include "esp_log.h" @@ -99,8 +100,7 @@ typedef struct { int rx_item_start_idx; #endif sample_to_rmt_t sample_to_rmt; - sample_with_context_to_rmt_t sample_with_context_to_rmt; - void* tx_context; + void *tx_context; size_t sample_size_remain; const uint8_t *sample_cur; } rmt_obj_t; @@ -785,21 +785,12 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) if (p_rmt->translator) { if (p_rmt->sample_size_remain > 0) { size_t translated_size = 0; - if (p_rmt->sample_with_context_to_rmt == NULL) - p_rmt->sample_to_rmt((void *)p_rmt->sample_cur, - p_rmt->tx_buf, - p_rmt->sample_size_remain, - p_rmt->tx_sub_len, - &translated_size, - &p_rmt->tx_len_rem); - else - p_rmt->sample_with_context_to_rmt((void *)p_rmt->sample_cur, - p_rmt->tx_buf, - p_rmt->sample_size_remain, - p_rmt->tx_sub_len, - &translated_size, - &p_rmt->tx_len_rem, - p_rmt->tx_context); + p_rmt->sample_to_rmt((void *)p_rmt->sample_cur, + p_rmt->tx_buf, + p_rmt->sample_size_remain, + p_rmt->tx_sub_len, + &translated_size, + &p_rmt->tx_len_rem); p_rmt->sample_size_remain -= translated_size; p_rmt->sample_cur += translated_size; p_rmt->tx_data = p_rmt->tx_buf; @@ -1227,7 +1218,6 @@ 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]->sample_with_context_to_rmt = NULL; p_rmt_obj[channel]->tx_context = NULL; p_rmt_obj[channel]->sample_size_remain = 0; p_rmt_obj[channel]->sample_cur = NULL; @@ -1235,43 +1225,24 @@ esp_err_t rmt_translator_init(rmt_channel_t channel, sample_to_rmt_t fn) return ESP_OK; } -esp_err_t rmt_translator_init_with_context(rmt_channel_t channel, sample_with_context_to_rmt_t fn, void* context) +esp_err_t rmt_translator_set_context(rmt_channel_t channel, void *context) { - RMT_CHECK(fn != NULL, RMT_TRANSLATOR_NULL_STR, ESP_ERR_INVALID_ARG); 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); - const uint32_t block_size = rmt_ll_get_mem_blocks(p_rmt_obj[channel]->hal.regs, channel) * - RMT_MEM_ITEM_NUM * sizeof(rmt_item32_t); - if (p_rmt_obj[channel]->tx_buf == NULL) { -#if !CONFIG_SPIRAM_USE_MALLOC - p_rmt_obj[channel]->tx_buf = (rmt_item32_t *)malloc(block_size); -#else - if (p_rmt_obj[channel]->intr_alloc_flags & ESP_INTR_FLAG_IRAM) { - p_rmt_obj[channel]->tx_buf = (rmt_item32_t *)malloc(block_size); - } else { - p_rmt_obj[channel]->tx_buf = (rmt_item32_t *)heap_caps_calloc(1, block_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - } -#endif - if (p_rmt_obj[channel]->tx_buf == NULL) { - ESP_LOGE(RMT_TAG, "RMT translator buffer create fail"); - return ESP_FAIL; - } - } - p_rmt_obj[channel]->sample_to_rmt = NULL; - p_rmt_obj[channel]->sample_with_context_to_rmt = fn; + p_rmt_obj[channel]->tx_context = context; - 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_set_translator_context(rmt_channel_t channel, void* context) +esp_err_t rmt_translator_get_context(const size_t *item_num, 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); + 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; - p_rmt_obj[channel]->tx_context = context; return ESP_OK; } @@ -1279,7 +1250,7 @@ esp_err_t rmt_write_sample(rmt_channel_t channel, const uint8_t *src, size_t src { RMT_CHECK(RMT_IS_TX_CHANNEL(channel), RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL); - RMT_CHECK(p_rmt_obj[channel]->sample_to_rmt != NULL || p_rmt_obj[channel]->sample_with_context_to_rmt != NULL, RMT_TRANSLATOR_UNINIT_STR, ESP_FAIL); + RMT_CHECK(p_rmt_obj[channel]->sample_to_rmt != NULL, RMT_TRANSLATOR_UNINIT_STR, ESP_FAIL); #if CONFIG_SPIRAM_USE_MALLOC if (p_rmt_obj[channel]->intr_alloc_flags & ESP_INTR_FLAG_IRAM) { if (!esp_ptr_internal(src)) { @@ -1288,20 +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); - if (p_rmt->sample_with_context_to_rmt == NULL) - p_rmt->sample_to_rmt((void *)src, p_rmt->tx_buf, src_size, item_block_len, &translated_size, &item_num); - else - p_rmt->sample_with_context_to_rmt((void*)src, p_rmt->tx_buf, src_size, item_block_len, &translated_size, &item_num, p_rmt->tx_context); + 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; @@ -1309,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; diff --git a/components/driver/test/test_rmt.c b/components/driver/test/test_rmt.c index 2817f200ff..283d6ef0f1 100644 --- a/components/driver/test/test_rmt.c +++ b/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;