Guidelines for using C++ as an alternative to C in embedded designs: Part 2
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
}
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
}


Loading comments... Write a comment