First, disclosure; I am not a C++ programmer - I think in C, and translate.
I don't naturally think in terms of classes, and "is-a" or "has-a" hierarchies or inheritancies.
Statement of problem:
I have a class which is a serial sniffer, for a connection between a sensor and a microcontroller
(it's an IKEA PM25 sensor, with the usual IKEA alpabetti spaghetti name), with a few smarts (well, a simple state machine)
to interpret the data packets presented by the sensor.
The class needs serial receive-only, and because the comms are slow, a software serial object can be used, though the class should
be able to handle hardware serial as well.
The class needs only the following functions from the serial object:
begin () - to set the line speed to the sensor's line speed (9600 bps)
available ()
read ()
Now, the tricky (for me) bit: How best to maintain encapsulation?
The calling sketch needs to provide an instance of a serial object, but SoftwareSerial and HardwareSerial are different types, and the only common class they inherit from is Stream, but Stream does not have the ability to set line speed.
So, I could simply pass the serial object (hardware or software) as an instance of Stream to the constructor, but that would mean that the calling sketch would have to set the line speed, which (in my mind) breaks encapsulation.
The outline scheme I came up with is:
class IKEA_PM25 {
public:
IKEA_PM25 ();
void handleSensor (); // called every iteration of loop (),
// calls serialAvailable and (conditionally) serialRead functions,
// basic, simple serial handling.
...
private:
virtual int serialAvailable () = 0;
virtual int serialRead () = 0;
...
};
class softIKEA_PM25 : public IKEA_PM25 {
public:
softIKEA_PM25 (SoftwareSerial& serial_) : serial (serial_) { };
void begin () {serial.begin (9600);};
private:
SoftwareSerial& serial;
int serialAvailable () {return serial.available ();};
int serialRead () {return serial.read ();};
};
class hardIKEA_PM25 : public IKEA_PM25 {
public:
hardIKEA_PM25 (HardwareSerial& serial_) : serial (serial_) { };
void begin () {serial.begin (9600);};
private:
HardwareSerial& serial;
int serialAvailable () {return serial.available ();};
int serialRead () {return serial.read ();};
};
So, the two derived classes are the only ones capable of being instantiated . . . but they look so similar,
I feel there must be a better way - a template? (I find template syntax hard to follow and, frankly, ugly)
Make the base class inherit from both HardwareSerial and SoftwareSerial? (just doesn't smell right)
Any thoughts?