Object-Oriented Device Networking

Michael presents an object-oriented approach that is an alternative to the traditional ways of designing networked devices.


August 01, 2001
URL:http://www.drdobbs.com/cpp/object-oriented-device-networking/184404729

Aug01: Object-Oriented Device Networking

Michael is chief technology officer for emWare. He can be contacted at mhoward@ emware.com.


Device networking is the focus of many current development efforts, with initial efforts focusing on remotely manipulating and monitoring newly connected devices. This is appropriate when the intent is to put users directly in control of the device. However, the problem is that billions of these new devices are built every year and many of them need to be part of larger intelligent systems. Clearly, architectures for device networking must provide a framework for creating complex systems from simple, standardized building blocks — and object-oriented design is the key to making this happen. In this article, I'll present an object-oriented approach that is an alternative to the traditional ways of designing networked devices.

The Opportunity

When I started working in the device-networking field four years ago, the task at hand seemed straightforward. We wanted to leverage the massive amount of Internet-related software R&D by making systems that connected web browsers to embedded devices. These devices were often built around simple microcontrollers in extremely cost-sensitive applications. Even though the microcontrollers were low cost, the value in being able to monitor and manipulate the devices was often surprisingly high.

We identified several areas where networking added value to previously isolated embedded systems. These areas included:

Initial Efforts

To address this market, we created a device-resident server that makes a set of functions, variables, and events available for remote manipulation via web-based clients. In effect, each device is encapsulated as a single device object in a web-based proxy server. The device object can be manipulated from remote interfaces using C, Java, or ActiveX APIs. The device object had a complete description of each function, variable, or event, but there was no attempt to create device types.

Initial customer interest came from service applications in which technicians walked up to a piece of equipment and used our software and a Java service applet to diagnose a complex system. Web technology made this type of application really cool because when the local technician had problems with a device, our software made the same diagnostic information available to an expert service technician located at the corporate office. The expert was available online to help the local technician with particularly difficult maintenance and service procedures.

Problems Start Coming Up

Since using web technology to connect people to networked devices seemed reasonable, I patted myself on my back and believed — for a while, anyway — that I understood the problem space.

As we moved forward to extend the Internet to microcontroller-based devices, however, I realized how massively outnumbered we are by the machines around us and couldn't imagine interacting with so many devices through individual UIs. The last thing I want is to have to pay attention to more details, so a web interface for each microcontroller-based device in my house seemed less and less like a good idea.

Other problems that arose with this paradigm included:

Although our initial development efforts solved the connectivity problem, the lack of typing and any sort of behavior contract created serious problems. These problems made it difficult to build larger systems.

Currently, I'm focusing on automation. Consequently, what I'd like to have is a device network infrastructure that is automated in terms of configuration, maintenance, and operation. The result should be that any information on a device is accessible by network resident applications through standard database APIs. The database APIs are also used to affect the state of many devices, not just a single one or a single type. The networked devices are also logically connected to each other. When one device has information relevant to the operation of another, this information is transferred according to predefined rules for interaction.

The problem space for this approach is divided into problems of representation and coordination. I want to maintain a network-based representation of a device. This representation is simply a replicated copy. It reflects the state of the device. When I manipulate the copy, the device state changes as well. When I talk about "device coordination," I'm referring to the creation of distributed systems. I call it "coordination" because the systems can be loosely coupled and one device is controlling the state of another device. For example, because a telephone possesses intelligence, it can send messages instructing stereos or TVs to turn down their volumes when the phone is ringing, thereby eliminating missed calls.

The Traditional Approach

Manufacturers have developed thousands of devices with connectivity in mind, and most have incorporated RS232 ports with custom protocols. Although these proprietary protocols may implement commands for diagnostics, data logging, and device control intended for use by other devices, their level of interoperability with disparate networks is limited. Of course, the benefit of this approach is that it is simple and relatively inexpensive. However, the problem with devices that utilize this limited form of connectivity is that they don't incorporate the concept of Design by Contract (for more information on DbC, see http://www.elj.com/eiffel/bm/ot-dbc/). Thus, these devices and systems are not scalable, and cannot integrate higher level systems. Someone has to look at each and every device type and create a translation module. This is not a simple process because of the lack of protocol standardization and abstraction.

The Object-Oriented Approach

With this in mind, we are pushing to create uniform interfaces to object representations of devices and use standard class definitions to describe similar devices. By doing this, the task of creating useful software applications that incorporate device information can be decoupled from the task of getting that information from the device. Additionally, the device descriptions represent a behavioral contract, which is a prerequisite to any real progress in the automation of device network configuration and management.

Our current effort starts with a system that lets you encapsulate a device into one or more objects. Each of these objects is essentially an instantiation of a predefined device-related class. Typical implementations include class implementations for management, general device application, and a subclass for proprietary extensions. The management class implements features used for firmware upgrades, capabilities discovery, device identification, and performance-related tuning. The class that implements general device application is essentially the feature set of the virtual base class for the specific type of device. For example, a networked furnace would have a basic set of properties used for maintenance, diagnostics, and control. This class definition would be one defined by and agreed upon by a standards group such as the American Home Appliance Manufacturers (http://www.aham.org/), whose charter is to promote and define standards that allow interoperability of networked appliances.

Interfaces

At first glance, the encapsulation of an embedded device application into an object appears trivial. The need for industry-wide device specification is apparent when you look at the support that Universal Plug-and-Play (http://www.upnp.org/) is getting. Given a way to let the device describe which classes and interfaces are implemented, and a protocol to allow manipulation of the device objects, the desired automation should be within reach.

But problems start creeping from several different factors:

Inheritance

Inheritance in the device-networking realm is an interesting feature. The implementation of inheritance that I need is a distributed inheritance. The base class of a device object is implemented on a larger device gateway program; the subclass is implemented on the product. The gateway device then further subclasses the device. This implementation lets you control the final presentation of an object from a device gateway.

The distributed class hierarchy that implements this type of inheritance allows you to create a device application that is based on services that are available through a supporting system such as a device gateway. Take, for example, a home-heating and air-conditioning (HVAC) system. At its simplest, this is a system composed of a heating unit, chiller, and thermostat. If the devices were connected via different transports to a home gateway, then the gateway would provide services to the application running in the thermostat for network connectivity. The method invocations of the HVAC control to raise the temperature would result in invocations in the gateway-resident base class, which are then forwarded to the other subnetwork. This may be superior to having the thermostat application smart enough to deal with networking issues and encoding the data communications into the application.

Connecting Objects

Given a device network of objects, the next step is to create bindings between the objects. The approach I first thought to take was to create bindings between the properties, methods, and events of various objects. As Figure 1 shows, there are a number of ways you can approach this.

In Figure 1(a), the user of the Hot Tub object knows that it is manipulating the Hot Tub, so the interaction is assumed appropriate. The developer of the Hot Tub enforces correct iteration with the equipment through the class definition, but trusts that users of this object will manipulate it appropriately. In Figure 1(b), the connection is between the implementor of an Occupant Status class, which describes the status of home occupants. The object state reflects that the occupant will not be around for the day. The desired actions resulting from this status are not the responsibility of the home controller. Finally, in Figure 1(c), the Hot Tub object is created to use an Occupant Status object if it is connected. If so, the behavior is made to place the equipment in the appropriate mode, given the status information supplied.

In all these scenarios, the binding phase presents a problem. The desire is to have a completely automatic plug-and-play type of system. The reality is that the binding of devices is often difficult or impossible to resolve automatically. Take, for example, a case where a consumer has two furnaces and two thermostats. How do these nodes know which to bind? The process of binding devices into control systems must be accomplished by:

One or more of these stages can be automated or skipped, but I have never seen a system where all these steps can always be skipped. One of the hurdles comes when the device subnetwork transport overlaps with subnetworks owned by other consumers. It would be a real problem to bind a smoke detector with RF output from one house into another.

With an object-oriented approach, device networks can be built that are automatically configured and efficiently managed, but there is no magical property that can make what would essentially be a random guess into a wise choice.

An Example

The device network interface software that Listing One is written for lets each variable access to be implemented with an accessor function that controls the movement of data to and from the communications channel. This is why there is no apparent data movement from the outside world into this system. This example assumes that the classes implementing Furnace are built from C. This is typical of control applications.

If you look at the state transitions, the over-temperature fault, which happens when the filter gets too dirty, does not stop the furnace from proceeding to cool-down phase and eventual startup. This is indicative of how these types of devices must continue to operate as good as possible even in the face of serious problems. That is why getting this valuable fault information is so important to the consumer. A remote service tech can easily determine the problem and even be alerted by the thermostat, which will know that its control is slipping.

Any device that wishes to control the furnace must supply the HeatControl output. This is stronger typing than simply linking to any module that can control temperature. The devices or applications interested in fault and status may be a separate maintenance module, not just the thermostat. The meaning of the input/output functions are not ambiguous and leave little room for misunderstanding in terms of behavior resulting from communications.

Extending the Contract

Recall that I suggested devices might be implemented using inputs that are of certain class objects instead of using inputs from properties that are manipulated. This is an important choice because, on one hand, you get devices that cannot possibly be connected to inappropriate input. On the other hand, you risk losing flexibility and the ability to bind inputs to reasonable but unanticipated sources.

Bidirectional contracts are good when the behaviors for given inputs are easy enough to design, but the inputs should be more strongly typed. If you view the inputs as classes, then this is done for you already because the contract is extended to include the appropriateness of the inputs to the device.

Device networking and object-oriented design is a natural fit because object-oriented design is premised on modeling real world systems and relationships. When embedded applications can be treated as instances of standard device classes, the devices can be integrated into larger, more automatic systems. To accomplish this automation, the device application developers must not only create an instance of a device class, they must be able to structure the relationships of their application and other devices. Having this type of object-oriented approach to device networking lets you vastly simplify the end-user's environment by making devices work together without needing an end-user to be tied to the system.

Conclusion

As embedded microcontrollers find their way into more and more applications around us, we are becoming surrounded by systems that implement behaviors appropriate for their limited inputs. Many of these systems will have valuable information available to them that is never made available to the outside world. This is sometimes due to cost, location, or for the sake of simplicity for users. By adding networking capabilities, you can tie these isolated systems together into larger coordinated systems. The components of the larger systems may be created by different vendors, but should easily, if not automatically, connect and work together.

This requirement is familiar to software developers who have dealt with software interoperability issues for many years. The tool developed for this problem of interoperability is object-oriented design. In device networking, an object-oriented approach of encapsulating device capabilities into classes facilitates network configuration and provides strong typing required for ensuring the appropriateness of an interaction. However, the relationship created by merely encapsulating capabilities, then using them elsewhere, does not sufficiently guarantee to the manufacturer of a device that the device will be used appropriately. I have suggested that making input objects for the controlled systems will provide this guarantee and pave the way for automatic configuration.

Applying object-oriented design to embedded devices promises many of the same benefits it delivers to larger software systems. To get these benefits, the mechanics of creating objects out of embedded applications must be addressed.

DDJ

Listing One

/* Heat Control Input.  This input represents the heat on/off 
** control from a thermostat.  
** EmergencyOff 
** The emergency off input requires that any activity should 
** be terminated as soon as possible, but in a way that will
** not damage equipment.  In this system, the cool down cycle
** is shortened when this is present.
** Heat
** The heat input from the thermostat.  The furnace must start
** heating as soon as possible and remain on until this is de-asserted.
*/  
typedef struct {
      BOOL EmergencyOff;
      BOOL Heat;
      BOOL Economy;
      } HeatControlIn;
/* Furnace Status Output.
** This is an output specific to Furnace device types. The
** fault flag is used to indicate if there is a current fault to report.  
** FanOn        - indicates whether the fan is currently running.
** Heating      - Indicates if the furnace is currently active.  This
**                is true during the phases of warm-up, heat, cool-down.
** InternalTemp - The internal temperature.  This value is used to 
**                control the phase transitions as well as the
**                fault shut-down.
*/
typedef struct {
      BOOL Fault;
      BOOL FanOn;
      BOOL Heating;
      TEMP InternalTemp;
      } FurnaceStatus;
/* Fault Output.  This is a generic equipment fault output.
** The Reason field is an ascii text description of the fault.
** The code is a device type specific fault value.  The
** tuple of (TypeId,code) will determine the fault meaning 
** for other devices.
*/
typedef struct {
      char *Reason;
      BYTE Code;
      DEVID Id;
      DevType TypeId;
      } FaultDesc;     

/* Sample State machine to go with these I/O on a furnace. */
/* check internal temperature, maintain status */
status.InternalTemp = InternalTemp = ReadTemp();

/* handle state transitions */
switch (FSTATE)
    {
      case idle:
        if (! EmergencyOff)
            {
               if (Heat)
             StartHeat();
            }
            break;
      case starting:
        if (InternalTemp >= START_TEMP)
           {
           SetFan(ON);
           FSTATE = heating;
           }
        break;
      case cooling:
        if ((EmergencyOff && (InternalTemp <= FAST_STOP_TEMP))
           || (InternalTemp <= STOP_TEMP))
           {
           SetFan(OFF);
           FSTATE = idle;
           }
        break;
      case heating:
        if (! Heat)
          {
          StopHeat();
          FSTATE = cooling;
          }
        if (InternalTemp >= MAX_TEMP)
          {
          StopHeat();
          FSTATE = cooling;
          status.Fault = TRUE;
          fault.Reason = "Internal temp exceeded, check filter";
          fault.Code = FAULT_FURNACE_TEMP;
          fault.Id = MyId;
          fault.TypeId = Mytype;
          } 
        break;
     }

Back to Article

Aug01: Object-Oriented Device Networking

Figure 1: Connecting objects.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.