[ell-i-developers] Initial spec for a CoAP API

  • From: Pekka Nikander <pekka.nikander@xxxxxx>
  • To: ell-i-developers@xxxxxxxxxxxxx
  • Date: Tue, 25 Feb 2014 22:26:44 +0200

I have now a preliminary skeleton for the CoAP API and some initial code for 
the implementation; far from ready though.

For the API, the idea is to define CoAP URLs at compile time, storing all the 
data structures in the flash, in a manner similar to how we handle peripheral 
initialisation now.

As an example of a temperature sensor, the API might look like the following:

static void temp_sensor_get(char *buffer, const char *format) {
    iprintf(buffer, format, ...);

DEFINE_COAP_GET_URL("/sensors/temp", temp_sensor_get, 
    { COAP_FORMAT_TEXT_PLAIN,       "%d" },
    { COAP_FORMAT_APPLICATION_JSON, "{ \"temperature\": \"%d\" }");

The idea is that this compiles into a statically allocated data structure that 
the linker makes available to the CoAP protocol part that handles GET urls.  

The GET handler will go through all of the GET URL data structures (linearly at 
this phase), until it finds a match with the requested URL.  When a match is 
found, it calls a callback function (temp_sensor_get in this case), passing it 
a pointer to a buffer where the result should be formatted (a pointer to the 
right place in the packet), and a pointer to a template for formatting the 
result.  The implementation may support multiple content formats, as can be 
seen.  The first one is the default one if the client does not specify what 
format it would like or if the requested format is not available.  

The callback function must not block.  In the first implementation it will run 
in the interrupt context; we will move the processing to the threading context 
only once we'll have thread support in the new runtime.  Even once moved to a 
threading context, it SHALL produce the result within CoAP ACK_TIMEOUT, which 
is currently 2 seconds.

I don't like much the idea that we must include iprintf() for this to work, but 
so far I haven't figured out any better idea on how to format the results, 
either.  Of course, the API does not necessitate the use of iprintf(), but 
without it e.g. generating JSON or XML replies is somewhat complicated and may 
produce so large code that using iprintf() is well justified.  But YMMV; 
opinions sought.

The PUT API is likely to be very similar, but I haven't yet been able to figure 
out what is the best way to parse the content.  sscanf() is too bulky and 
insecure.  I think I will leave that to the handler so that it can parse in an 
ad-hoc manner, most probably only supporting plain text messages in an 
application-specific format.  Good ideas here would be very welcome.

I'm not planning to support POST or DELETE methods.

Comments?  Suggestions for improvements?

If you need more background, please have a look at these:



On 2014–02–25, at 19:22 , Pekka Nikander <pekka.nikander@xxxxxx> wrote:

> I have now a skeleton written for UDP and IP; I'm writing a skeleton for CoAP.
> This very first version will *NOT* be compatible with the Arduino Ethernet 
> library, but will be more minimal, with all sockets and CoAP URLs 
> compile-time allocated.  In this way it consumes less RAM and flash.  And is 
> easier to write.
> I expect to have a first working but untested version ready on Thursday; 
> perhaps already tomorrow.
> ARP, ICMP and DHCP are still completely missing, but we can test the stack 
> without them.
> --Pekka

Other related posts: