CMP EMBEDDED.COM

Login | Register     Welcome Guest  
HOME DESIGN PRODUCTS COLUMNS E-LEARNING CONFERENCES CODE FORUMS/BLOGS NEWSLETTERS CONTACT FEATURES RSS RSS




Introduction to CORBA for Embedded Systems

by Niall Murphy

CORBA is a protocol for communicating among heterogeneous systems. This article introduces the concepts of CORBA to embedded systems developers and indicates what its applicability is for the systems they’re developing.

Embedded systems communicate with each other and with desktop systems more now than ever before. A number of options exist for the system designer who faces the task of allowing a range of embedded systems to communicate. When a number of systems are going to communicate over a network, TCP/IP is the most popular protocol, and it also allows the option of communication over the Internet. However, TCP/IP sockets allow only a low level of communication where raw bytes are pushed from one place to another. Each node on the network must parse those bytes to decide what request is being made, or if this is a reply to an earlier request. If the system is large and the there is a rich mixture of message types, then a higher level of communication is necessary. Rather than simply getting a message to the right device, you want to get a message to a specific object on that device. CORBA can supply this.

The Common Object Request Broker Architecture (CORBA) standard, defined by the Object Management Group (OMG), is being embraced by the financial and telecommunications industry as a means of communicating in heterogeneous systems. 1 CORBA is becoming further established on the desktop by its integration into the latest version of C++ Builder from Inprise (formerly Borland), and the latest release of Lotus Notes. But does this protocol have anything to offer the embedded systems developer? Read on and decide if it meets your future networking needs.

This article introduces the concepts of CORBA to programmers who are already familiar with C++. While the CORBA standard embraces other languages, C++ is the one with which readers are most likely to be familiar—so I use C++ in the following examples. While this article is too short to bring readers to the point where they could write programs using CORBA, they should certainly understand the principles involved and where to go for further information.

Making systems talk to each other

For systems to communicate they need a common medium. One goal of CORBA is to allow systems using different hardware, operating systems, and programming languages to communicate. CORBA also allows the interactions between those systems to be defined in a platform-independent way, giving the system a set of well-defined interfaces.

The CORBA standard can be compared to a hardware bus. So long as all of the parts that wish to communicate conform to the bus specification, the internals of each part may be very different. Any one computer may make one or more objects available on the bus, as shown in Figure 1. Once the objects are visible, all of the other nodes on the network may access them in a consistent way. This architecture may appear at first glance to cause the bus to be a bottleneck; however, once communication is initiated, the actual packets travel directly from sender to receiver. While the CORBA bus specifies the protocol, it doesn’t require a central node to implement the bus—that responsibility is shared among the nodes communicating on the network. While some objects are made visible to the bus, each of the computers involved may also have many other objects that aren’t available directly over the network.

CORBA should also allow remote objects to be accessed as naturally as objects that are native to the local programming environment. In C++, the call:

objectPtr->doSomeThing(123, “some string”);

is an invocation on an object pointed to by objectPtr. The object could have been created in one of the normal C++ ways, or the object could exist on a remote system. In the remote case, the arguments and the name of the function have to be bundled into a TCP/IP packet and passed across the network. Any exceptions or return values have to be passed back before the function can return. While asynchronous mechanisms do exist, this synchronous call—that imitates a native call as closely as possible—is the usual way to make CORBA invocations.

For communication to be seamless, each program involved in the communication must have the software that hides the transfer of control from one device to another. This software is called the Object Request Broker (ORB).

The call is converted by the ORB into a TCP/IP packet, which is encoded in the Internet Inter-ORB Protocol (IIOP). This standard protocol is used by all CORBA-compliant ORBs, allowing programs built with different ORBs to communicate, assuming they’re all using TCP/IP. This feature is important if you can’t find one ORB vendor to support all of your platforms, or if you interact with software from many vendors which may have been built with a variety of ORBs.

So that we may explore the options that CORBA provides at the architecture level, let’s consider a hypothetical system in which several patient monitors in a hospital are networked. A number of computers must be capable of accessing the patient monitors; some computers may be accessing the patient data to archive it, while others may be displaying information to a human operator. Another client program may automatically page certain doctors if particular patients exhibit signs of trouble. The hardware and operating systems on each patient monitor may be different, and third parties might be asked to build systems that can inter-operate with the network put in place.

Software can now be written on several desktop architectures in a number of different programming languages to communicate with the patient monitors. The monitors could communicate with each other using the same protocol. The monitor need not be aware that a particular request came from another monitor, or from a desktop system. This feature could be useful if the some of the monitors are capable of allowing the user to view information about other monitors in other parts of the hospital.

Browser access to embedded devices

Since the TCP/IP protocol is used, the option to put this network on the Internet is available, though obviously some security precautions would have to be taken if actual control of the monitors was allowed from outside of the hospital. An Internet link would allow the option of a doctor checking up on a patient from home. Unlike a Web-enabled device, the CORBA server isn’t capable of serving Web pages containing device-specific information, though no reason exists why the device couldn’t be Web-enabled in addition to communicating with CORBA. An alternative browser architecture is shown in Figure 2.

In this architecture, we combine Java and CORBA, allowing a user to access the monitors from any Java-capable browser. However, rather than designing the monitor to serve its own Web page, accessible via its own URL, a single Web site provides the HTML-based user interface for the monitors. This site may be managed by the hospital or by the vendor of the patient monitors. Such a site could be far more sophisticated than one programmed into the embedded device. This site would serve a Java applet that is capable of communicating using CORBA. To do this, the ORB library is downloaded with the applet. A number of commercial ORBs have Java implementations and can be used in this way.

When the HTML page requires data from a monitor, it makes CORBA requests to gather that information. The applet also serves to locate the monitor on the network. The applet may access some central server to request the location of the monitor, based on such criteria as the patient’s name. This gives us an architecture in which the user interface to the device, as presented in a browser, can be updated without having to update the code on any of the patient monitors because only the HTML served by the central server needs to be updated to change the appearance of the interface. This convenience is especially useful if the patient monitors are different devices from different vendors. We also have the advantage that only the raw data will be transferred from the monitors, which are likely to have a slower network connection and less processing power.

I believe that this architecture is more beneficial than allowing the embedded device to serve a Web page of its own. Allowing the embedded device to deliver only the raw data, rather than full HTML pages, allows for a variety of user interfaces: one interface for administrative use, and a different one for doctors. User interfaces for different spoken languages could easily be supported without any extra load on the embedded device. And the browser could display information from many embedded devices on a single Web page.

The biggest apparent drawback to the architecture presented in Figure 2, as compared to Web-serving embedded devices, is the need for a central Web server to serve the applets. I believe that any large-scale system that deploys Web-serving embedded systems will need such a server. Locating the devices based on some humanly understandable key will have to be performed. If the Web-serving devices are reassigned occasionally, in location or use, then recording the URL of each device will not be sufficient, and a higher level of device management will be necessary.

Clients and servers

In CORBA, any invocation involves a caller and a callee. In CORBA terminology, they are referred to as the client and the server, respectively. Note, though, that the client and server roles may change in later calls. CORBA supports peer-to-peer communication and any node on the network may choose to be a client, server, or both. To be a client, the program makes invocations on objects elsewhere in the network. To be a server, a program must create objects and make them known to the rest of the network via the ORB.

Designing distributed objects with IDL

To create objects that can be placed on one device and accessed from another, you need to define the objects in a language- and platform-independent way. The Interface Def-inition Language (IDL) allows you to do this.

Listing 1 The IDL that may be implemented in the hospital system
// Structures may be defined in much the same 
way as C++ though they may not //
have member functions.
struct DayTime {
float hour;
float min;
};
interface Patient
{
string getName();
float getWeight();
string getWard();
};
interface Alert
{
short getPriority();
DayTime getStartTime();
Patient getPatient();
void resetAlert();
};
// Define an AlertList to be a sequence 
(or linked list) of structures of type
// Alert
typedef sequence
 AlertList;
interface Monitor
{
Alert getHighestPriority();
AlertList getAllAlerts();
//
parameters must have an in, out or inout direction 
// specifier - in this case parameter is passed in.
void clearAlert(in Alert alertToClear);
};
// The VentMonitor inherits from the Monitor interface.
interface VentMonitor : Monitor
{
float getBreathRate();
void setAlarmLevel(in float alarmRate);
};
// The BloodGasMonitor inherits from the Monitor interface.
interface BloodGasMonitor : Monitor
{
float getO2Level();
float getCO2Level();
};

Listing 1 provides an example of the IDL that may be implemented for the hospital system I’ve described.

These interfaces aren’t far removed from the kind of definitions you might find in a C++ header file. Note that the keyword interface in IDL corresponds to the keyword class in C++. A number of differences are present. One is that no private data is shown—all information in an IDL file is considered public. Another difference is that no constructors or destructors are shown for the interfaces. The objects are created or destroyed by the server, and the constructors and destructors can’t be accessed directly by the client programs. While the client cannot create or destroy objects on the server, they may be created or destroyed indirectly as a result of an invocation. For example the clearAlert() operation on Monitor may lead to the Alert object being destroyed.

The IDL is compiled to produce definitions for classes in C++, but it can also be compiled to produce Java classes or code in a number of other programming languages. The client and server use the code in slightly different ways. The client includes the generated C++ header file that contains the class definition, and can then call the member functions of that class. The class definition for Patient is shown in Listing 2.

Listing 2 The class definition for Patient
class Patient: public virtual CORBA::Object {
public:
// string in IDL maps to char * in C++
virtual char * getName (void) ;
// float in IDL maps to CORBA::Float in C++
virtual CORBA::Float getWeight (void) ;
virtual char * getWard (void) ;
};

The source in Listing 2 has been significantly simplified for this article, but the principle doesn’t change. Patient is derived from CORBA::Object, and hence inherits the ability to communicate with the rest of the network via the ORB. Accessing the Patient class will cause the function call to be transmitted to the appropriate object on the network.

The server also includes the C++ header file. However, the server has to implement the functions, not merely call them. ORB vendors provide a number of mechanisms to allow this implementation. One of the more elegant solutions is for the server to declare a class that inherits from the class generated from the IDL.

Listing 3 A class for Patient
// header file defines derived class
class PatientImpl: public virtual Patient {
public:
virtual char * getName (void) ;
virtual CORBA::Float getWeight (void) ;
virtual char * getWard (void) ;
};
//
.c file implements server side functionality
// - only one of the virtual functions shown here
CORBA::Float getWeight(void)
{
CORBA::Float w;
// w may already be stored, or
// may be calculated
w = /* read value from some structure */
return w;
}

Listing 3 shows such a class for Patient. Since the Patient class defines the interface, we need a different name for the class that actually provides the server side implementation. In this case, I’ve called it PatientImpl. Note that all of the virtual functions that were generated from the IDL are now being redefined. The code that implements these functions can be any C++ code that the designer wishes, as long as the signature of the function remains the same. Once the class has been implemented, the server may create some of the instances in the main() function at start-up, or objects may be created as a result of invocations on other objects on the same device.

Inheritance

In Listing 1, the VentMonitor and BloodGasMonitor both inherit from Monitor. The inheritance syntax is similar to C++, though there is no reference to the keyword public or private because in IDL all inheritance is assumed to be public. Inheritance in IDL has the same advantages as inheritance in C++, and CORBA fully supports it. When a client makes a call on a Monitor object, it may not be aware whether the actual implementation on the other device is a VentMonitor or a BloodGasMonitor. This minimizes the amount of code that must be rewritten when a new type of Monitor is added to the system.

Exceptions

Because the programmer has far less control over what happens during a remote call, exceptions are used extensively by CORBA. An exception may be raised because the TCP/IP link has been broken, or if a server doesn’t reply to a call within a specified timeout period.

The application programmer may also specify his or her own exceptions in IDL. Such user-defined exceptions are application-specific. For example, a NO_PATIENT exception may be thrown by a monitor if that monitor isn’t connected to a patient when a client requests some patient-specific information. The monitor can then raise an exception using the C++ throw syntax. The client may catch the exception using the try and catch clauses that are used to catch normal C++ exceptions.

The specification allows an alternative mechanism for compilers that don’t support exceptions, or for programmers who avoid them for efficiency or because their coding standard prohibits them. This feature may become relevant to any programmers who wish to use CORBA with an Embedded C++ compiler. 2

Referring to objects

Once you’ve written the code that implements the interfaces, objects may exist anywhere on the network. A client that has a pointer to one of these classes—say, an Alert*—may access it exactly as it would a normal C++ class. For example:

Alert * a = /* get pointer to an alert */

a->resetAlert();

If the Alert happens to reside on the same device as the caller does, then a well-implemented ORB will simply implement the call as a normal virtual function call in C++. If the object is on another device, the call will be passed to that device. The caller need not be aware of where the object is for any given call. This property is called transparency .

To implement this scheme the ORB must have a way of referring to objects on the network. This interoperable object reference (IOR) is a string that contains information including the IP address of the device, the IP port on which the device is listening for invocations on this object, and a key which distinguishes this object from others on the device.

Most times programmers aren’t concerned with the IOR string, though these strings can be used when establishing the initial communication between the client and server. The IOR may be hard-coded into the client software if the location of the server is known at compile time. Otherwise the IOR is obtained from a server known as the Naming Server, which tells clients the whereabouts of server objects. During this initial connection, the code is quite obviously concerned with the location of objects on the network, and we lose the elegance of treating the objects as if they were local. However, this is usually only a minor portion of the code. The client usually gains access to the first server object via a well-known string or the Naming Server. Further object references are obtained as return values from invocations on this first object. For these later accesses, the use of the IOR will be hidden from the application programmer, as shown in this example:

Monitor *mon;

Alert *alert;

Patient *patient;

char * name;

mon = /* get pointer to monitor */;

alert = mon->getHighestPriority(); patient = alert->getPatient(); name = patient->getName();

While the pointer to the Monitor was obtained via the Naming Server or some other start-up mechanism, the alert and then the patient are accessed as return values from operations defined in the IDL.

How are the data passed?

The common data representation (CDR) defines an exact representation for each of the types that can be used in IDL. This precise definition removes ambiguities regarding the size of a value. Byte-ordering issues are resolved by always sending data in the byte ordering of the client. If the server uses a different byte ordering, the receiver then has the option of remapping the values before processing the request. If the conversion occurred when the request was received, then the reverse mapping must take place when the reply is sent. This mechanism guarantees that no conversion is performed when both systems use the same byte ordering, and is, of course, transparent to the user of the ORB.

Smaller-system solutions

If resources are limited, a full CORBA implementation may not be feasible. There may not be enough code space to fit an ORB library, or there may not be enough code space and RAM to support the object-oriented program that results from implementing a CORBA server. In these cases, you may still wish to communicate with other systems that have greater resources and are using CORBA. One option is to communicate with these systems using a proprietary protocol from a CORBA-enabled device, which acts as a gateway between the CORBA world and the proprietary system. The proprietary protocol may be based on something as simple as a serial link, as shown in Figure 3. The CORBA standard encourages this approach and provides a number of mechanisms to support building such gateways.

Another option is to remove some of the functionality of the ORB. By the time you read this, the OMG will have adopted the Minimum CORBA standard, which specifies features that may be omitted in a reduced ORB.

A third option is to use a library that allows your program to communicate using the protocol, without the other overheads of a full ORB implementation. Such a library is known as an IIOP engine . Commercial versions for QNX and VxWorks are available from Iona. 3 Sun provides free, but unsupported, source code for an IIOP engine. 4 The TAO ORB also includes an IIOP engine. 5

The IIOP engine may be as small as 15K, while the full ORB library may be of the order of 150K. The IIOP engine communicates at a much lower level than conventional CORBA clients and servers—because an OO environment isn’t required, it can be implemented in C. For a client, the programmer has to explicitly construct the IOR, to allow a remote object to be referenced and has to explicitly map C++ structures to CDR types that can be passed to a CORBA server. If the device is a server, then the server object, which would be necessary in a full implementation, is no longer required. The server can receive the request and parse the IOR to find out about the identity of the object that the client expected to exist. The server may then construct an appropriate reply. While this may be unwieldy for a system that has to imitate many objects, it is manageable for the smaller number of objects that you would expect to find on a minimal embedded system.

Hard real-time issues

While current ORBs provide soft real-time facilities such as timeouts and asynchronous messages, no current commercial ORB claims to support hard real-time programming. The OMG hasn’t yet agreed on the features to be added to the CORBA standard to support real-time applications. They must first solve a number of difficult problems, one of which is negotiating a quality of service. A client may require a certain amount of bandwidth, or a worst-case response time. The quality of service properties could be specified in the IDL, making it a design-time decision, which would be appropriate for closed systems, in which all nodes on the network are known at design time. Alternatively, these properties might be specified when the connection between the client and server is being established at run time. This method would allow for a more flexible system, but one that would be more difficult to design. A failure mechanism would have to be provided by the application for the cases in which connections fail when insufficient resources are available.

Another major issue is whether task priority information should be passed from the client to the server, or if server objects should have static priorities assigned to them. Because CORBA doesn’t dictate a standard threading model, such issues are currently being handled in a proprietary manner by each ORB.

The telecommunications industry has driven a standard for streaming audio and video data over ATM, where the emphasis is on average response time over a brief period, to ensure that live video and audio quality is acceptable. 6 Much research is taking place into more general solutions for hard real-time systems. 7,8

Transport protocol

TCP/IP is by far the most popular transport protocol used in the CORBA world. On some embedded systems a serial connection is more appropriate and SLIP or PPP can be used to pass TCP/IP traffic over the serial link. 9 A number of vendors also provide ATM access. Visibroker has been implemented over a VME backplane, and Nortel has found UDP to be more efficient than TCP/IP in many cases. 10,11

Some applications demand that a proprietary transport be used—sometimes in order to meet the application’s real-time requirements, and sometimes to take advantage of the RTOS’s communications features. Most ORBs in the embedded arena offer, or soon will offer, hooks to such pluggable protocols .

Using a transport other than TCP/IP may mean the ability to talk to other nodes on the CORBA network has been lost. However, the CORBA specification includes a number of features that facilitate building gateways between different environments.

Programming language

While the CORBA standard defines a mapping to several languages, C++ is the one most likely to be used in embedded systems. Most developers turning to CORBA have already embraced OO programming and C++. If an embedded system contains a Java Virtual Machine, any Java ORB can run on it. Such ORBs are available from a number of vendors.

C is less suitable for use with CORBA, and developers would be ill advised to attempt to develop an entire system in C. However, in a network of mixed embedded systems, some targets may not have C++ compilers and yet may wish to communicate using CORBA. Both Nortel and Lockheed Martin have developed versions of their ORBs for C. 12

Other approaches

CORBA isn’t the only attempt at a solution to this problem. The Remote Procedure Call (RPC) protocol is a mechanism that allows one computer to invoke a function on another. But CORBA provides a greater level of abstraction than RPC, and in fact, some ORBs are built on top of the RPC mechanism. This greater level of abstraction is provided by CORBA’s ability to specify an object without necessarily specifying the server that contains that object. The location independence, in turn, allows references to objects to be passed freely around the network.

The Microsoft solution is the Distributed Common Object Model (DCOM), but since this depends heavily on Microsoft operating systems, it is unlikely to have an impact on the embedded world, apart from Windows CE targets. Gateways between DCOM and CORBA are available.

In another Embedded Systems Programming article 13 , author Laszlo Huray described Inter-Object Communication Manager, a proprietary system which has many of the properties of a CORBA ORB but has removed many of the advanced features in favor of simplicity.

Available embedded ORBs

On desktop platforms, probably the two most popular ORBs are Orbix from Iona Technologies and Visibroker from Inprise. Iona sells the Orbix ORB for QNX and VxWorks. Highlander Communications specializes in porting the Visibroker ORB to embedded systems. Visibroker for C++ for Tornado is available, and a pSOS version is in beta. Nortel recently started selling RCP-ORB on the VxWorks platform. This ORB had been used internally within Nortel for a number of years.

Lockheed Martin has developed an ORB called HARDpack for several military projects with real-time requirements. It will be available commercially on a number of Unix platforms and LynxOS by the time you read this. CORBAplus from Expersoft is currently being ported to VxWorks and LynxOS. 14

A number of free ORBs are also available, notably TAO, which has been ported to several RTOSes and has been used in research into hard real-time problems.

You’ll have to find an ORB that has been ported to your combination of OS, hardware, and compiler. As you can imagine, there are a lot of combinations, especially when you allow for different versions of each, so be sure that your vendor is specific about the platforms that are supported.

CORBA for the masses?

CORBA’s strength really shows on systems that are larger and more complex than the hospital example used here. It’s designed to scale to large systems. Currently, the greatest demand for embedded ORBs is in the telecommunications and defense sectors. As the problems faced by other embedded programmers get larger, then the need for CORBA will increase.

CORBA solutions are still expensive, often costing several thousand dollars per developer seat, plus run-time royalties. Although prices are falling, they’ll have to fall further before CORBA can be considered a mainstream solution. CORBA is still a heavyweight solution for many smaller embedded systems. But just as the overhead of C++ was overcome by a combination of careful use and cheaper computing power, CORBA will become a tool that is accessible to the embedded developer.

Niall Murphy has been writing software for embedded systems for seven years. He is the author of Front Panel: Designing Software for Embedded User Interfaces . (R&D Books, Lawrence, KS, 1998). He occasionally teaches a CORBA course. Murphy’s writing and consulting business is based in Galway, Ireland. He welcomes feedback at nmurphy@iol.ie, or visit his Web site at www.iol.ie/~nmurphy.

References

1. The Object Management Group’s home page is www.omg.org.

2. The Embedded C++ Technical Committee: www.caravan.net/ec2plus/

3. Iona Technologies: www.iona.com/

4. SunSoft’s IIOP Engine: ftp://ftp.omg.org/pub/contrib/interop/

5. TAO, The ACE ORB. www.cs.wustl.edu/~schmidt/TAO.html

6. The Control and Management of Audio/Video Streams specification is available in the CORBAtelecoms Index at www.omg.org/corba/ctelindx.htm.

7. See Douglas Schmidt’s CORBA page: www.cs.wustl.edu/~schmidt/corba.html

8. The OMG’s Real-Time Platform Special Interest Group’s home page: www.omg.org/realtime/

9. Rowe, Don, “Implementing TCP and PPP,” Embedded Systems Programming, August 1998, p. 48.

10. See Highlander Communications: www.highlander.com

11. Nortel: www.nortel.com/RCP-ORB/

12. Lockheed Martin Federal Systems: www.owego.com/hardpack

13. Huray, Laszlo, “Interoperable Objects for Distributed Real-Time Systems,” Embedded Systems Programming , March 1997, p. 38.

14. Expersoft: www.expersoft.com

Embedded.com Career Center
Looking for a new job?
SEARCH JOBS

Browse all jobs

SPONSOR
RECENT JOB POSTINGS





 :