Guidelines for using C++ as an alternative to C in embedded designs: Part 2

April 12, 2008

An Initial C++ Solution
There is no single solution to a problem such as this, so a series of approaches will be investigated. Here is a first attempt at a write-only port (wop) class:

class wop
{
        int shadow;              // not accessible
        int* address;           // to user
public:
        wop(long);               // constructor
        ~wop();                    // destructor
        void or(int);             // "operator"
        void and(int);          // functions
};

This hides the address of the port itself (address) and the shadow copy of the data (shadow) in the private part of the class, which can only be accessed by member functions.

A constructor initializes the member shadow value and the port itself with an arbitrary initial value (of zero):

wop::wop(long port)
{
        address = (int*) port;
        shadow = 0;             // initial value
        *address = 0;
}

The destructor would probably simply write zero to the port to return it to its initial state.

Two further member functions provide the user with a means of performing OR and AND operations on the port, which facilitates setting and clearing of individual bits:

void wop::or(int val)
{
        shadow |= val;                  // set bit(s) in copy
        *address = shadow;         // update port
}

void wop::and(int val)
{
        shadow &= val;                 // clear bit(s) in copy
        *address = shadow;           // update port
}

In both cases, the shadow data is maintained automatically. The applications programmer can create wop objects and use them thus:

main()
{
        wop out(0x10000);

        out.or(0x30);                     // set bits 4 and 5
out.and(~7);                              // clear bits 0, 1 and 2
};

Overloaded Operators
This C++ solution may be improved in a variety of ways. To start with, the use of the two member functions to perform OR and AND operations is not "natural". It would be much better if intuitive operators where available. This can be accommodated by overloading the |= and &= operators thus:

class wop
{
        int shadow;
        int* address;
public:
        wop(long);                         // constructor
        ~wop();                              // destructor
        void operator|=(int);         // overloaded
        void operator&=(int);        // operators
};

The way these operators perform should be exactly as any C/C++ programmer would expect. They may be implemented like this:

void wop::operator|=(int val)
{
            shadow |= val;              // set bit(s) in copy
            *address = shadow;     // update port
}

void wop::operator&=(int val)
{
            shadow &= val;             // clear bit(s) in copy
            *address = shadow;      // update port
}

Interestingly, this code is identical to the previous member functions, with just a change of function names. The new operators may be used thus:

main()
{
        wop             out(0x10000);

        out |= 0x30;                           // set bits 4 and 5
        out &= ~7;                             // clear bits 0, 1 and 2
}

<>Initialization
With the wop class above, there is a rational strategy for initialization " zero is written to the port (and saved in the shadow). However, it may be useful to allow the user to specify a custom value for each object. This requires a small change to the class definition and the constructor function, thus:

class wop
{
            int           shadow;
            int*         address;
            int           initval;                      // stored initial value
public:
            wop(long, int);                          // constructor
            ~wop();                                     // destructor
            void operator|=(int);                // overloaded
            void operator&=(int);             // operators
};

wop::wop(long port, int init=0)
{
            address = (int*) port;
            initval = init;
            shadow = initval; // initial value
            *address = initval;
}

The constructor takes an additional parameter, which specifies the initialization value, which may be applied like this:

main()
{
        wop     out(0x10000, 0x0f);

        out |= 0x30;                                 // set bits 4 and 5
        out &= ~7;                                  // clear bits 0, 1 and 2
}

Note that this second parameter has a default value of zero, which would be used if the constructor were called with a single parameter. This provides useful backwards compatibility with the previous version of the wop class.

The initial value is also retained in a private member variable (initval) which might be utilized by a destructor:

wop::~wop()
{
        *address = initval;                     // shutdown value
}

< Previous
Page 2 of 4
Next >

Loading comments...

Most Commented

Parts Search Datasheets.com

KNOWLEDGE CENTER