I'm writing a real-time operating system for microcontrollers in C++11 - distortos. Currently I'm thinking about a C++ framework for various peripherals. The most basic peripheral which I would like to have there are input/output pins. Because such input/output pins can both be built into the chip or be external (I2C expanders, shift registers, ...) I plan to implement interfaces for them with pure abstract classes.
These are some of mine requirements:
- some pins can only be inputs and it shouldn't be possible to (easily) change their direction - for example if you change the direction of pin connected to push-button to "output" you can irreversibly damage the chip, the board or the device that is connected to the other side of the wire;
- some pins can only be outputs and it shouldn't be possible to (easily) change their direction - if you are using a HC595 shift register then this can only be "output" and nothing more;
- some pins can change their direction freely - this is required if you want to implement software I2C or software 1-wire;
Initially I have thought about doing it like this:
- The most basic interface class would be
InputPin- it would only support "reading" the state of the pin.
- Second interface class would be
OutputPin- it would inherit from InputPin (as you can read the value of pin configured as output) and also add the ability to "write" the value.
- Third interface class -
InputOutputPinwould inherit from
OutputPinand also provide a function to change direction.
Such approach has a very nice feature that I can use use any derived class in function that requires one of the bases. But actually there is one substitution that is not always correct - using
InputOutputPin in a function that requires
OutputPin can be a problem when the instance of
InputOutputPin is currently configured to be an input...
I've tried googling around for some inspiration and it seems that there is not much to use. ARM's mbed framework has 3 completely unrelated classes (there is no inheritance there) - one for "in", one for "out" and one for "in/out". Most of the code that I found has only one class that is for "in/out". I've actually found an article about exactly the same issue that I'm facing - http://www.embeddedrelated.com/showarticle/108.php . The solution presented there doesn't suit my needs - in a multi-threaded environment the operation of changing the direction of the pin is not so simple and usually requires exclusive access to configuration registers (the change is a read-modify-write operation).
I wouldn't like to implement any solution where the functions could fail (for example return error codes when the operation is not possible) - this would really complicate the usage.
Implementing a type-conversion operator - so that conversion from
OutputPin would be done in a function which also makes sure the direction is correct - is error prone, because the reference to
OutputPin can be stored for later use and at that time the direction may have changed again.
Maybe I should just simplify the hierarchy -
InputOutputPin would both inherit from
InputPin (this would always be correct), so
OutputPin wouldn't be a base for
InputOutputPin. This looses some of the flexibility, but I'm not sure that such substitution would be required anyway.