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

Is there a way to allow dynamic modification of the bytes_encoder_config parameter in the rmt_new_bytes_encoder function? (IDFGH-11662) #12775

Closed
3 tasks done
zigele opened this issue Dec 12, 2023 · 2 comments
Assignees
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Feature Request Feature request for IDF

Comments

@zigele
Copy link

zigele commented Dec 12, 2023

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

General issue report

I want to dynamically modify the duration0 parameter in the bytes_encoder_config structure on the encoder callback function. Similar to the following usage, but this will result in frequent calls to the heap_caps_calloc function and I'm worried about poor performance.
the importan is

    rmt_bytes_encoder_config_t bytes_encoder_config = {
        .bit0 = {
            .level0 = 0,
            .duration0 = scan_code->speed * scan_code->resolution / 1000000, // 
            .level1 = 0,
            .duration1 = scan_code->speed * scan_code->resolution / 1000000, // 
        },
        .bit1 = {
            .level0 = 1,
            .duration0 = scan_code->speed * scan_code->resolution / 1000000, // 
            .level1 = 1,
            .duration1 = scan_code->speed * scan_code->resolution / 1000000, // 
        },
        .flags.msb_first = 0, 
    };
    rmt_new_bytes_encoder(&bytes_encoder_config, &bytes_encoder);

all code here:

static size_t rmt_encode_ir_nec(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) 
{
    rmt_ir_nec_encoder_t *nec_encoder = __containerof(encoder, rmt_ir_nec_encoder_t, base); 
    rmt_encode_state_t session_state = RMT_ENCODING_RESET;
    rmt_encode_state_t state = RMT_ENCODING_RESET;
    size_t encoded_symbols = 0;
    ir_nec_scan_code_t *scan_code = (ir_nec_scan_code_t *)primary_data;
    uint32_t flag[6] = {0x80000001, 0x80000001, 0x80000001, 0x80000001, 0x80000001, 0x80000001};
    rmt_encoder_handle_t bytes_encoder;

    rmt_bytes_encoder_config_t bytes_encoder_config = {
        .bit0 = {
            .level0 = 0,
            .duration0 = scan_code->speed * scan_code->resolution / 1000000, // 
            .level1 = 0,
            .duration1 = scan_code->speed * scan_code->resolution / 1000000, // 
        },
        .bit1 = {
            .level0 = 1,
            .duration0 = scan_code->speed * scan_code->resolution / 1000000, // 
            .level1 = 1,
            .duration1 = scan_code->speed * scan_code->resolution / 1000000, // 
        },
        .flags.msb_first = 0, 
    };
    rmt_new_bytes_encoder(&bytes_encoder_config, &bytes_encoder);

    switch (nec_encoder->state)
    {
    case 0:
        encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, &flag[0], sizeof(uint32_t), &session_state);
        if (session_state & RMT_ENCODING_COMPLETE)
        {
            nec_encoder->state = 1; // we can only switch to next state when current encoder finished
        }
        if (session_state & RMT_ENCODING_MEM_FULL)
        {
            state |= RMT_ENCODING_MEM_FULL;
            goto out; // yield if there's no free space to put other encoding artifacts
        }
        // fall-through
    case 1:
       //...................
    default:
        break;
    }
out:
    *ret_state = state;
    return encoded_symbols;
}

If I use similar demo code,like this.
How can I dynamically change the duration0 and duration1 parameters of the bytes_encoder variable In the rmt_encode_ir_nec function ?
when i call the funtion rmt_new_bytes_encoder,i haveno way to change the duration0 and duration1 param in the struct 'bytes_encoder_config'
like:

    rmt_encoder_handle_t bytes_encoder = nec_encoder->bytes_encoder;
    bytes_encoder .bit0.duraton0=xxxx;
    bytes_encoder .bit0.duraton1=xxxx;
    bytes_encoder .bit1.duraton0=xxxx;
    bytes_encoder .bit1.duraton1=xxxx;
{
    rmt_ir_nec_encoder_t *nec_encoder = __containerof(encoder, rmt_ir_nec_encoder_t, base);
    rmt_encode_state_t session_state = RMT_ENCODING_RESET;
    rmt_encode_state_t state = RMT_ENCODING_RESET;
    size_t encoded_symbols = 0;
    ir_nec_scan_code_t *scan_code = (ir_nec_scan_code_t *)primary_data;
    uint32_t flag[6] = {0x80000001, 0x80000001, 0x80000001, 0x80000001, 0x80000001, 0x80000001};

    rmt_encoder_handle_t bytes_encoder = nec_encoder->bytes_encoder;
  
  //
  // How can I dynamically change the duration0 and duration1 parameters of the bytes_encoder variable? 
  //

    switch (nec_encoder->state)
    {
    case 0:
        encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, &flag[0], sizeof(uint32_t), &session_state);
        if (session_state & RMT_ENCODING_COMPLETE)
        {
            nec_encoder->state = 1; // we can only switch to next state when current encoder finished
        }
        if (session_state & RMT_ENCODING_MEM_FULL)
        {
            state |= RMT_ENCODING_MEM_FULL;
            goto out; // yield if there's no free space to put other encoding artifacts
        }
        // .............................
    default:
        break;
    }
out:
    *ret_state = state;
    return encoded_symbols;
}

esp_err_t rmt_new_ir_nec_encoder(const ir_nec_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
    esp_err_t ret = ESP_OK;
    rmt_ir_nec_encoder_t *nec_encoder = NULL;
    ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
    nec_encoder = calloc(1, sizeof(rmt_ir_nec_encoder_t));
    ESP_GOTO_ON_FALSE(nec_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for ir nec encoder");

    nec_encoder->base.encode = rmt_encode_ir_nec;
    nec_encoder->base.del = rmt_del_ir_nec_encoder;
    nec_encoder->base.reset = rmt_ir_nec_encoder_reset;

    rmt_bytes_encoder_config_t bytes_encoder_config = {
        .bit0 = {
            .level0 = 0,
            .duration0 = config->speed * config->resolution / 1000000, // T0H=560us
            .level1 = 0,
            .duration1 = config->speed * config->resolution / 1000000, // T0L=560us
        },
        .bit1 = {
            .level0 = 1,
            .duration0 = config->speed * config->resolution / 1000000, // T1H=560us
            .level1 = 1,
            .duration1 = config->speed * config->resolution / 1000000, // T1L=1690us
        },
        .flags.msb_first = 0, //
    };
    rmt_new_bytes_encoder(&bytes_encoder_config, &nec_encoder->bytes_encoder);
    *ret_encoder = &nec_encoder->base;
    return ESP_OK;
err:
    if (nec_encoder)
    {
        if (nec_encoder->bytes_encoder)
        {
            rmt_del_encoder(nec_encoder->bytes_encoder);
        }
        free(nec_encoder);
    }
    return ret;
}
@espressif-bot espressif-bot added the Status: Opened Issue is new label Dec 12, 2023
@github-actions github-actions bot changed the title Is there a way to allow dynamic modification of the bytes_encoder_config parameter in the rmt_new_bytes_encoder function? Is there a way to allow dynamic modification of the bytes_encoder_config parameter in the rmt_new_bytes_encoder function? (IDFGH-11662) Dec 12, 2023
@suda-morris
Copy link
Collaborator

hi @zigele So you need to change the bit0 and bit1 of the bytes encoder at runtime. One of the solution I can think of is to provide two "setters" for the bytes encoder to reassign the bit0 and bit1 representation. Or simply provide a reconfigure function to initialize the rmt_bytes_encoder_config_t all. e.g.

rmt_bytes_encoder_init(rmt_encoder_handle_t bytes_encoder, const rmt_bytes_encoder_config_t *config);

@suda-morris suda-morris added the Type: Feature Request Feature request for IDF label Dec 12, 2023
@zigele
Copy link
Author

zigele commented Dec 12, 2023

hi @zigele So you need to change the bit0 and bit1 of the bytes encoder at runtime. One of the solution I can think of is to provide two "setters" for the bytes encoder to reassign the bit0 and bit1 representation. Or simply provide a reconfigure function to initialize the rmt_bytes_encoder_config_t all. e.g.

rmt_bytes_encoder_init(rmt_encoder_handle_t bytes_encoder, const rmt_bytes_encoder_config_t *config);

I tried.
Because the source code of the rmt_new_bytes_encoder() function repeatedly requests the heap and stack.

iDF source code fole: rmt_encoder.c
esp_err_t rmt_new_bytes_encoder(const rmt_bytes_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
    esp_err_t ret = ESP_OK;
    ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
    rmt_bytes_encoder_t *encoder = heap_caps_calloc(1, sizeof(rmt_bytes_encoder_t), RMT_MEM_ALLOC_CAPS);
    ESP_GOTO_ON_FALSE(encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for bytes encoder");
    encoder->base.encode = rmt_encode_bytes;
    encoder->base.del = rmt_del_bytes_encoder;
    encoder->base.reset = rmt_bytes_encoder_reset;
    encoder->bit0 = config->bit0;
    encoder->bit1 = config->bit1;
    encoder->flags.msb_first = config->flags.msb_first;
    // return general encoder handle
    *ret_encoder = &encoder->base;
    ESP_LOGD(TAG, "new bytes encoder @%p", encoder);
err:
    return ret;
}

To implement modifying the parameters of the rmt_bytes_encoder_config_t structure without calling the rmt_new_bytes_encoder() function repeatedly.
I had to make changes to the IDF source code. Added a custom function to the 'rmt_encoder.c' file.


esp_err_t rmt_bytes_encoder_init(const rmt_bytes_encoder_config_t *config, rmt_encoder_t *encoder)
{
    esp_err_t ret = ESP_OK;
    rmt_bytes_encoder_t *bytes_encoder = __containerof(encoder, rmt_bytes_encoder_t, base);
    bytes_encoder->bit0 = config->bit0;
    bytes_encoder->bit1 = config->bit1;
    bytes_encoder->flags.msb_first = config->flags.msb_first;
    return ret; // always return  ESP_OK
}

That's what I wanted.
thanks。Thanks for the pointers.

@espressif-bot espressif-bot added Status: In Progress Work is in progress Status: Reviewing Issue is being reviewed and removed Status: Opened Issue is new Status: In Progress Work is in progress labels Dec 18, 2023
@espressif-bot espressif-bot added Status: Done Issue is done internally Resolution: NA Issue resolution is unavailable and removed Status: Reviewing Issue is being reviewed labels Jan 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Feature Request Feature request for IDF
Projects
None yet
Development

No branches or pull requests

3 participants