Interfacing with modern sensors: Interface design using C++ - Embedded.com

Interfacing with modern sensors: Interface design using C++

Over the last several articles, we have been exploring how developers can interface to sensors and develop reusable drivers. In “Interfacing with modern sensors: Interface design”, we looked at how we could design sensor interfaces using C. In this article, we are going to look at creating sensor interface from a more object-oriented standpoint using C++.

Interface Design using UML

The Unified Modeling Language (UML) provides a standardized way to express software concepts that are independent of programming language. Before ever sitting to start banging out code, a developer who wants to design an interface to a sensor should create a simple class diagram that demonstrates what their sensor interface class will look like. For example, a class diagram for a sensor might look something like the following:


(Source: Jacob Beningo)

There are several interesting points to note in this diagram. First, an interface is a collection of operations that an inheriting class must implement. The reader will notice that our top level is an interface that is describing what operations each inheriting class must implement. In this example, this includes operations for:

  • Initializing the sensor
  • Writing to the sensor
  • Reading from the sensor

Any sensor will have these operations at a minimum, but they may provide additional methods such as the Power class also providing a calibrate operation. In object-oriented terms, the sensor class is an abstract class. Second, we use an open arrow to show that the implementing class inherits from the interface. Temperature, Humidity and Power are all class that implement Sensor. Finally, the Power class also as an additional method (operation), calibrate, which is not part of the Sensor interface.

Implementing an Interface in C++

C++ does not specifically have interfaces like other object-oriented programming languages such as Java. C++ provides the interface capability simply using abstract classes. An abstract class is a base class that other classes inherit from that has at least one pure virtual function. A pure virtual function is a function that has been declared, but the implementation is not provided. Instead, the inheriting class must provide the implementation. Thinking back to our UML diagram, this makes sense. The Sensor class is creating a contract that all sensors will provide Init, Write and Read operations but the Sensor class itself does not know how to implement those operations. It is leaving the implementation up to the class implementation to do that.

Creating the interface in C++ is relatively straight forward. A developer creates the class just like any other class except that they do not include a constructor, that is up to the implementing class, but should still create a deconstructor. Each operation is then declared as a pure virtual function. An example for the Sensor interface base class can be seen below:

class SensorInterface
{
    public:
        virtual void Init() = 0;
        virtual void Write() = 0;
        virtual void Read() = 0;
};

The class is created just like any other class except that the functions, which are often called methods, are declared virtual and assigned an empty value. We also include a destructor to ensure that we can clean up as well.

Implementing a new sensor class

In our example diagram, we had three different inheriting classes, Temperature, Humidity and Power. We certainly could have more or less, and we may even have classes that relate to or inherit from those classes. For today though, we are interested in seeing how we can have our sensor class inherit from the interface (abstract class).

When we define the sensor class that will inherit from the SensorInterface class, we would define the classes like the following:

class Temperature: public SensorInterface
{
    public:
        void Init();
        void Write();
        void Read();
};

class Humidity: public SensorInterface
{
    public:
        void Init();
        void Write();
        void Read();
};

class Power: public SensorInterface
{
    public:
        void Init();
        void Write();
        void Read();
        void Calibrate();
};

As you can see, we use the: after the new class definition followed by the base class. The new class must define the pure virtual functions in order to instantiate the class. Today I’m not going to go through in detail how this looks, but to give you a general idea, the notation I’m using is for outside definitions so each class would have an implementation of the form:

class:: function
{

}

Conclusions

A base class can be used to design an interface from which other classes can inherit. The benefit to creating an interface in this way is that it creates a contract between the application and object as to how it will be used. This helps to abstract out the details about what is happening under the hood which then adds flexibility and scalability to the design. This is definitely advantageous when we start to look at interacting with low-level hardware objects.

Jacob Beningo is an embedded software consultant, technical advisor and educator who currently works with clients in more than a dozen countries to dramatically transform their software, systems and processes. Feel free to contact him at jacob@beningo.com, at his website www.beningo.com, and sign-up for his monthly Embedded Bytes Newsletter here.

 

1 thought on “Interfacing with modern sensors: Interface design using C++

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.