Receive CoAP Block messages on Thingy:53

Hello,

I am currently developing a CoAP client on the Thingy:53. For one task, the client has to send a request to a server on a Raspberry Pi which is based on the LibCoAP library and then gets a response with a payload. This works fine as long as the reply does not exceed the maximum CoAP message size of 1024 bytes. Therefore I wanted to send the reply with CoAP block transfer. LibCoAP provides a corresponding functionality. On the Thingy:53, I work with the OpenThread CoAP API. I am able to receive the first 1024 bytes of the message. The API provides this function: "otCoapSendRequestBlockWise", which takes a "otCoapBlockwiseReceiveHook" function pointer as one of the arguments. However, I was not able to handle the incoming block traffic properly and the Thingy reboots when the message arrives. It would be great if someone has some experience with using the OpenThread API on a nrf device to handle CoAP block transfer and may provide an example of how to use the receive hook. 

Thanks in advance and kind regards,

Simon

  • Hi Charlie

    Thanks for the fast reply. Yes, I already saw this post. The thing is however, that I try to receive a blockwise response from the server which is implemented with libcoap. This library provides a function that handles blockwise responses (https://libcoap.net/doc/reference/develop/man_coap_add_data_large_response.html#coap_add_data_large_response). I am able to receive the first block of 1024 bytes. But when I add the receive hook function in the request, the nrf device crashes as soon as the response arrives.

  • Hi Simon

    Are you able to share your code so we can try to reproduce the issue here?

    If you don't want to share your code in a public ticket I can make the case private. 

    Charlie is on travel this week, but he should be back next week.

    Best regards
    Torbjørn 

  • Hi, sorry for the late reply. Here some snippets of my code:

    This is the request I send from the Thingy:53 device to the server:

    static void get_request(struct k_work *item) {	
    	
    	ARG_UNUSED(item);
    
    	otError 		error = OT_ERROR_NONE;
    	otMessage 		*myMessage;
    	otMessageInfo 	myMessageInfo;
    	otInstance 		*myInstance = openthread_get_default_instance();
    	
    	LOG_INF("Send 'GET' request\n");
    
    	do{
    		myMessage = otCoapNewMessage(myInstance, NULL);
    		if (myMessage == NULL) {
    			printk("Failed to allocate message for CoAP Request\n");
    			return;
    		}
    		memset(&myMessageInfo, 0, sizeof(myMessageInfo));
    		myMessageInfo.mPeerPort = OT_DEFAULT_COAP_PORT;
    		otIp6AddressFromString(serverAddr, &myMessageInfo.mPeerAddr);
    		if (error != OT_ERROR_NONE){ 
    			printk("IPv6 Error\n");
    			break;
    		}
    
        	otCoapMessageInit(myMessage, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_GET);
        
    
    		otCoapMessageGenerateToken(myMessage, OT_COAP_DEFAULT_TOKEN_LENGTH);
    		error = otCoapMessageAppendObserveOption(myMessage, 0);
    		if (error != OT_ERROR_NONE){ 
    			printk("Append Observe Option Error\n");
        	}
        	
        	error = otCoapMessageAppendUriPathOptions(myMessage, "uri-path");
        	if (error != OT_ERROR_NONE){ 
        		printk("URI PATH FAIL\n");
        	}
        
        	error = otCoapMessageAppendContentFormatOption(myMessage, 
        										OT_COAP_OPTION_CONTENT_FORMAT_TEXT_PLAIN);
        	if (error != OT_ERROR_NONE){ 
        		printk("Content Error\n");
        	}
        	
        	error = otCoapMessageSetPayloadMarker(myMessage);
        	if (error != OT_ERROR_NONE){ 
        		printk("Set Payload Marker Error\n");
        	}
    	
    		if (error != OT_ERROR_NONE){ 
    			printk("CoAP message initialization error!\n");
    			break;
    		}
    
    		error = otCoapSendRequestBlockWise(myInstance, myMessage, &myMessageInfo,
    											default_response_handler, NULL, NULL, BlockwiseReceiveHook);
    	}
    	while(false);
    
    	if (error != OT_ERROR_NONE) {
    		printk("Failed to send GET request: %d\n", error);
    		otMessageFree(myMessage);
    	}
    	else{
    		printk("GET request sent success");	
    	}
    }

    And here the ReceiveHook function. This is currently just a test function to test if it even gets called:

    otError BlockwiseReceiveHook(void         *aContext,
    							const uint8_t *aBlock,
    							uint32_t       aPosition,
    							uint16_t       aBlockLength,
    							bool           aMore,
    							uint32_t       aTotalLength)
    {
    	printk("Receive Hook Function\n");
    
    	OT_UNUSED_VARIABLE(aContext);
        OT_UNUSED_VARIABLE(aMore);
        OT_UNUSED_VARIABLE(aTotalLength);
    
        return OT_ERROR_NONE;
    }

    By using the debugger, I found out that the ReceiveHook gets called at the arrival of the message but then crashes somewhere in the code where the first block of the response gets handled. 

    I am able to receive the block response with this CoAP client browser plugin, so the server seems to be able to send it properly: https://github.com/mkovatsc/Copper

    Thank you very much for your help! 

    Best wishes, Simon

  • Hi Simon,

    You can find a reference implementation of BlockwiseReceiveHook from openthread/cli_coap.cpp at main · openthread/openthread (github.com) or directly test with ot-cli commands sample,

    remember to Updating pre-built OpenThread libraries with OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE enabled, since this configuration is disabled by default.

    Best regards,

    Charlie

Related