Beckhoff-USA-Community / SPT-Libraries

MIT License
70 stars 16 forks source link

INTERFACE I_CyclicFB EXTENDS I_BaseFB - why???? #3

Closed stefanspiegel closed 1 year ago

stefanspiegel commented 1 year ago

Hello,

my name is Stefan Spiegel and am working for a swiss company named soplar. Together with @vanoo1983 we are developing a machine for paper bottles. We found your work on github and are very confinced that this is the proper way to develop a new machine. Thanks for your effort!

My question is the following: Why do the Base Interfaces EXTEND from each other? i.e. I_CyclicFB EXTENDS I_BaseFB, I_ComponentBase EXTENDS I_CyclicFB.

I can't see the point, why this is neccessary? I understand, that the FBs are EXTENDING from each other, but the INTERFACES? Wouldn't this lead to a so called diamond problem?

And in addition to that, when I look at the FB_DigitalSensor (which is using the same design pattern) - there the INTERFACE I_DigitalSensorBase is NOT EXTENDING the I_ComponentBase.

Best regards from switzerland, Stefan

nshiggins commented 1 year ago

I_CyclicFB extends I_BaseFB because any class (FB) that implements I_CyclicFB is expected to include all of the elements of I_BaseFB (Busy, Error, ErrorID). Likewise, all classes implementing I_ComponentBase are expected to also include these base interfaces.

Specifically with I_ComponentBase, it's important that all components that are to be used by PackML modules have a CyclicLogic() method so that the EM can call them simply by you registering the components with the EM. This is implied by I_ComponentBase extending I_CyclicFB.

We could have defined I_ComponentBase not extending I_CyclicFB and just specified CyclicLogic(), Busy, Error, ErrorID, etc. but this is duplicated effort and not a clean architecture.

Multiple inheritance is not allowed--compiler won't let you extend multiple FBs--but because interfaces are just prototypes and not concerned with specific implementation we can make an FB that implements multiple interfaces. The compiler doesn't care what the methods do, just that they exist and match the prototype. However, this example is not allowed:

INTERFACE I_A
  BOOL MyMethod()
INTERFACE I_B
  UDINT MyMethod()
FUNCTION_BLOCK FB_Test IMPLEMENTS I_A, I_B

^^^^^^^^^^ This will not work, as the return types for the two methods specified in the interfaces return different types. The compiler won't let you do this.

I_DigitalSensorBase does not extend I_ComponentBase because not all digital sensors are necessarily components. FB_DigitalSensor extends FB_ComponentBase, so it will automatically inherit all the interfaces that FB_ComponentBase implements. I could see the argument that FB_DigitalSensor maybe should be named FB_Component_DigitalSensor to make this more clear--I will raise that with the team.

Another example in that library is FB_Component_xxxxAxis--they all extend FB_ComponentBase and can thus be used as components in PackML EMs, but they also implement I_BasicAxis so when you actually use them in your EM their functionality is already known via I_BasicAxis. In actuality the FB_Component_xxxxAxis FBs are just wrappers for FB_BasicAxis, adding the component model functionalities so that they can be used by PackML EMs.

The intent of the architecture was that we start with a device (NC axis for example) which you could use in any machine program. The next layer up is the component model, which adds Tc3_EventLogger functionality, a friendly name, specification of alarm handling behavior, etc. All of the above can be used without even thinking about PackML.

Finally if you have a PackML-based machine program, you use FB_PackML_BaseModule which already knows about the component model and how to handle that. In your specific PackML EM you can declare and assign various components (implements I_ComponentBase) to the EM and it already knows how to call them, react to errors, etc.

I hope this helps--it's a little bit difficult to explain.

stefanspiegel commented 1 year ago

Hello Nick, thank you very much for your detailed explanation! All the confusions are gone now :-). The fact, that components are registered at its owner-EM via the I_ComponentBase explains it all. When you ca.. methods from the I_CyclicFB via the registered I_ComponentBase there is a need to do this EXTENSION. I will close this issue - everything is clear and understood ;-). Kind regards, Stefan