Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rmt: Add user context pointer for use with RMT translator callbacks (IDFGH-4135) #6002

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions components/driver/include/driver/rmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,22 @@ 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.
*
Expand Down Expand Up @@ -749,6 +765,29 @@ 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
*
* @param channel RMT channel .
* @param fn Point to the data conversion function.
*
* @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);

/**
* @brief Translate uint8_t type of data into rmt format and send it out.
* Requires rmt_translator_init to init the translator first.
Expand Down
72 changes: 64 additions & 8 deletions components/driver/rmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ typedef struct {
rmt_item32_t *tx_buf;
RingbufHandle_t rx_buf;
sample_to_rmt_t sample_to_rmt;
sample_with_context_to_rmt_t sample_with_context_to_rmt;
void* tx_context;
size_t sample_size_remain;
const uint8_t *sample_cur;
} rmt_obj_t;
Expand Down Expand Up @@ -603,12 +605,21 @@ 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;
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);
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_size_remain -= translated_size;
p_rmt->sample_cur += translated_size;
p_rmt->tx_data = p_rmt->tx_buf;
Expand Down Expand Up @@ -915,17 +926,59 @@ 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;
ESP_LOGD(RMT_TAG, "RMT translator init done");
return ESP_OK;
}

esp_err_t rmt_translator_init_with_context(rmt_channel_t channel, sample_with_context_to_rmt_t fn, 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)
{
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_write_sample(rmt_channel_t channel, const uint8_t *src, size_t src_size, bool wait_tx_done)
{
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(p_rmt_obj[channel]->sample_to_rmt != NULL, RMT_TRANSLATOR_UNINIT_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);
#if CONFIG_SPIRAM_USE_MALLOC
if (p_rmt_obj[channel]->intr_alloc_flags & ESP_INTR_FLAG_IRAM) {
if (!esp_ptr_internal(src)) {
Expand All @@ -940,7 +993,10 @@ esp_err_t rmt_write_sample(rmt_channel_t channel, const uint8_t *src, size_t src
const uint32_t item_block_len = rmt_ll_get_mem_blocks(p_rmt_obj[channel]->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);
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_size_remain = src_size - translated_size;
p_rmt->sample_cur = src + translated_size;
rmt_fill_memory(channel, p_rmt->tx_buf, item_num, 0);
Expand Down