This article discusses one of the typical development cycles in embedded device and communication design and presents a possible, light weight solution using the free DClib/netpp framework.

Well, we're not saying, we're there yet. But we're getting closer...

Make all devices just so intelligent that they can speak to each other, and tell you what they are capable of.

A simple way of making the device report all it can do - the property list

Light weight and compact code generation - we want the least manual coding possible!

Most abstract and generic description language for hardware entities like registers, commands, and also abstract 'Properties'

Well, as you would guess, none of these solutions really 'did it' for us. Why is that? We could list all the pros and cons for each of the above in detail, but generally, the problem was the abstraction and the code complexity, or just the fact that they're not opensource or license free. The Google Protocol buffers appear most simple, but they lack a specific hardware definition. Specific hardware protocols such as modbus are too unflexible and feature too little abstraction. A web server is kinda out of scope as well, for example, you wouldn't want to implement a web client in a device just to communicate with another device. If you did, you would have to parse a lot of irrelevant data -- well, a web interface is just not made for that.

Well, there are quite a number of existing solutions that try to tackle the abstraction problem of remote control and property description. Let us list a few:

What again is not standardized, is, how you communicate on the abstract level, rising the rhethorical questions for example: Do you operate/configure the device via touch screen? Or a web interface? Or a TCP protocol, a login shell, or an USB library? How do you see all operation modes and properties the device has? And how does the device internally react, when you change a property, do you show the front end user settings, commands, or even function calls?

When it comes to interfacing with a user or another device, things can and do have to become more bureaucratic: An interface must be properly standardized, otherwise it will not work right.

Many intelligent devices nowadays are equipped with a more complex operating system (OS) and USB interface or even Ethernet. Quite a number of black boxes have a (uC)linux OS running under the hood, there are plenty of open reference designs around, enabling a short design cycle. We can conclude from that that many of these OSes are considered as standard, even if the possibly bureaucratic approval instance might be missing.

Assume we're faced with the design of an embedded device, be it a simple SoC unit or a more complex, uC controlled engine with various attached peripherals. From first prototype to the market, the following development cycle is typically walked through:

DClib - the device control library

The basic idea behind the DClib is:

Write a device description file, preferrably using an entry form or style sheet based editor

Automatically turn the device description into a slave (embedded device) library that runs on the embedded target

Speak to all your devices with one single, unified client module.

But we're not done yet with the shopping list: We need to elaborate methods to actually access hardware entities. As a hardware developer, you might be used to deal with:

a low level register based protocol such as i2c, SPI, ...

single bit fields that need to be accessed within a register

As a firmware developer, you may have to deal with:

local configuration variables in uC memory

code that sets and gets register values based on the peripheral's protocol

other handler code controlling the operation modes of the device

Ideally, you would want to have this automatized and somewhat abstracted, but not too far. So, assuming that the DClib framework takes off some burden, what coding requirements would you be left width?

This should give you a quick idea, but isn't the whole story:

You write a device_read() and device_write() method to access one or several peripherals on your target (using software address decoding) You implement some global variables for the configuration (preferrably in a current context structure) You wrap some of the devices functionality that can't be covered with registers or variables into Getter and Setter functions.

But let us now look at the technique to describe the hardware.

The Device Description: XML There was not really a search needed to find the right language for device description. It's pretty obvious: from all kinds of web standards, XML is the most simple one - and its transform methods into other sources are well defined using the XSLT standards guarded by the W3C. What we get with XML: Validation: Prevent the user from writing the 'wrong' XML dialect

Translation: Translate XML into a large number of desired formats using XSLT style sheets and standardized processors

A large number of editors supporting adaptable style sheets Ok, so now you might say: Nothing new, that's just XMLRPC, right? No, it isn't. Remember that XMLRPC really passes plain XML data (i.e. structures) around. So it needs an XML parser on client and server (or master and slave) side. This turns out in a very bloated and rather academic solution which won't run on a simple uC or FPGA. Well, from the above item concerning translation, you could guess: We translate the XML into compact C code. So, we can create a library that wraps register procotol accesses into properties. That means, a somewhat CPU featured control instance can access an abstract Property list and does not have to bother about a low level protocol. Whether the library is running on a PC or inside the target is a priori irrelevant, or based on the abstraction level you wish to expose to the outside world. But we'll get to that later in the section called “netpp - The network property protocol”. One important aspect of development is always a certain learning curve and potential booby traps that can cost you time or cause frustration from the beginning. Remember, we want to save us some work, not create more. This is where a validating editor steps in. We need a easy to use interface which presents us a structure - and a choice of possible elements that can be inserted to the structure. To elaborate for the example of a device: Our 'root node', using geek terms, is typically the device entity. Then, the device node has children entities, like for example a few registermaps, one register bank accessed over i2c, another over SPI, etc. Inside a register, we might want to define a single bit for access...well, you get the point: Due to the nature of XML, we're editing a tree structure. For the convenience of style sheet support, and because there is a free evaluation version that works perfect, we use the XMLMind XML Editor, short XXE . Below (Figure 1, “Screenshot of XXE”), you can see an example of XXE in action. All entity nodes are presented as simple, collapseable color bars, the editing of attributes is straightforward. On the right upper pane, you can see what happens if we try to insert nodes: the XXE will only allow us to insert nodes that conform to your XML dialect (which is specified in an XSD file). So, we can normally not mutilate a device description, which masks out quite a few potential early failures. In the bottom status line to the left, you see a green "ok" sign. This is the validation status. If there's something dodgy, it will turn into a yellow warning sign or a red X sign, when we have errors. A descriptive error report is shown in the right lower pane, when we click on the status sign. Figure 1. Screenshot of XXE

By the way: The XXE web resource where you can also download the entire package is: http://www.xmlmind.com/xmleditor/

Baking Code So, we are turning XML into source code. This is kind of easy to understand: XML will somehow be translated into static C structures. So far so good. But how does the entire development flow look like? Figure 2. Authoring flow scheme

From the scheme in Figure 2, “Authoring flow scheme”, we can see three main software tools involved: GNU make: Take care of building what needs to be built xsltproc: Turns XML into C code (or other) using XSLT descriptions The GNU C Compiler (gcc): Compiles all the source into a target executable I guess we don't have to mention that those tools are all free. And yes, we're not constrained to Linux, these tools are found in the Windows world as well, for example in the Cygwin or Mingw environments. So again, the development process for you as a developer is typically: Edit the XML file and define device properties (registers, bit fields, etc.). Also insert documentation nodes in those entities Write some code to support your target framework. This normally consists of a hardware layer, defining how registers are accessed, and some handler code dealing with more complex properties. Run "make" to build it all, and end up with a target executable. As we hinted above, we don't have to necessarily turn the XML description into C. We also normally turn it into documentation templates or VHDL register maps, ready to be synthesized with our RTL implementations. That means, ideally, that we touch this single XML file only for the hardware definition.

Register access example In this example, we would like to define a GPIO for a LED output and map it into a named Property that we can access the abstract way. In Figure 3, “Register setup” you can see the GREEN bitfield node inside a LED_Slot1 register which might live in a CPLD on your custom hardware. Not that we normally access LEDs from the outside world, but well, it's just an example. Figure 3. Register setup

To define the bit location in the register, we edit the 'lsb' and 'msb' attributes and give the bit a name - it makes sense, to stick to a C notation standard, but you're free to use your house rules. Done! We have a register and bit definition. Now, we are going to map this bit into a named Property in Figure 4, “Property mapping”. Since we like it the object oriented way, we just started packing the various LEDs into a struct -- but the 'Green' Property would not necessarily have to be encapsulated in the parent struct. Anyhow, after we've named the properties as shown below, we have to somehow map it to the hardware entity. This is done by inserting a 'regref' node and specifying the name of the register we defined above. To refer to one specific bit, we have to fill in the 'bits' attribute as well. Now we can access the LED as an abstract property by the name 'LED.Green' in the device's namespace. Figure 4. Property mapping