OTlib, or “OpenTag Library” is where the bulk of the OpenTag code lives. It is device-independent and contains the local API (OTlib interface), internal API (OTAPI-C), and external API (OTAPI-ALP). Any platform with enough resources and a standards-compliant C compiler should be able to run the OpenTag library.
OTlib modules are stored inside
./OTlib, as referenced from the top-level project directory. OTlib itself contains several modules, shown in the table below.
|OSI Layer||Code Module||Description||Code Files|
|Application||ALP||Application Layer Protocols (including message APIs)||alp.h, alp_api_client.c, alp_api_server.c, alp_dashforth.c, alp_filedata.c, alp_logger.c, alp_main.c, alp_security.c, alp_sensor.c|
|OTAPI||C-based API||OTAPI.h, OTAPI_c.h, OTAPI_logger.c, OTAPI_tmpl.h|
|NDEF||Terminal protocol wrapper (uses NDEF)||ndef.h, ndef.c|
|External||External events wrapper||external.h, external.c|
|Presentation||Authentication||Cryptographic authentication, and key table||auth.h, auth.c|
|Veelite||Filesystem module (ties into Platform)||veelite.h, veelite_core.h, veelite.c|
|Session||Session||Session Stack, and session event management||session.h, session.c|
|Transport||M2QP||Mode 2 Query Protocol Transport Layer||M2QP.h, M2QP.c|
|Network||Network||Network Routing & Broadcast||M2_network.h, M2_network.c|
|Data Link||System||MAC layer and system event manager||system.h, system.c|
|CRC16||CRC16 calculation (may tie to Platform)||crc16.h, crc16_table.h, crc16.c|
|Queue||Data Type for FIFO streams||queue.h, queue.c|
|Buffers||Memory buffers used by System Queues||buffers.h, buffers.c|
|Physical||Encode||Frame/Packet encode/decode (may tie to Platform)||encode.h, encode_M2_table.h, encode_M2.c|
|Radio||Radio layer (ties to Platform)||radio.h|
|None||Configuration||OTlib configuration and interface||OT_config.h, OT_support.h, OT_types.h, OT_utils.h, OT_utils.c, OT_version.h|
|None||Platform I/O||Platform tie-in interface||OT_platform.h|
OpenTag is designed for embedded systems, first and foremost, so it is not as modular as some higher level system architects might like (and it is certainly not object oriented), but generally speaking it is quite modular. Modules can be replaced, and as long as the interface is the same, the code will function just fine. What follows is an summary of the modules in OpenTag, and what each one of them does.
OTAPI main article
The API module contains several parts, all of which ultimately link to the C API. All OpenTag builds contain the C API, which just links to internal functions in the OTlib. The C API may be used internally, by other firmware/software running alongside OpenTag on the same device. The other API components – ALP, DASHForth, and Logger – are wrappers to/from C API, which may be used by I/O other than a server-side C program.
Veelite is also shown in the API table, even though it is an independent module, because it can be interfaced via C or via its own, standardized ALP protocol. Therefore, it is available to Client side and Server side programs.
|C API||A static C Library of functions and data types||Compiled Server-side application|
|DASHForth||A Forth-based word library||Server-side and Client-side applets|
|ALP API||A messaging protocol for invoking C API functions||Client-side directives of Server|
|Logger||A messaging protocol for automated data output||Server-side automated output to Client|
|Veelite||The filesystem interface||Compiled Server-side or via ALP|
The External module is not much more than a wrapper for interfacing application layer events with internal, OTlib event handlers and event-based data elements. Application layer events, like sensor alarms or passive RF wake-up detections, can cause state-changes in the DASH7 session layer and Data Link Layers, and they can also cause file data to change. The External module defines how and what these events can do.
Authentication Module main article
The Authentication Module stores a key table, kind of like SSH, where each device/host ID maps to a user type (root/user/guest), a certain type of crypto and, of course, a key. The auth module is called whenever a file is opened (via the veelite filesystem) to validate that the user (device ID) who is trying to access the data is also qualified to access it.
The Authentication Module includes some assortment of cryptographic codecs. The codec I/O interface is algorithm-independent, so any cryptographic function module designed for the standard interface can be used. The basic/default method is AES128.
Security exchange methods like TLS, IKEv2, etc, would be implemented in the networking or transport layers of OpenTag, not the Authentication Module. The final phase of the security process – authentication and cryptography – is handled by the authentication module.
Veelite main article
One of the pride-points of OpenTag is Veelite, a very compact file system that includes flash wear leveling, mirroring to RAM, and a POSIX-like interface (it stands for Virtual EEPROM lite, which doesn't quite do justice, but it is catchy). Veelite contains functions that open, close, read, and write files. The opening process is gated by user authentication, which leverages the Authentication module.
The flash wear-leveling component of Veelite is part of the platform section. There are two variants, X1 and X2.
The X2 system works by a process of logical transformations (i.e. a data cipher), such that the data in the flash may not actually represent the file data unless you know the logical mapping template. Thus, the mapping table needs to be saved in ROM when the power goes down, such that it can be brought back up when power resumes. Otherwise the data in Veelite will be lost. Application layer tricks, like saving the mapping table when voltage gets low and then shutting down, are suitable for providing high-reliabilty for X2, and the savings in power of using the much faster X2 method more than make up for not being able to utilize the last drops of battery power. Alternatively, some platforms contain integrated EEPROM, and, on these sorts of devices, the mapping table can be saved directly to EEPROM. This strategy, when available, provides bulletproof reliability to the X2 method.
Session main article
The Session Layer defines the session data type and stores the session stack. The Session Data Type is kind of like glue that holds several other layers together. It stores parameters that need to be passed, layer-to-layer, and it holds each set of these individually in a stack element. The stack is ordered such that the newest sessions are on top (as stacks generally are), and if the stack gets too full, the oldest sessions are the ones that get the boot. So, OpenTag (and DASH7 Mode 2, Chapter 8) favor new sessions over old. This not only is more practical for DASH7 type networks, but it also is very compact and elegant to implement.
Each session takes up 8 bytes of SRAM. A typical device has a session stack between 2 and 6 levels deep – anything more than an 8-session stack would be special-purpose. A 1-session stack is adequate for many sorts of applications, a 2-session stack can do most (if not all) applications, and the default configuration calls for a 4-session stack. The limit is a 255-session stack. If going beyond an 8-session stack, you may want to use a more efficient sort method for the stack (the basic method is linear insertion sort).
This is the transport layer protocol that does most of the cool stuff, like data querying and datastream negotiation (it means Mode 2 Query Protocol). It includes functions for parsing incoming packets/frames, functions for constructing outgoing packets/frames, and internal functions for doing the command processing.
M2QP is mostly just a data I/O setup, but in a few cases it also changes System and Session states, and some event manipulation, particularly when doing Datastream dialogs.
The network layer holds M2AdvP (a background protocol), M2NP (the main network protocol), and M2DP (the datastream protocol). M2NP is the only one where any processing actually takes place, and in this case it is minimal. OpenTag/Mode 2 offers optional routing (i.e. multihop routing) and Network Layer security. These are the two main features of M2NP. In cases where neither is used, or neither is enabled, the network layer is mostly bypassed.
CRC16 is a fundamental component of DASH7 (the method used is the CCITT “0x29B1” standard, using polynomial 0x1021). The OpenTag implementation allows HW accelerators to be used if available, otherwise it uses a tabular implementation of the algorithm.
The CRC16 may be calculated on a block of data, and then appended to data manually. Alternatively, it can be “streamed,” or automatically computed as data is passed in, byte-by-byte, and then appended to the back of the data queue automatically. This latter method simulates a HW FIFO with CRC automation.
Queue is a data type for organized, yet arbitrary, string data. Queues are used for many types of data transfers within OpenTag, but the only static Queues are the DASH7 RX and TX data queues. Additionally, users may implement a Queue or two for a serial messaging API as well (OpenTag implements them for you if you enable them).
The Queue itself is pretty uninteresting. It manages length and cursors automatically as long as you use the Queue functions for reading and writing data. These functions automatically account for endian issues between platforms. By default the Queue is designed to enable big endian data transfer, which is the standard method for DASH7 (and also better… I hate little endian).
Encode module is part of the radio data chain (along with Queue and CRC16). It is quite self-contained, and as a user you will never need to worry about it. It implements in software (or hardware if available) the encoding methods used by DASH7. It also calls the CRC of the data automatically. The Radio module calls the Encode module functions, so it is mostly transparent to the user.
Configuration Main Article
OpenTag can be configured for many different types of device/host behavior. There are two kinds of configuration: compile-time configuration and runtime configuration.
The runtime configuration is managed via the Veelite filesystem, which maintains 16 files that each address, explicitly, a component of operational configuration. The runtime configuration files can be read, written (or modified) during runtime by the APIs or the filesystem ALP. These files must be supplied with default data, also, which is supplied at compile-time or linking-time (for simplicity, we will consider that linking-time is the same as compile-time).
The compile-time configuration is managed through several configuration headers (.h files) and may be extended to GNU automake (or similar) build models. Compile-time configuration also requires default data to be written to the 16 veelite configuration files (see above). These default data are generally stored in a .c file (often stored as /Platforms/[platform_name]/data_[config_name].c) that is filled with
const char arrays. The arrays are mapped to areas of memory defined in the .h configuration headers.