Re-Thinking (or overthinking) Embedded OOP

rflcptr

Supreme [H]ardness
Joined
Mar 27, 2008
Messages
6,900
I've been writing some embedded libraries for an ongoing personal project and downshifted to really think about my approach.

Particularly, I'm sanity-checking whether an object-oriented implementation for some of this stuff is even a starter, or if my OO approach is worthless.

Here's where I'm coming from.
  • I've got a ControlStrategy (CS) class that provides the means for Device objects to self-arbitrate how they're operated.
    • actuated devices contain an instance of CS.
    • a device could be switched from Program (automatic) control to Operator (manual via HMI, phone app, etc.) for example.
    • a device could also be switch from anything to "Local" control, meaning the physical device is responding to its own hardwired inputs (typically a drive).
      • this would be handled by simply feeding the status of a local control station's Hand/Off/Auto switch to the CS.
      • implementing how this is handled is the challenge, I think.

What could be done in the class is:

C++:
class CS
{
    public:
    void setDisabled();
    void setEnabled();
 
    void setLocal();
    void releaseLocal();
 
    int32_t getOwner(); // returns current device owner
    private:
    int32_t owner; // enumerated, 0: undefined, 1: Local, 2: Disabled, 8: Program, 10: Operator, ...
};

What this demands of the calling code are branching if/else that can impact performance (each method call also evaluates ownership), readability, and possibly put the responsibility of determining the CS object state to the caller itself:

C++:
void loop()
{
    dvcMotor Device;
    bool swAuto = getDigIn01(); // pretend these calls represent input points
    bool swHand = getDigIn02();
 
    if (!(swAuto || swHand)) // HOA switch in 'Off'
        Device.CS.setDisabled();
    else if (swAuto)
        Device.CS.setProgram();
    else if (swHand)
        Device.CS.setLocal();
 
    // or maybe:
    if (!swAuto && !swHand) // HOA switch in 'Off'
        Device.CS.setDisabled();
    else
        Device.CS.setEnabled();
 
    if (swHand) // HOA switch in 'Hand/Local'
        Device.CS.setLocal();
    else
        Device.CS.releaseLocal(); // ... to what? Operator? Program?
}

Then there's the idea of mapping external inputs to the state of some public bool members. Those members are evaluated at the end of the controller loop to determine the owner of the motor.

C++:
class CS
{
    public:
    bool Inp_Disable;
    bool Inp_Local;
 
    void update(); // synchronous program call to 'refresh' object state
    int32_t getOwner(); // returns current device owner
    private:
    int32_t owner; // enumerated, 0: undefined, 1: Local, 2: Disabled, 8: Program, 10: Operator, ...
};

C++:
void loop()
{
    dvcMotor Device;
 
    Device.CS.Inp_Disable = getDigIn01();
    Device.CS.Inp_Local = getDigIn02();
 
    // possibly a bunch of process-related code
 
    Device.CS.update();
}

No branching required and the object manages itself from the state of inputs (Inp_Local always supercedes Inp_Disable in priority).

What do you think?
 
Last edited:
My C++ knowledge is limited, but.... based on your explanation, a base class with virtual methods/functions would be ideal. If you wanted to provide tighter rails to the implementation, then a base class with protected and/or abstract methods/functions could give value by providing a similar "presentation" to the consuming code.

Anything you can do upfront that simplifies the process for adding a new device would pay off dividends as your device catalog grows.
 
Last edited:
Back
Top