This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Coap message type, confirmable/non-confirmable

Hello,

I am using the coap Client example from nRF Connect SDK, which uses the Coap utils library https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/include/net/coap_utils.html

As stated in the documentation, this library only enables non-confirmable communication, since in the source file ncs\nrf\subsys\net\lib\coap_utils\coap_utils.c, the application level function used, coap_send_request(), calls coap_init_request() with hardcoded COAP_TYPE_NON_CON coap_msgtype. I reckon changing this would not help. How can I achieve confirmable communication with the coap client example? Do I need to enable another coap library than coap utils?

The coap server example, which uses the openthread coap api, however, calls otCoapMessageInit()  at application level, which takes an otCoapType aType argument. Thus, it looks like the openthread coap api supports confirmable coap communication. Is this correct? I have not tested this yet.

Another thing, in the header of coap_send_request() in coap_utils.h, it says

 * @retval 0    On success.
 * @retval != 0 On failure.
However, the return value of the functions called from in coap_send_request() is only checked against a negative value. Indeed, according to the headers of the functions called in coap_init_request(), which is called by coap_send_request(), only a negative value should indicate an error. The second and last function returning an error code in coap_send_request() is coap_send_message(), but I cannot find any documentation of the return value of sendto() called by this function. Is the header of coap_send_request() wrong?
I have seen return values such as e.g. 38 and 48 from my coap_send_request() calls, but I am still receiving the packets. So what do these numbers indicate?
Parents
  • Hello,

    Sorry for the late reply. I had to check in with our Thread team.

    The coap_utils does not support confirmable communication for now. The easiest way to acheive confirmable coap communication is to use OpenThread CoAP API in a similar way to how it is presented in the coap_server sample.

    There is a bug in the coap_utils.h description. In fact, coap_send_request() returns retval >= 0 on sucess, and retval < 0 on failure.

    Zephyr sendto() description:

    https://docs.zephyrproject.org/latest/reference/networking/sockets.html?highlight=sendto#c.zsock_sendto

    Thank you for reporting the retval description bug. It has been fixed now:

    https://github.com/nrfconnect/sdk-nrf/pull/2899/commits

    Hopefully, this answers some of your questions.

    Best regards,

    Edvin

  • I understand, thank you.

    I tried to change to the OpenThread CoAP API by doing this:

    However, nothing is received by the server. No error messages are printed either, the program executes the whole function.

    If I use the Zephyr CoAP API with the same IPv6 address as I have used in the example above, it works fine:

    Is there anything obviously wrong with the function calls in the OpenThread CoAP example? Indeed, I have added the resources with the appropriate URI options, which I guess is confirmed by the fact that it works with the Zephyr implementation.

    For the record, I have merged together the client and server example in the ncs so both are able to initiate traffic on the same port.

  • Hello, I fixed the problem by using the coap type OT_COAP_CODE_CONTENT instead of OT_COAP_CODE_PUT in the ack response.

    I cannot find any documentation of what the different otCoapCode enumerations really means in terms of the coap api implementations. What difference did this change make?

  • Hello,

    The enumeration that defines OT_COAP_CODE_CONTENT is part of the openthread repository (particularly this file), so I don't know any more than what this says.

    In what function call did you use OT_COAP_CODE_CONTENT instread of OT_COAP_CODE_PUT?

  • Yes, I have seen that documentation and it virtually says nothing.

    When I acknowledge a confirmable message, I now use OT_COAP_CODE_CONTENT instead of OT_COAP_CODE_PUT and the sender receives the acknowledgement and stops resending the confirmable message. When I used OT_COAP_CODE_PUT, the sender never received an ack and eventually timed out. Therefore, there has to be something very different going on in the openthread api depending on the coap codes, and it would be advantageous for me to know what.

    I have not tried other coap types as it works with OT_COAP_CODE_CONTENT. As you can see, there is quite many - without any particular documentation on what the differences are. Indeed, one could use it as an "opcode" and dispatch the receiver to the right event handler, but there have to be more happening "under the hood" since there are api side effects depending on what coap type you choose.

  • Edvin said:
    In what function call did you use OT_COAP_CODE_CONTENT instread of OT_COAP_CODE_PUT?

     I am sorry if this is really obvious, but can you please let me know where you use this?

    Have you tried sniffing the connection when you use OT_CPAP_CODE_CONTENT and OT_COAP_CODE_PUT? Does it behave different? I obviously does, but if this is a bug, then a sniffer trace like this can help resolve what the issue is.

  • When I send a confirmable message, I do something like this: 

    otCoapSendRequest(srv_context.ot, request, &messageInfo, ack_handler, NULL);
    Upon receiving a confirmable message, i.e.:
    otCoapMessageGetType(message) == OT_COAP_TYPE_CONFIRMABLE
    I do the following for acking:
    static void send_acknowledgement(const otMessage *message, const otMessageInfo *message_info)
    {
    	otMessageInfo messageInfo = get_message_info((const uint8_t*)message_info->mPeerAddr.mFields.m8);
    
    	otMessage* response = otCoapNewMessage(srv_context.ot, NULL);
    	if (response == NULL) {
    		printk("New message error\n");
    		return;
    	}
    
    	otCoapMessageInitResponse(response, message, OT_COAP_TYPE_ACKNOWLEDGMENT, OT_COAP_CODE_CONTENT);
    
    	otError error = otCoapMessageAppendUriPathOptions(response, COMMUNICATION_URI_PATH);
    	if (error != OT_ERROR_NONE) {
    		printk("URI error\n");
    		return;
    	}
    
    	error = otCoapSendResponse(srv_context.ot, response, &messageInfo);
    	if (error != OT_ERROR_NONE) {
    		printk("Send error\n");
    		return;
    	}
    }
    When I use the PUT coap code, I get a timeout error in the ack_handler() provided in otCoapSendRequest(), whereas when I use CONTENT it works as expected.
    No, I have not tried to sniff the communication. I will try to do that when I have time to do so.
Reply
  • When I send a confirmable message, I do something like this: 

    otCoapSendRequest(srv_context.ot, request, &messageInfo, ack_handler, NULL);
    Upon receiving a confirmable message, i.e.:
    otCoapMessageGetType(message) == OT_COAP_TYPE_CONFIRMABLE
    I do the following for acking:
    static void send_acknowledgement(const otMessage *message, const otMessageInfo *message_info)
    {
    	otMessageInfo messageInfo = get_message_info((const uint8_t*)message_info->mPeerAddr.mFields.m8);
    
    	otMessage* response = otCoapNewMessage(srv_context.ot, NULL);
    	if (response == NULL) {
    		printk("New message error\n");
    		return;
    	}
    
    	otCoapMessageInitResponse(response, message, OT_COAP_TYPE_ACKNOWLEDGMENT, OT_COAP_CODE_CONTENT);
    
    	otError error = otCoapMessageAppendUriPathOptions(response, COMMUNICATION_URI_PATH);
    	if (error != OT_ERROR_NONE) {
    		printk("URI error\n");
    		return;
    	}
    
    	error = otCoapSendResponse(srv_context.ot, response, &messageInfo);
    	if (error != OT_ERROR_NONE) {
    		printk("Send error\n");
    		return;
    	}
    }
    When I use the PUT coap code, I get a timeout error in the ack_handler() provided in otCoapSendRequest(), whereas when I use CONTENT it works as expected.
    No, I have not tried to sniff the communication. I will try to do that when I have time to do so.
Children
No Data
Related