Skip to content

μcuREST – an application server for constrained platforms

Introduction

μcuREST (micurest) is a C++11 library for implementing REST services on constrained platforms, such as bare metal applications on low-end MCUs. The library is platform-agnostic, zero-allocation, and has almost no external dependencies. It allows mapping hierarchically organized URIs to C/C++ variables, constants and methods, and exposing the URIs via HTTP protocol.

Architecture

Diagram 1
Legend

Diagram on the left shows architecture of a RESTful application, implemented with μcuREST library. The latter facilitates the Core, a set of Content Providers and a set of Resource Mapping Templates. For some platforms, μcuREST also provide implementation of I/O stream interfaces to platform specific Transport Layer. The Application provides content (variables, functions, methods) and a Resource Map, which is the key part of application’s design. This map statically (at compile time) associates application content with URIs and content providers.

Transport Layer

An application, implementing HTTP RESTful services with μcuREST, needs a platform specific transport layer and a mediator (Session Layer in terms of OSI model) between μcuREST and the transport layer. The mediator must handle sessions and implement two interfaces: istream and ostream.

Resource Map

Resource map is defined with C++ language, using a set of templates. Example of a simple map is given on Example 1, a more complicated example available on Example 2.

/* map of URIs to application resources */
const directory& resourceMap() noexcept {
  return Root<
    resource::FileConstString<name::hello_html, hello_html_content, media::html>,
    resource::FileText<name::hello, sizeof(hello_text), hello_text>,
    resource::FileFunctions<name::led, bool, getLed, setLed>
  >();  
}
/* map of URIs to application resources
 * D defines a directory,
 * E defines an entry with a name and content node
 * N defines a content node
 * F combines E and N in one for simple content, such as variables
 */
const directory& resourceMap() noexcept {
	return Root<		/// this notation documents URI of the resource
		/*		cost of adding another page: 190/28							*/
		/* first entry that matches accepted content is served by default	*/
		E<name::io,   Embed<io>>,
		/* directory d	 													*/
		D<name::d,
			E<name::X,
				N<V<micurest::accessor::vector<byte,
					digital_read, digital_write, digital_has>>>>,
			E<identity::numeric,
				N<micurest::accessor::vector<byte,
					digital_read, digital_write, digital_has>>>>,
		/* directory r	 													*/
		D<name::r,
			E<name::X,
				N<V<micurest::accessor::vector<byte,
					relay_read, relay_write, relay_has>>>>,
			E<identity::numeric,
				N<micurest::accessor::vector<byte,
					relay_read, relay_write, relay_has>>>>,
		/* directory a	 													*/
		D<name::a,
			E<name::X,
				N<V<micurest::accessor::bunch<int,
					analog_read, analog_has>>>>,
			E<identity::numeric,
				N<micurest::accessor::bunch<int,
					analog_read, analog_has>>>>,
		/* directory in	 													*/
		D<name::in,
			E<name::X,
				N<V<micurest::accessor::bunch<byte,
					interrupt_read, interrupt_has>>>>,
			E<identity::numeric,
				N<micurest::accessor::bunch<byte,
					interrupt_read, interrupt_has>>>>,
		E<name::X, json_node>,
		F<name::blob,&blob_length, sizeof(blob), blob>,
		F<name::mode, pointer<enums::mode_t, &mode>>,
		E<name::modes,
			N<enums::list<enums::mode_names>>>,
		E<name::ip, N<V<ip_addr, &ip>>>,
		E<name::mac, N<V<mac_addr, &mac>>>,
		E<name::rtc, Object<datetime>>,
		E<name::demo, Embed<demo>>,
		F<name::natural, pointer<unsigned, &natural>>,
		F<name::logical, pointer<bool, &logical>>,
		F<name::text, countof(text), text>
	>();
}

Limitations

μcuREST implements a minimal subset of HTTP specification, sufficient for serving GET requests from browsers, GET/PUT/POST requests from JavaScript via XMLHttpRequest and simple machine-to-machine communications. Only normalized case-sensitive URIs are supported. Query strings, cookies, absolute URLs, cache control, transfer encoding, and many other HTTP features are not supported. Support for authentication is currently in consideration.

Depending on the transport layer in use and the mediator implementation, HTTM message size could be limited to the size of one MTU (~1460 bytes).

Principle of Operation

Control flow

1. When a client sends an HTTP requests, the Transport Layer receives it and makes the data available to the application.
2. The Session Layer detects presence of the data, creates I/O streams to interface the data, and calls μcuREST for servicing the request.
3. μcuREST starts parsing the HTTP header and, as it progresses with URI, calls resource map for finding a Content Provider matching the URI.
4. When the HTTP header is parsed, μcuREST calls the matched Content Provider to process message body (if such is available).
5. The Content Provider reads message body, parses it in its specific way and delivers content to the associated application’s variable or function.
6. If parsing and content delivery finishes with success, μcuREST starts writing success HTTP response and calls the Content Provider to write message body.
7. The Content Provider obtains content from the application’s variable or function, formats the data in its specific way and writes the message body. When message servicing complete the Session Layer finishes the session and closes connection (unless keep-alive is present in the header and supported by the Transport Layer)

Requirements

  • Compiler: μcuREST sources need a C++11 enabled compiler, such as g++-4.8 and up.
  • Library: libstdc++ v3 highly desirable. But if not available a workaround exists
  • Transport layer: A platform specific transport layer, such as TCP/IP, is required for implementing HTTP REST services.
  • ROM/RAM space: on AVR platform μcuREST core takes 6K of ROM and 100 bytes of RAM. Size of the resource map starts with 3K/200 and grows with its complexity, taking in average 750 bytes of ROM and 250 bytes of RAM per entry.

Screenshots

Below you may find screenshots of web pages, implemented in examples for Controllino MAXI, ESP8266 NodeMCU and Particle Photon

NodeMCU GPIO Panel

NodeMCU Demo Panel

NodeMCU Status Panel

NodeMCU Setup Panel

Controllino I/O Panel

Controllino Demo Panel

ATmega2560 JSON-RPC via Dev.Tool

Photon JSON-RPC Panel

Photon JSON-RPC via Dev.Tool

ATmega2560 JSON-RPC Panel

Related Materials

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*

*