0

I'm trying to abstract away hardware dependencies for an embedded application.

I have an interface (frameWriterI.h)

template<typename Message)    
class FrameWriterI
{
     public:
        virtual void writeMessage(Message m)=0;
}

With multiple implementations like this one

(writerA.h)
class WriterA : public FrameWriterI<MessageA>
{
   public:
     void writeMessage(MessageA m)
}
(writerA.cpp)
void WriterA::writeMessage(MessageA m)
{
     /*use a DAC to write m with a format specific to A*/
     somethingReallyHardwareSpecific();
}

In the layer above, I have 1 state machine per implementation (A, B, C) that use the related Writers

 class StateMachineA:
 {
    public:
        void doSomethingThatUseWriterA();
    private:
         WriterA writer;
}

problem is that now, my state machines are hardware dependent. So in order to mock the writer for unit testing, I should use the interface instead:

 class StateMachineA:
 {
    public:
        void doSomethingThatUseWriterA();
    private:
         FrameWriterI<MessageA>& writer;
}

but where do I initialize the real WriterA?

in the constructor I cannot reference a temporary

(StateMachineA.cpp)
StateMachineA::StateMachineA(): writer(WriterA()){} //not valid

I try to avoid pointers as much as possible (limited heap space and coding preference) but if it's the only solution I could live with it but it can't be dynamically allocated.

The only solution that I found so far is the have a file scoped variable

(StateMachineA.cpp)
WriterA realWriter;
StateMachineA::StateMachineA(): writer(realWriter){}

Any better/cleaner solution?

  • If you are compiling for multiple specific hardware items you can usually create the class differently using pre-processor macros – Fantastic Mr Fox Jul 26 '18 at 13:36
  • You should read about object slicing. Also the idea of "abstracting away hardware dependencies" implies that the same binary may be executed on different hardware. Is it really the case? – user7860670 Jul 26 '18 at 13:37
  • Yes, the unit tests runs on my PC and the application itself run on an stm32. The usage of interfaces allows me to clearly separate real code from mock code in 2 different projects. It will quickly become a mess if I use #define for everything that I need to mock – Bertrand Thelen Jul 26 '18 at 13:46
  • I just googled object slicing but here given that it's a reference to the base class, it shouldn't be a problem: [link](https://stackoverflow.com/questions/2822146/references-and-object-slicing) and by reading your comment again, I see that you're speaking about the same binary and in that case no, it won't be the same binary but it will be the same headers and part of the same implementation as well – Bertrand Thelen Jul 26 '18 at 13:57
  • Sorry, I don't understand the problem? Why don't you pass the writer instance by reference to the constructor of the state machine? Since you have to keep an instance of the state machine class as long as you use the hardware resource, you can also keep an instance of the writer in the same place. For tests on the development host you can supply a mock instance e.g. using a mocking framework. – Alexander Jul 27 '18 at 18:48
  • That's what I did in the end. It's just that it makes the constructor of the StateMachine kind of heavy (the FrameWriter is not the only hardware dependency that I try to abstract) so for every dependency, I need to provide a reference to the interface class in the constructor but I can live with it – Bertrand Thelen Aug 01 '18 at 06:58
  • Ah ok, maybe you should add this concern to the question. A technique I developed for myself is to pass a reference to a struct which holds all external resources used by a driver instance. This includes references to lower layer driver interfaces as well as configuration options. However I don't supply this to the constructor, but through an init method, such that the config can be changed at runtime and I have full control when the initialization happens instead as part of the global object init. – Alexander Aug 01 '18 at 08:22

0 Answers0