Synchronous sock based messaging with nanocoap. More...
Synchronous sock based messaging with nanocoap.
nanocoap sock uses the nanocoap CoAP library to provide a synchronous interface to RIOT's sock networking API to read and write CoAP messages. For a server, nanocoap sock accepts a list of resource paths with callbacks for writing the response. For a client, nanocoap sock provides a function to send a request and waits for the server response. nanocoap sock uses nanocoap's Buffer API to write message options.
See the nanocoap_server example, which is built on the nanocoap_server() function. A server must define an array of coap_resource_t resources for which it responds. See the declarations of coap_resources
and coap_resources_numof
. The array contents must be ordered by the resource path, specifically the ASCII encoding of the path characters (digit and capital precede lower case). Also see Server path matching in the base nanocoap documentation.
nanocoap itself provides the COAP_WELL_KNOWN_CORE_DEFAULT_HANDLER entry for /.well-known/core
.
For each resource, you must implement a coap_handler_t handler function. nanocoap provides functions to help implement the handler. If the handler is called via nanocoap_server(), the response buffer provided to the handler reuses the buffer for the request. So, your handler must read the request thoroughly before writing the response.
To read the request, use the functions in the Header and Options Read sections of the nanocoap documentation. If the pkt payload_len attribute is a positive value, start to read it at the payload pointer attribute.
If a response does not require specific CoAP options, use coap_reply_simple(). If there is a payload, it writes a Content-Format option with the provided value.
For a response with additional CoAP options, start by calling coap_build_reply(). Then use the Buffer API to write the rest of the response. See the instructions in the section Write Options and Payload below.
Follow the instructions in the section Write Options and Payload below.
To send the message and await the response, see nanocoap_request() as well as nanocoap_get(), which additionally copies the response payload to a user supplied buffer. Finally, read the response as described above in the server Handler functions section for reading a request.
For both server responses and client requests, CoAP uses an Option mechanism to encode message metadata that is not required for each message. For example, the resource URI path is required only for a request, and is encoded as the Uri-Path option.
nanocoap sock uses the nanocoap Buffer API for options. The caller must provide the last option number written as well as the buffer position. The caller is primarily responsible for tracking and managing the space remaining in the buffer.
Before starting, ensure the CoAP header has been initialized with coap_build_hdr(). For a response, coap_build_reply() includes a call to coap_build_hdr(). Use the returned length to track the next position in the buffer to write and remaining length.
Next, use the functions in the Options Write Buffer API section of nanocoap to write each option. These functions require the position in the buffer to start writing, and return the number of bytes written. Options must be written in order by option number (see "CoAP option numbers" in CoAP defines).
If there is a payload, append a payload marker (0xFF). Then write the payload to within the maximum length remaining in the buffer.
Block-wise is a CoAP extension (RFC 7959) to divide a large payload across multiple physical packets. This section describes how to write a block-wise payload for a response, and is known as Block2. (Block1 is for a block-wise payload in a request.) See _riot_board_handler() in the nanocoap_server example for an example handler implementation.
Start with coap_block2_init() to read the client request and initialize a coap_slicer_t struct with the size and location for this slice of the overall payload. Then write the block2 option in the response with coap_opt_put_block2(). The option includes an indicator ("more") that a slice completes the overall payload transfer. You may not know the value for more at this point, but you must initialize the space in the packet for the option before writing the payload. The option is rewritten later.
Next, use the coap_blockwise_put_xxx() functions to write the payload content. These functions use the coap_block_slicer_t to enable or disable actually writing the content, depending on the current position within the overall payload transfer.
Finally, use the convenience function coap_block2_build_reply(), which finalizes the packet and calls coap_block2_finish() internally to update the block2 option.
Files | |
file | nanocoap_sock.h |
nanocoap high-level API | |
Functions | |
int | nanocoap_server (sock_udp_ep_t *local, uint8_t *buf, size_t bufsize) |
Start a nanocoap server instance. More... | |
ssize_t | nanocoap_get (sock_udp_ep_t *remote, const char *path, uint8_t *buf, size_t len) |
Simple synchronous CoAP (confirmable) get. More... | |
ssize_t | nanocoap_request (coap_pkt_t *pkt, sock_udp_ep_t *local, sock_udp_ep_t *remote, size_t len) |
Simple synchronous CoAP request. More... | |
ssize_t nanocoap_get | ( | sock_udp_ep_t * | remote, |
const char * | path, | ||
uint8_t * | buf, | ||
size_t | len | ||
) |
Simple synchronous CoAP (confirmable) get.
[in] | remote | remote UDP endpoint |
[in] | path | remote path |
[out] | buf | buffer to write response to |
[in] | len | length of buffer |
ssize_t nanocoap_request | ( | coap_pkt_t * | pkt, |
sock_udp_ep_t * | local, | ||
sock_udp_ep_t * | remote, | ||
size_t | len | ||
) |
Simple synchronous CoAP request.
[in,out] | pkt | Packet struct containing the request. Is reused for the response |
[in] | local | Local UDP endpoint, may be NULL |
[in] | remote | remote UDP endpoint |
[in] | len | Total length of the buffer associated with the request |
int nanocoap_server | ( | sock_udp_ep_t * | local, |
uint8_t * | buf, | ||
size_t | bufsize | ||
) |
Start a nanocoap server instance.
This function only returns if there's an error binding to local
, or if receiving of UDP packets fails.
[in] | local | local UDP endpoint to bind to |
[in] | buf | input buffer to use |
[in] | bufsize | size of buf |