Hi Chris,
By having the behavior of the driver defined, each object generated by the
driver (based on the mspec) must add its control logic.
In general, the way to solve the answers is based on the differentiation of
the classes in two ways, using "instanceof" or checking the values of the
"properties".
In code it would be something like this:
if (payloadItems[0] instanceof
S7PayloadUserDataItemCpuFunctionMsgSubscriptionResponse) {
...
} else if (payloadItems[0] instanceof
S7PayloadUserDataItemCpuFunctionMsgSubscriptionSysResponse) {
...
} else if (payloadItems[0] instanceof
S7PayloadUserDataItemCpuFunctionMsgSubscriptionAlarmResponse) {
...
} else if (payloadItems[0] instanceof
S7PayloadUserDataItemCpuFunctionAlarmAckResponse) {
...
} else if (payloadItems[0] instanceof
S7PayloadUserDataItemCpuFunctionAlarmAckErrorResponse) {
...
}
An so on, and
if ((myparameter.getCpuFunctionGroup() == 0x04) &&
(myparameter.getCpuFunctionType() == 0x00) &&
(myparameter.getCpuSubfunction() == 0x03)) {
...
} else if ((myparameter.getCpuFunctionGroup() == 0x02) &&
(myparameter.getCpuFunctionType() == 0x00) &&
(myparameter.getCpuSubfunction() == 0x01)){
...
} else if ((myparameter.getCpuFunctionGroup() == 0x02) &&
(myparameter.getCpuFunctionType() == 0x00) &&
(myparameter.getCpuSubfunction() == 0x05)) {
...
}
And so on
This is something that works and solves the problem, it is not in
discussion, and it is a good interceptor point for other languages, but how
can we help make it more readable and automatic from the mspec.
@startuml
interface Message
Message : public void accept(MessageVisitor visitor);
class S7PayloadUserDataItem
Message <-- S7PayloadUserDataItem
S7PayloadUserDataItem <--
S7PayloadUserDataItemCpuFunctionMsgSubscriptionResponse
S7PayloadUserDataItem <--
S7PayloadUserDataItemCpuFunctionMsgSubscriptionSysResponse
S7PayloadUserDataItem <--
S7PayloadUserDataItemCpuFunctionMsgSubscriptionAlarmResponse
S7PayloadUserDataItem <-- S7PayloadUserDataItemCpuFunctionAlarmAckResponse
S7PayloadUserDataItem <--
S7PayloadUserDataItemCpuFunctionAlarmAckErrorResponse
S7PayloadUserDataItemCpuFunctionMsgSubscriptionResponse : public void
accept(MessageVisitor visitor);
S7PayloadUserDataItemCpuFunctionMsgSubscriptionSysResponse : public void
accept(MessageVisitor visitor);
S7PayloadUserDataItemCpuFunctionMsgSubscriptionAlarmResponse : public void
accept(MessageVisitor visitor);
S7PayloadUserDataItemCpuFunctionAlarmAckResponse : public void
accept(MessageVisitor visitor);
S7PayloadUserDataItemCpuFunctionAlarmAckErrorResponse : public void
accept(MessageVisitor visitor);
@enduml
The only code required within each generated instance is
S7PayloadUserDataItemCpuFunctionMsgSubscriptionResponse() {
...
public void accept(MessageVisitor visitor) {
v.visit(this);
}
...
}
Now the visitor interface can be generated manually or from the mspec.
@startuml
interface S7MessageVisitor
S7MessageVisitor : public void
visit(S7PayloadUserDataItemCpuFunctionMsgSubscriptionResponse visitable);
S7MessageVisitor : public void
visit(S7PayloadUserDataItemCpuFunctionMsgSubscriptionSysResponse visitable);
S7MessageVisitor : public void
visit(S7PayloadUserDataItemCpuFunctionMsgSubscriptionAlarmResponse
visitable);
S7MessageVisitor : public void
visit(S7PayloadUserDataItemCpuFunctionAlarmAckResponse visitable);
S7MessageVisitor : public void
visit(S7PayloadUserDataItemCpuFunctionAlarmAckErrorResponse visitable);
@enduml
Having this interface defined, we can implement directly on the protocol
logic object, in the case of S7 "S7ProtocolLogic".
After implementing the logic associated with the objects, the main code
would look like:
...
payloadItems [0] .accept (this);
...
Something more elegant, I think.
For the control of the state machine we would surely have to pass specific
parameters, so the interface of the visitors should be something like:
public void accept (MessageVisitor visitor, Object ... args);
or something similar,
As for why this pattern applies to our case.
1. The objects associated with the protocol do not change over time, unless
the protocol is changed, which in itself is another protocol.
2. The objects generated by the mspec only have properties and not
associated logic.
3. The logic associated with each object can be implemented by the Visitor
pattern, which from my point of view generates more organized code, while
remaining optional.
My grain of sand,
El mar, 9 nov 2021 a las 5:45, Christofer Dutz ()
escribió:
> Hi Cesar,
>
> could you possibly whip up some example code that shows how it's currently
> done and how you propose to do it?
>
> Sebastian and I are currently greatly refactoring the code-generation, so
> now would be a perfect time for optimizing things.
>
> Chris
>
> -----Ursprüngliche Nachricht-
> Von: Cesar Garcia
> Gesendet: Montag, 8.