Thread provides basic services required for application frameworks implementation with the usage of Unicast and Multicast transmissions over UDP.
Thread specification is only focused on the network layer; many application layers can be designed to run without any problem as it is application layer agnostic.
In this laboratory the user will work with the Constrain Application Protocol (CoAP) for this application layer as the Thread stack uses CoAP for most of the multi-hop network management and commissioning messages.
The Constrained Application Protocol (CoAP) is a specialized web transfer protocol to use with constrained nodes and constrained networks in the Internet of Thing. It uses a binary RESTful protocol with four methods
CoAP also uses ACK responses; CONfirmable (ACK requested) and NONconfirmable messages.
The Thread stack uses CoAP for the majority of multi-hop network management and commissioning messages
Through this laboratory the user will modify the firmware to achieve the following list:
The process desired behavior by the laboratory is shown in figure 1.
Figure 1 Diagram showing the desired behavior of the laboratory
Setup
In the following list, the components with a dash (—) will be the ones used to create this laboratory.
— Rev. A
— Thread Router Eligible Device project
— TeraTerm
Figure 2 FRDM-KW41Z
The following changes will be made in the router_eligible_device_app.c file.
1. Define the URI path names that will be used in the shell to access the resources.
#define APP_RESOURCE1_URI_PATH "/resource1"
#define APP_RESOURCE2_URI_PATH "/resource2"
2. Declare the URI resources with coapUriPath_t. When using this struct the user must enter the length of the URI path and the path created in the last step.
const coapUriPath_t gAPP_RESOURCE1_URI_PATH = {SizeOfString(APP_RESOURCE1_URI_PATH), APP_RESOURCE1_URI_PATH};
const coapUriPath_t gAPP_RESOURCE2_URI_PATH = {SizeOfString(APP_RESOURCE2_URI_PATH), APP_RESOURCE2_URI_PATH};
3. Create the callbacks for the resources. This callbacks will handle the packet received and perform the desired action depending on the type of COAP method received.
static void APP_CoapResource1Cb(coapSessionStatus_t sessionStatus, void *pData, coapSession_t *pSession, uint32_t dataLen);
static void APP_CoapResource2Cb(coapSessionStatus_t sessionStatus, void *pData, coapSession_t *pSession, uint32_t dataLen);
4. Add the callback handler for the packet received, in this function it will be defined which action will be performed depending on the type of COAP method received.
static void APP_CoapResource1Cb ( coapSessionStatus_t sessionStatus, void *pData, coapSession_t *pSession, uint32_t dataLen ) { static uint8_t pMySessionPayload[3]={0x31,0x32,0x33}; static uint32_t pMyPayloadSize=3; coapSession_t *pMySession = NULL; pMySession = COAP_OpenSession(mAppCoapInstId); COAP_AddOptionToList(pMySession,COAP_URI_PATH_OPTION, APP_RESOURCE2_URI_PATH,SizeOfString(APP_RESOURCE2_URI_PATH)); if (gCoapConfirmable_c == pSession->msgType) { if (gCoapGET_c == pSession->code) { shell_write("'CON' packet received 'GET' with payload: "); } if (gCoapPOST_c == pSession->code) { shell_write("'CON' packet received 'POST' with payload: "); } if (gCoapPUT_c == pSession->code) { shell_write("'CON' packet received 'PUT' with payload: "); } if (gCoapFailure_c!=sessionStatus) { COAP_Send(pSession, gCoapMsgTypeAckSuccessChanged_c, pMySessionPayload, pMyPayloadSize); } } else if(gCoapNonConfirmable_c == pSession->msgType) { if (gCoapGET_c == pSession->code) { shell_write("'NON' packet received 'GET' with payload: "); } if (gCoapPOST_c == pSession->code) { shell_write("'NON' packet received 'POST' with payload: "); } if (gCoapPUT_c == pSession->code) { shell_write("'NON' packet received 'PUT' with payload: "); } } shell_writeN(pData, dataLen); shell_write("\r\n"); pMySession -> msgType=gCoapNonConfirmable_c; pMySession -> code= gCoapPOST_c; pMySession -> pCallback =NULL; FLib_MemCpy(&pMySession->remoteAddr,&gCoapDestAddress,sizeof(ipAddr_t)); COAP_SendMsg(pMySession, pMySessionPayload, pMyPayloadSize); shell_write("'NON' packet sent 'POST' with payload: "); shell_writeN((char*) pMySessionPayload, pMyPayloadSize); shell_write("\r\n"); } |
There can be one COAP instance per UDP port, in case the application only uses one port, one instance will be enough.
There can be multiple COAP sessions per instance, a COAP session is per packet/transaction. In this case as the desired result was to have a different response of the ACK, it will be necessary to create a new session with the new resource.
static void APP_CoapResource2Cb ( coapSessionStatus_t sessionStatus, void *pData, coapSession_t *pSession, uint32_t dataLen ) { if (gCoapNonConfirmable_c == pSession->msgType) { shell_write("'NON' packet received 'POST' with payload: "); shell_writeN(pData, dataLen); shell_write("\r\n"); } } |
5. After creating the callbacks, those must be registered in the CoAP callback array in the function APP_InitCoapDemo(void)
{APP_CoapResource1Cb, (coapUriPath_t*)&gAPP_RESOURCE1_URI_PATH},
{APP_CoapResource2Cb, (coapUriPath_t*)&gAPP_RESOURCE2_URI_PATH},
There are some things to mention of the usage of the CoAP library that were not used for this laboratory but might be useful for other types of applications.
When using COAP_SendMsg() the session will close automatically by default unless it is indicated with the usage of pSession->autoClose.
There are two options while sending the message:
Confirmable (CON): It waits for an ACK reply and until it gets the message it will close the session or it will close the session when retransmissions are exhausted.
Non-confirmable (NON): For NON, immediately after sending the message.
In case a message was sent and there was no response a retransmission will be sent each COAP_ACK_TIMEOUT (in miliseconds), the retransmissions are sent exponentially: first after random (2, 3) seconds, next doubles the timeout and so on, until COAP_MAX_RETRANSMIT is reached.
After retransmissions stop, the session is automatically closed and informs the application of failure the application callback will be called with status gCoapFailure_c.
When the callback is called the current session is still valid, but CoAP session will close it after exiting the function. There are two different work this out:
A new session must be created
Set pSession->autoClose = FALSE. If autoClose is set to FALSE, without forgetting to close the session from application, using COAP_CloseSession().
1. Download the modified firmware in the boards
2. Open a serial terminal for each board with a baud rate of 115200
Figure 3 Serial terminal and its configuration
3. In one of the board’s terminal type “thr create”, this board will be the leader.
Figure 4 Board 1 with command "thr create"
Figure 5 Board 1 after the command "thr create"
4. Once the network has been created type “thr join” in the second board’s terminal.
Figure 6 Board 2 with command "thr join"
Figure 7 Board 2 after command "thr join"
5. In both serial terminals type the command “ifconfig”. This command will display all the addresses of the board.
Figure 8 Board 1 after command "ifconfig"
Figure 9 Board 2 after command "ifconfig"
6. To test the callbacks created, a CoAP message must be sent. The following command must be typed;
coap <type> <method> <address> <URI> <payload>
|
coap CON POST fe80::5df0:2bf0:d69b:1b3c /resource1 hello
|
Figure 10 CoAP command to send
7. The result of sending must look like :
— Board 1
The board 1 will request the board 2 the resource1
Figure 11 Board 1 before sending the CoAP command
As it was coded the other board will send an ACK and print the message.
Figure 12 Board 1 after sending the CoAP command
— Board 2
Figure 13 Board 2 after receiving the CoAP command
If using the CON message the requester board will receive a response, while if the message is a NON type it will not have the response.
When using this types of messages independently of the package type when sending a message a new session will be open and it will send a NON type of message.