COAP_CLIENT_LIB request issue

Hi.

I'm using nrf Connect SDK v3.0.1 and Zephyr v4.0.99 to implement a IoT device which connects to a Thingsboard server with CoAP. With the COAP_CLIENT Lib I want to download data in 945 chunks of 512 byte size.

I've used the coap_download example as a template for my implementation. I create the request and send it to the library with coap_client_req(). When the server responds, the callback function gets called in which I process the data (copy it to a queue in my case) and give a sem to tell the coap thread to cancel the request (coap_client_cancel_request()). This works as many times as I have configured in CONFIG_COAP_CLIENT_MAX_REQUESTS. After that the lib reports an error "No more free requests".

It looks for me that the cancel of the request didn't work. But maybe I didn't understand the usage of the COAP_CLIENT lib.
Are there any hints to use it correctly?

Thanks
BR
Christian

Parents
  • Well, since the path changes, you need to send a different request per chunk as you said. It indeed looks like the cancellation fails. Exactly where do you call coap_client_cancel_request() and what are your parameters? If you'd like, you could upload your source file or your callback function and I can have a look at it.


    It should look something like this:

    static void on_coap_response()
    {
        /* 1. Copy payload to your queue */
        copy_to_queue();
    
        /* 2. Free the slot immediately */
        coap_client_cancel_request();
    
        /* 3. Wake up the thread that will launch the next chunk */
        k_sem_give(&ready_sem);
    }
    

  • Hello.

    This is the callbackfunction:

    static void on_coap_download_chunk_response(int16_t result_code, size_t offset, const uint8_t *payload, size_t len, bool last_block, void *user_data)
    {
        coap_payload_t data;
    
        // Something was received, so restart keep alive timer.
        k_timer_start(&keep_alive_timer, K_MSEC(TX_KEEP_ALIVE_INTERVAL), K_MSEC(TX_KEEP_ALIVE_INTERVAL));
    
        LOG_INF("CoAP download chunk response, result_code=%d, offset=%u, len=%u, last_block=%d", result_code, offset, len, last_block);
    
        if (result_code == COAP_RESPONSE_CODE_CONTENT && last_block)
        {
            memcpy(data.payload, payload, MIN(len, CONFIG_COAP_CLIENT_BLOCK_SIZE));
            data.len = len;
            // Send it to the update task.
            k_msgq_put(&coap_payload_msgq, &data, K_FOREVER);
        }
    
        k_sem_give(&coap_download_chunk_done);
    }
    

    And this is the function for the request. It is called in a for loop with counting up chunk number in a thread:

    static int client_download_software_chunk(uint8_t *new_sw_title, uint8_t *new_sw_version, uint16_t chunkSize, uint16_t chunkNumber)
    {
        int ret;
        char path[100];
    
        /* Prepare the path for the request. */
        snprintf(path, sizeof(path), "sw/Fsau7Dg9Adfg4d?title=%s&version=%s&size=%d&chunk=%d", new_sw_title, new_sw_version, chunkSize, chunkNumber);
        LOG_INF("Download path: %s", path);
    
        /* Prepare the request parameters. */
        struct coap_client_request request = {.method = COAP_METHOD_GET,
                                              .fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
                                              .confirmable = true,
                                              .path = path,
                                              .payload = NULL,
                                              .len = 0,
                                              .cb = on_coap_download_chunk_response,
                                              .options = NULL,
                                              .num_options = 0,
                                              .user_data = NULL};
    
        /* Make the request. It will be added to the coap_client_rcv thread and handled by that. */
        ret = coap_client_req(&client, sock, NULL, &request, NULL);
        if (ret)
        {
            LOG_ERR("Failed to send CoAP request, err %d", ret);
            return ret;
        }
    
        /* Wait for CoAP request to complete */
        k_sem_take(&coap_download_chunk_done, K_FOREVER);
        /* Cancel this request because in the next request the path will change (because of chunknumber) and there are only a few
         * different requests possible. */
        coap_client_cancel_request(&client, &request);
        // k_sleep(K_MSEC(200));
        return 0;
    }
    

    Tell me if you need more information.

    Thank you.
    Best Regards

    Christian

Reply
  • Hello.

    This is the callbackfunction:

    static void on_coap_download_chunk_response(int16_t result_code, size_t offset, const uint8_t *payload, size_t len, bool last_block, void *user_data)
    {
        coap_payload_t data;
    
        // Something was received, so restart keep alive timer.
        k_timer_start(&keep_alive_timer, K_MSEC(TX_KEEP_ALIVE_INTERVAL), K_MSEC(TX_KEEP_ALIVE_INTERVAL));
    
        LOG_INF("CoAP download chunk response, result_code=%d, offset=%u, len=%u, last_block=%d", result_code, offset, len, last_block);
    
        if (result_code == COAP_RESPONSE_CODE_CONTENT && last_block)
        {
            memcpy(data.payload, payload, MIN(len, CONFIG_COAP_CLIENT_BLOCK_SIZE));
            data.len = len;
            // Send it to the update task.
            k_msgq_put(&coap_payload_msgq, &data, K_FOREVER);
        }
    
        k_sem_give(&coap_download_chunk_done);
    }
    

    And this is the function for the request. It is called in a for loop with counting up chunk number in a thread:

    static int client_download_software_chunk(uint8_t *new_sw_title, uint8_t *new_sw_version, uint16_t chunkSize, uint16_t chunkNumber)
    {
        int ret;
        char path[100];
    
        /* Prepare the path for the request. */
        snprintf(path, sizeof(path), "sw/Fsau7Dg9Adfg4d?title=%s&version=%s&size=%d&chunk=%d", new_sw_title, new_sw_version, chunkSize, chunkNumber);
        LOG_INF("Download path: %s", path);
    
        /* Prepare the request parameters. */
        struct coap_client_request request = {.method = COAP_METHOD_GET,
                                              .fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
                                              .confirmable = true,
                                              .path = path,
                                              .payload = NULL,
                                              .len = 0,
                                              .cb = on_coap_download_chunk_response,
                                              .options = NULL,
                                              .num_options = 0,
                                              .user_data = NULL};
    
        /* Make the request. It will be added to the coap_client_rcv thread and handled by that. */
        ret = coap_client_req(&client, sock, NULL, &request, NULL);
        if (ret)
        {
            LOG_ERR("Failed to send CoAP request, err %d", ret);
            return ret;
        }
    
        /* Wait for CoAP request to complete */
        k_sem_take(&coap_download_chunk_done, K_FOREVER);
        /* Cancel this request because in the next request the path will change (because of chunknumber) and there are only a few
         * different requests possible. */
        coap_client_cancel_request(&client, &request);
        // k_sleep(K_MSEC(200));
        return 0;
    }
    

    Tell me if you need more information.

    Thank you.
    Best Regards

    Christian

Children
No Data
Related