CoAP client and CoAP server examples  [Mongoose more than an Embedded Web Server]

Alexander Alashkin, Oct 26, 2016 02:37 PM

In this blogpost, I’m going to show how to implement a CoAP client and a CoAP server with Mongoose Embedded Web Server.

To start off, download the Mongoose source code from here.

CoAP Client

Running client example

To build this example type make in mongoose/examples/coap_client folder on GitHub.

Now execute coap_client

You’ll see an output like this:

$ ./coap_client
Using udp://coap.me:5683 as CoAP server
Sending CON...
Sent CON with msg_id = 1
ACK/RST for message with msg_id = 1 received

 

This examples connects to a CoAP server (coap.me by default, you can specify any server as a comand line argument: ./coap_client udp://mycoapserver.com:888), sends a test message, waits for the response and exists.

Pretty simple application, that can be adapted to your needs.

Let’s take a look that works.

Client code explained

First of all, we need to perform the usual Mongoose tasks: initialise Mongoose manager, create an outbound connection and choose the protocol to use. In this case we choose CoAP:

 mg_mgr_init(&mgr, 0);
 nc = mg_connect(&mgr, address, coap_handler);
 /* Check for errors here! */
 mg_set_protocol_coap(nc);

And then run the polling loop, like this:

 

 while (!s_time_to_exit) {
   mg_mgr_poll(&mgr, 1000);
 }

Now the main thing: the event handler:

 static void coap_handler(struct mg_connection *nc, int ev, void *p) {
 switch (ev) {
   case MG_EV_CONNECT: {
     struct mg_coap_message cm;
     uint32_t res;

     memset(&cm, 0, sizeof(cm));
     cm.msg_id = 1;
     cm.msg_type = MG_COAP_MSG_CON;
     printf("Sending CON...\n");
     res = mg_coap_send_message(nc, &cm);
     if (res == 0) {
       printf("Sent CON with msg_id = %d\n", cm.msg_id);
     } else {
       printf("Error: %d\n", res);
       s_time_to_exit = 1;
     }
     break;
   }
   case MG_EV_COAP_ACK:
   case MG_EV_COAP_RST: {
     struct mg_coap_message *cm = (struct mg_coap_message *) p;
     printf("ACK/RST for message with msg_id = %d received\n", cm->msg_id);
     s_time_to_exit = 1;
     break;
   }
 }
}

Here we handle three events: MG_EV_CONNECT, MG_EV_COAP_ACK and MG_EV_COAP_RST.

MG_EV_CONNECT is a general Mongoose event which occurs when the connection is established. Since Mongoose implements CoAP over UDP, it is just an event and everything is ready to go. So here we go! We use the mg_coap_send_message function to send a test message. The first parameter is a connection to use, while the second is a structure that describes the message. See Mongoose documentation for details; actually this structure uses the same terms as RFC 7252 does, so, you can refer to RFC 7252 as well.

MG_EV_COAP_ACK and MG_EV_COAP_RST are CoAP specific events which are invoked if ACK and RST received.

CoAP Server

Running server example

Ok, the next stop is the server. Go to mongoose/examples/coap_server folder and run make.

Then run the coap_server

$ ./coap_server 
Listening for CoAP messages at udp://:5683

Now, we have a CoAP server listening on port 5683.

Run the coap_client from the previous chapter with the parameter udp://127.0.0.1:5683 (if you are running both samples on the same computer, otherwise replace 127.0.0.1 with right IP address).

Client output should look like this:

$ ./coap_client udp://127.0.0.1:5683
Using udp://127.0.0.1:5683 as CoAP server
Sending CON...
Sent CON with msg_id = 1
ACK/RST for message with msg_id = 1 received

Almost the same as in previous chapter, but we are using the coap.me server.

As for the coap_server output, it will be the following:

$ ./coap_server 
Listening for CoAP messages at udp://:5683
CON with msg_id = 1 received
Successfully sent ACK for message with msg_id = 1

So, the server received the message, printed its ID and sent acknowledgement (ACK, in CoAP terms).

Server code explained

The server code starts as any Mongoose-based server does:

  mg_mgr_init(&mgr, 0);
 nc = mg_bind(&mgr, s_default_address, coap_handler);

 mg_set_protocol_coap(nc);

 while (!s_sig_received) {
   mg_mgr_poll(&mgr, 1000);
 }

All we do, is to initialise Mongoose, create a listening connection, choose a CoAP protocol and start a polling loop.

And, as in any Mongoose-based server the details are in the events handler:

static void coap_handler(struct mg_connection *nc, int ev, void *p) {
 switch (ev) {
   case MG_EV_COAP_CON: {
     uint32_t res;
     struct mg_coap_message *cm = (struct mg_coap_message *) p;
     printf("CON with msg_id = %d received\n", cm->msg_id);
     res = mg_coap_send_ack(nc, cm->msg_id);
     if (res == 0) {
       printf("Successfully sent ACK for message with msg_id = %d\n",
              cm->msg_id);
     } else {
       printf("Error: %d\n", res);
     }
     break;
   }
   case MG_EV_COAP_NOC:
   case MG_EV_COAP_ACK:
   case MG_EV_COAP_RST: {
     struct mg_coap_message *cm = (struct mg_coap_message *) p;
     printf("ACK/RST/NOC with msg_id = %d received\n", cm->msg_id);
     break;
   }
 }
}

Well, it is an example, so, this event handler does almost nothing. It waits for the MG_EV_COAP_CON event and once it occurs (that means that the CON message was received) sends ACK to the sender. There is a helper to send ACK - mg_coap_send_ack function. It takes the connection and message ID as parameters and sends ACK.

The rest of the events are basically ignored, this sample just prints information that they were received.

Wrapping up

Although CoAP isn’t the simplest protocol to use, we do our best to make its usage as simple possible. Read CoAP RFC (7252) for protocol details and Mongoose documentation for learning the API provided for CoAP.

And happy hacking!

Mongoose Embedded Web Server Source Code

Comments