Hi all, I'm an embedded c developer who is starting to explore embedded c++. I'm currently working on a project where a remote device will be responsible for monitoring a number of sensors attached to and I'm looking for a bit of help with wrapping my head around the best architecture to use for this implementation.
Some details:
- Platform is STM32 running an RTOS and the language is C++
- The device can have any number of sensors attached to it via different interfaces ( analog, spi, i2c, etc).
- Sensors will fall into a few categories (temperature, pressure, humidity) for now but this list may be expanded on.
- The available sensors will configured during run time
Goals:
- Design a sensor API that allows the application to add, init, and use whichever sensors it has been configured with.
- Easily be able to expand on the supported sensor type, interface type, and sensor device itself.
I've done a few OO designs but they have been a little more basic than this. I've looked into the factory pattern briefly which looks promising. Another option I've considered is just creating a hierarchy of class ( something like Sensor > TempSensor > TempDevice1 ) and just instantiating the devices that are marked as available during runtime.
I know this questions is kind of vague but I was hoping someone could point me in the right direction so I can do my research in the correct areas from the start.
You will probably use a factory pattern to instantiate the sensor objects at runtime.
You should also look for whatever common functions the sensors have and one or more abstract base classes to represent them. It might be as simple as:
1 2 3
class Sensor {
virtualdouble getReading() = 0;
};
Then you have derived classes for the various sensor types. Each one implements getReading() for that particular sensor.
I'd start by trying to define the classes involved before writing the code. Don't be surprised if you find yourself starting this class design from scratch a few times.
Good luck! Once you get used to C++, you'll never want to go back to C.
Could anyone make a suggestion as to whether I should have a single base class (ie. sensor) that all devices would extend/implement or if it makes sense to add a second layer of temperature type devices between the two? When would this be an advantage? Would this cause problems when I have a device that is both a temperature and a humidity sensor?
I was thinking of separate 'Interface' and 'Sensor' abstract classes.
These would be respectively derived into SPI,I2C etc and Temperature,Pressure etc.
At some point, you might want to attach one temperature sensor to an I2C, and another temperature sensor to a SPI.
The Interface is all about data transport.
- Is the underlying hardware push or pull?
- Do you poll, or use interrupts?
- Do measurements need to be requested, or is the latest always available?
At it's most basic, you have an Interface.getReading() method.
The Sensor is about adding meaning to the data, like say for example normalising the data across a family of sensors.
A value of 100 from one temperature sensor might be Kelvin, and 100 from another is Centigrade.
I was thinking of doing something similar with specifying the interface but I think the sensors may vary too much to get much reuse out of an "I2C" interface class for example. One sensor might require a single register to be read while another may require complex configuration and different registers to be read / aggregated in a certain way. Because of this I was thinking I would need to write a separate driver for each device I use. Since my device OS has the hardware drivers I would just need to call the appropriate I2C or SPI r/w API to configure and poll the sensor.
I'm thinking it would be helpful to group sensors into the type of sensor they are so if I wanted to average the temperature reading across 5 sensors I could easily do this by iterating my list of temperature sensors. This would imply a structure as follows:
Sensor <--- Temperature<---- ADT7410
I think Sensor could be pure virtual or an interface however I'm a bit stuck with how I handle the case where I have two sensors in a single device. For example:
RHT03 would need to implement getTemperature() and getHumidity() and call the appropriate method based on which interface I use to access it. However I'm not sure what would happen if I wanted to print the reading of all sensors and called Sensor.getReading() for example. This is where my understanding of these classes is starting to break down.
I'm still stuck on whether or not I should have a separate layer for the different sensor types or just have a "sensor" class and then devices implementing that.
Also not sure how to handle the case where a device implements two sensor types. Any thoughts?