• Keine Ergebnisse gefunden

Background

2.3 Portability Architectures

One of the major roles of an execution environment is to create a unified abstract computing environment for the application programmer that is independent from the details of the underlying hardware. For this, the parts of the software that directly interact with the hardware have to be isolated from the parts that have more general applicability and can be reused over different platforms.

This hardware transparency is traditionally achieved with two related concepts:

anHardware Abstraction Layer2that mostly deals with the architectural differences of the processing units; and aDevice Driver Modelthat concentrates on the abstraction and the interfacing of peripheral hardware devices.

Although widely used, the realization of these concepts varies significantly among the differentOSand can lead to different trade-offs between efficient resource use and portability. Before introducing our own framework in the form of the portability anchor of DASA(Chapter 4), in this section we briefly review several prominent portability architectures from the general-purpose computing and embedded systems domain, including some existingWSNsolutions.

2.3.1 General-purpose and Embedded Operating Systems

Because they have to operate on top of a large number of complex and diverse processing units, the general-purpose and embeddedOSs typically have mature hardware abstraction layers. To hide the architectural differences across the different processing units, theOSprovides processor-independent mechanisms for handling interrupts, exceptions, memory paging,I/O, Inter-Process Communication (IPC), etc.

The organization of the device drivers, in turn, is closely related with the abstrac-tion of the chip interconnect (Secabstrac-tion 2.1.1). For example, theNetBSDis claimed to be the most portable of the modern UNIX-like operating systems. It currently runs on top of more than fifty different hardware architectures. This extraordinary portability is due to the specific design of the device driver framework which is machine-independent and based on clean separation between the chip drivers and the bus interfacing code. The access to the bus memory and register areas is im-plemented in a fully machine-independent way, allowing the same device driver source to be used on different system architectures and bus types [196]. The new Linuxdevice driver model [145], reuses a subset of these architectural approaches and structures the hardware abstraction functionality in different elements likebuses, classes,devicesanddrivers.

2the typical acronym used isHAL, but in this work, this acronym is reserved for theHardware Adaptation Layer, part of the vertical decomposition architecture of the portability anchor (Section4.2.2).

Another important dimension in the organization of the hardware abstraction code is the level of adaptability, i.e. the degree to which the hardware abstractions code can be adapted to the specific needs of the application at hand. The embedded

OSeCOSis a typical example for a more adaptable organization of the hardware abstraction functionality. eCOS is component-based and uses compile-time recon-figuration to trim the execution environment to the specific requirements of each application.

The hardware abstraction functionality in eCos is organized in two main parts [138]:

an “abstraction layer” that provides architecture-independent support for handling interrupts, virtual vectors and exceptions; and a group of “device drivers” that ab-stract the capabilities of the hardware modules. The drivers are implemented as monolithiccomponents and are accessed by the rest of the system via the “I/O Sub-System” that defines a standard interface for communication with the exposed driver

“handlers”.

In contrast, the device drivers in theWindowsCEembedded operating system from Microsoft can be either monolithic or structured in two customized layers [150]. The upper layer is formed by the platform-independent “Model Device Driver (MDD)”

that uses the services of the “Platform-Dependent Driver (PDD)” that forms the lower layer. Unfortunately, the application is not allowed to directly access to the lower Platform-Dependent Driver interface and has to communicate with the hardware via single “Device Driver Interface (DDI)”.

In Section4.1we discuss why the monolithic organization of the driver com-ponents like in eCOS, nor the two-layer model of WindowsCS, fully addresses the specific requirements ofWSNs, and the need to balance between system efficiency and portability on these severely resource-constrained devices.

2.3.2 WSN Operating Systems

As discussed in Section2.1.1, most of theWSNplatforms use relatively simpleMCUs

that don’t offer hardware-protected execution levels and lack a memory-management unit. Consequently, an extended abstraction of the processing architecture, typical for the general-purposeOSsis not needed in theWSNdomain. Instead, aspects like the abstraction of platform hardware modules,I/Oconcurrency management and power management, become prime areas where the developer can benefit from the services of the underlying execution environment.

We useTinyOS [88],MantisOS [15] and Contiki [42], to illustrate the level of maturity of the hardware abstraction models inWSNexecution environments at the beginning of our work on theDASAportability anchor. Our discussion is based on TinyOS 1.15, MantisOS 0.95 and Contiki 0.9.3.

TinyOS

TinyOS is one of the first execution environments specifically designed to meet the requirements of resource-constrained, event-driven and networked embedded

systems. Similarly to eCOS, the component-based nature of TinyOS (Section3.2) allows compile-time customization of the hardware abstraction functionality to the specific needs of each particular application. The component-based model is also instrumental in buffering the changes introduced by the fluid software/hardware boundary by allowing software components to be replaced with real hardware modules (that export the same interfaces) and vice-versa.

The organization of the components that encapsulate the platform hardware modules, however, have been very inflexible and tightly coupled with the specific properties of the mica family of nodes (Section2.1.2). In Section4.5we discuss how the situation was qualitatively changed in the next generation of theOS, TinyOS 2.x, through the application of the decomposition principles of the DASA portability anchor. The description here pertains to the organization of the platform abstraction components in TinyOS 1.x before these changes.

Access to the services of the platform hardware modules can be provided using eithersharedorvirtualizedservices. A shared service gives clients full access to the module at the cost of some form of access control. Virtualisation gives each client its own (possibly simplified) “copy” of the module, at the cost of some runtime or latency overhead.

TinyOS 1.x provides one significant virtualized service: the timer. The service offers periodic and one-shot millisecond-resolution events, multiplexed from a single compare register. TinyOS 1.x also provides abstraction for several standard data buses likeSPI,UART,I2C, 1-Wire, etc. which are also responsible for arbitration of the shared access. The power control of the peripheral modules is being performed through a standardized interface with a start and stop command.

Most of the differences between the processor architectures in TinyOS 1.x are masked through the use of the nesC/C programming language [65] with a common compiler suite like GNU C Compiler (GCC). The standard C library distributed with the compiler creates the necessary architecture-dependent start-up code like initialization of the global variables, the stack pointer and the interrupt vector table.

TinyOS puts theCPUin a low-power state whenever the event/task queue is empty and no interrupts are pending. The selection of the most appropriate sleep mode is computed using chip-specific function that examines the internal registers in the

CPUto determine which peripherals are being used at the current time.

MantisOS

MantisOS took a different approach in addressing the specific challenges of theWSN

domain than TinyOS. Rather than using a new language and code organization model, it is C based and provides a micro-threaded UNIX-like environment with blocking operations.

The driver architecture in MantisOS closely follows the Portable Operating System Interface (POSIX) model—based on the "everything is a file" abstraction—and supports a small number of system calls with a large number of parameters. For example, the

complete interaction between the application code and the driver layer is constrained to only four system calls: dev_read()anddev_write()for reading and writing data, dev_ioctl()for passing device specific configuration information anddev_mode()for explicit device power state control.

While the idea of UNIX-like calls might seem appealing initially, the reliability drawbacks outweigh the benefits of comfort. The model pushes the error checking to runtime, as the interfaces do not express the constraints underlying resources. For example, a program can try to read from an sensor using aGPIOpin that does not exist.

Consequently, errors that are easily detectable at compile-time under the TinyOS wiring model, can result in run-time errors in MantisOS, and require complicated error detection and mitigation code.

For coordination of simultaneous access, a traditional mutual exclusion approach is used. Each driver maintains a simple “mutex” When the peripheral is locked for exclusive access, any other calling thread is queued in an associated waiting queue and blocked pending the release of the mutex lock by the current owner.

MantisOS drivers that wants to be power managed, must implement adev_mode() function that can be called to modify the power state of the underlying peripheral.

Three distinct device power states are supported: on, off and idle. TheCPUpower management in MantisOS is tightly coupled with the thread scheduling and supports two levels of power saving. When the scheduler ready queue is empty, the scheduler implicitlyputs theCPUinto anidlestate that consumes less power than the active state, but still supports full peripheral functionality. For greater power savings, the scheduler needsexplicit information from the threads in order to determine when it is safe for theCPUto go into asleepstate. The signaling is performed by a mos_thread_sleep()function that threads use to declare the intended duration of sleep.

When all threads in the system are sleeping, the scheduler is free to put theCPUinto a deeper power-saving state, with only a single timer left running to wake the threads up after the sleeping period is over.

Contiki

The hardware modules are typically accessed in Contiki by calling a particular set of C functions to directly communicate with hardware (e.g., the telosb flash chip, serial port support). In some cases, these functions also communicate with a protothread (Contiki’s lightweight, thread-like abstraction for event-based systems [43]) that implements part of the module functionality (e.g., the CC2420 transceiver). Events are signaled by peripherals either by calling a particular function from within an interrupt handler, or by signaling an event to a specific protothread.

There is no general-purpose support for implementing either shared or virtual-ized services. Some peripherals provide ad-hoc virtualisation (e.g., timer library).

Others deal with sharing through various mechanisms: providing only blocking func-tions (e.g., flash, serial port), synchronization via global variables (e.g., the CC2420 transceiver and access to theI2Cbus) and buffering (theTCP/IPnetworking).

Contiki does not provide any standard mechanisms for managing the power state of peripheral devices. Some peripherals implement on and off functions. Like TinyOS, it puts theCPUin a low-power state whenever the event/task queue is empty and no interrupts are pending.