Looks all good to me, and I agree with your both. On note to option 2: When you look at it from a generic perspective this is more like a batch-set-property were you set "some" property (endianess is one of them) for a batch of fields. So I could imaging such batch-attribute-setting later down the line.
And yes setting them as complex attributes look clean and as Lukasz noted it shouldn't be that hard... - Sebastian On 2021/09/26 21:34:37, Łukasz Dywicki <l...@code-house.org> wrote: > man, these samples are pretty long to go with, but from overall issue it > seems like we need to do reflect multi layer protocols in a better way. > > As far I understand the problem - it boils down to underlying buffer > which is started with BE and we need to read things using LE. > I see issue in two areas: > 1) We have no BE/LE switch for buffer other than constructor argument > 2) The switch in case of profinet is contextual and depends on protocol > layer we're currently in. > > Given the 1 - which is currently the base layer I think going with any > of ways you mentioned we will probably need a "flip" operation to swap > endianness or so. > Personally I think making the switch at the type level is easiest to get > since we had this attempt in the past. Having an extra block for it > seems like a bigger change (yet we discuss another block idea). > Making a contextual switches for fields is doable since new APIs made by > Sebastian for reader/writer allow to pass "withOptions" which would > really work well in this scenario. > > So if you'd ask me I'd opt for type level and field level switch. With > this we could in theory simulater a block with a a complex type having a > endianness switch. > > Best, > Łukasz > > > On 26.09.2021 15:59, Christofer Dutz wrote: > > Hi all, > > > > I'm currently working on the PROFINET ... here I have the challenge, that I > > have multiple layers of different protocols. > > > > UDP -> DCE/RPC -> PROFINET IO CM (Block Container) -> PROFINET IO CM Blocks > > > > The problem is: > > > > > > * UDP is Big Endian > > * PROFINET IO CM Blocks are Big Endian > > * DCE/RPC is big or little endian depending on a variable inside the > > DCE/RPC packet > > * Profinet IO CM (block container) is the same encoding as the DCE/RPC > > packet > > > > At first I thought if I force my request to big endian, then the response > > would be accordingly. > > Unfortunately that's not the case ... So if I send a request with Big > > Endian DCE/RPC (Hence, makeing the entire message Big endian). I still get > > a response back with DCE/RPC in Little Endian. So I have to be able to > > handle both. > > > > Now I had multiple ideas: > > > > * A new sort of block "endianessSwitch" (or a better name) ... which > > takes an argument and which simply switches the endianess of the buffers to > > the given one. This would probably be pretty simple to implement with a > > "try-finally" block in Java. > > * We add an optional additional option to the complex-type > > declarations. This would however have us split types into two. > > > > Here comes the example of the PN DCE/RPC packet with an endianessSwitch: > > > > [discriminatedType 'DceRpc_Packet' > > [const uint 8 'version' '0x04' > > ] > > [discriminator DceRpc_PacketType 'packetType' > > ] > > [typeSwitch 'packetType' > > ['REQUEST' DceRpc_Packet_Req > > [reserved uint 1 '0x0' > > ] > > [const uint 1 'broadcast' > > '0' ] > > [const uint 1 'idempotent' > > '1' ] > > [const uint 1 'maybe' > > '0' ] > > [const uint 1 'noFragmentAcknowledgeRequested' > > '0' ] > > [const uint 1 'fragment' > > '0' ] > > [const uint 1 'lastFragment' > > '0' ] > > [reserved uint 1 '0x0' > > ] > > ] > > > > ['RESPONSE' DceRpc_Packet_Res > > [reserved uint 1 '0x0' > > ] > > [const uint 1 'broadcast' > > '0' ] > > [const uint 1 'idempotent' > > '0' ] > > [const uint 1 'maybe' > > '0' ] > > [const uint 1 'noFragmentAcknowledgeRequested' > > '1' ] > > [const uint 1 'fragment' > > '0' ] > > [const uint 1 'lastFragment' > > '1' ] > > [reserved uint 1 '0x0' > > ] > > ] > > > > ['REJECT' DceRpc_Packet_Rej > > [reserved uint 1 '0x0' > > ] > > [const uint 1 'broadcast' > > '0' ] > > [const uint 1 'idempotent' > > '0' ] > > [const uint 1 'maybe' > > '0' ] > > [const uint 1 'noFragmentAcknowledgeRequested' > > '0' ] > > [const uint 1 'fragment' > > '0' ] > > [const uint 1 'lastFragment' > > '0' ] > > [reserved uint 1 '0x0' > > ] > > ] > > ] > > [reserved uint 6 '0x00' > > ] > > [const uint 1 'cancelWasPending' > > '0' ] > > [reserved uint 1 '0x0' > > ] > > [simple IntegerEncoding 'integerEncoding' > > ] > > [simple CharacterEncoding 'characterEncoding' > > ] > > [simple FloatingPointEncoding 'floatingPointEncoding' > > ] > > [endianessSwitch 'integerEncoding == IntegerEncoding.BIG_ENDIAN' > > [const uint 8 'serialHigh' '0x00' > > ] > > [const uint 8 'serialLow' '0x00' > > ] > > // 4.10.3.2.8 Coding of the field RPCObjectUUID > > DEA00000-6C97-11D1-8271-{instanceOrNodeNumber}{deviceId}{vendorId} > > // Apache Vendor Id: 0x060B > > // PLC4X Profinet Driver Device ID (can be chosen freely): 0xCAFE > > // NOTE: We can get the Device-Id and Vendor-Id from the PN-DCP > > search result of the browser. > > [const uint 32 'uuid1' '0xDEA00000' > > ] > > [const uint 16 'uuid2' '0x6C97' > > ] > > [const uint 16 'uuid3' '0x11D1' > > ] > > [const uint 16 'uuid4' '0x8271' > > ] > > [simple uint 16 'instanceOrNodeNumber' > > ] > > [simple uint 16 'deviceId' > > ] > > [simple uint 16 'vendorId' > > ] > > // 4.10.3.2.9 > > // Device Interface: > > DEA00001-6C97-11D1-8271-00A02442DF7D > > // Controller Interface: > > DEA00002-6C97-11D1-8271-00A02442DF7D > > // Supervisor Interface: > > DEA00003-6C97-11D1-8271-00A02442DF7D > > // Parameter Server Interface: > > DEA00004-6C97-11D1-8271-00A02442DF7D > > [const uint 32 'interface1' '0xDEA00001' > > ] > > [const uint 16 'interface2' '0x6C97' > > ] > > [const uint 16 'interface3' '0x11D1' > > ] > > [const uint 16 'interface4' '0x8271' > > ] > > [const uint 16 'interface5' '0x00A0' > > ] > > [const uint 32 'interface6' '0x2442DF7D' > > ] > > // 4.10.3.2.10 > > // The Controller and the Device generate the uuid for each AR > > (Application Relationship) and use them as long as the AR exists > > [const uint 32 'activity' > > ] > > [const uint 16 'activity2' '0x0000' > > ] > > [const uint 16 'activity3' '0x1010' > > ] > > [const uint 16 'activity4' '0xAA25' > > ] > > [const uint 32 'activity5' '0x606D3C3D' > > ] > > [const uint 16 'activity6' '0xA9A3' > > ] > > [const uint 32 'serverBootTime' > > ] > > [const uint 32 'interfaceVer' '0x00000001' > > ] > > [const uint 32 'sequenceNumber' > > ] > > [const DceRpc_Operation 'operation' > > ] > > [const uint 16 'interfaceHint' '0xFFFF' > > ] > > [const uint 16 'activityHint' '0xFFFF' > > ] > > [const uint 16 'fragmentLength' > > 'payload.lengthInBytes'] > > [const uint 16 'fragmentNum' '0x0000' > > ] > > [const uint 8 'authProto' '0x00' > > ] > > [const uint 8 'serialLow2' '0x00' > > ]// TODO: Check this ... > > [simple PnIoCm_Packet 'payload' ['packetType'] > > ] > > ] > > ] > > > > The endianess switching would also apply tot he PnIoCm_Packet automatically. > > > > > > The other option would be: > > > > [discriminatedType 'DceRpc_Packet' > > [const uint 8 'version' '0x04' > > ] > > [discriminator DceRpc_PacketType 'packetType' > > ] > > [typeSwitch 'packetType' > > ['REQUEST' DceRpc_Packet_Req > > [reserved uint 1 '0x0' > > ] > > [const uint 1 'broadcast' > > '0' ] > > [const uint 1 'idempotent' > > '1' ] > > [const uint 1 'maybe' > > '0' ] > > [const uint 1 'noFragmentAcknowledgeRequested' > > '0' ] > > [const uint 1 'fragment' > > '0' ] > > [const uint 1 'lastFragment' > > '0' ] > > [reserved uint 1 '0x0' > > ] > > ] > > > > ['RESPONSE' DceRpc_Packet_Res > > [reserved uint 1 '0x0' > > ] > > [const uint 1 'broadcast' > > '0' ] > > [const uint 1 'idempotent' > > '0' ] > > [const uint 1 'maybe' > > '0' ] > > [const uint 1 'noFragmentAcknowledgeRequested' > > '1' ] > > [const uint 1 'fragment' > > '0' ] > > [const uint 1 'lastFragment' > > '1' ] > > [reserved uint 1 '0x0' > > ] > > ] > > > > ['REJECT' DceRpc_Packet_Rej > > [reserved uint 1 '0x0' > > ] > > [const uint 1 'broadcast' > > '0' ] > > [const uint 1 'idempotent' > > '0' ] > > [const uint 1 'maybe' > > '0' ] > > [const uint 1 'noFragmentAcknowledgeRequested' > > '0' ] > > [const uint 1 'fragment' > > '0' ] > > [const uint 1 'lastFragment' > > '0' ] > > [reserved uint 1 '0x0' > > ] > > ] > > ] > > [reserved uint 6 '0x00' > > ] > > [const uint 1 'cancelWasPending' > > '0' ] > > [reserved uint 1 '0x0' > > ] > > [simple IntegerEncoding 'integerEncoding' > > ] > > [simple CharacterEncoding 'characterEncoding' > > ] > > [simple FloatingPointEncoding 'floatingPointEncoding' > > ] > > [simple DceRpc_PacketPayload 'payload' > > endianess='integerEncoding' ] > > ] > > > > [type 'DceRpc_PacketPayload' > > [const uint 8 'serialHigh' '0x00' > > ] > > [const uint 8 'serialLow' '0x00' > > ] > > // 4.10.3.2.8 Coding of the field RPCObjectUUID > > DEA00000-6C97-11D1-8271-{instanceOrNodeNumber}{deviceId}{vendorId} > > // Apache Vendor Id: 0x060B > > // PLC4X Profinet Driver Device ID (can be chosen freely): 0xCAFE > > // NOTE: We can get the Device-Id and Vendor-Id from the PN-DCP search > > result of the browser. > > [const uint 32 'uuid1' '0xDEA00000' > > ] > > [const uint 16 'uuid2' '0x6C97' > > ] > > [const uint 16 'uuid3' '0x11D1' > > ] > > [const uint 16 'uuid4' '0x8271' > > ] > > [simple uint 16 'instanceOrNodeNumber' > > ] > > [simple uint 16 'deviceId' > > ] > > [simple uint 16 'vendorId' > > ] > > // 4.10.3.2.9 > > // Device Interface: DEA00001-6C97-11D1-8271-00A02442DF7D > > // Controller Interface: DEA00002-6C97-11D1-8271-00A02442DF7D > > // Supervisor Interface: DEA00003-6C97-11D1-8271-00A02442DF7D > > // Parameter Server Interface: DEA00004-6C97-11D1-8271-00A02442DF7D > > [const uint 32 'interface1' '0xDEA00001' > > ] > > [const uint 16 'interface2' '0x6C97' > > ] > > [const uint 16 'interface3' '0x11D1' > > ] > > [const uint 16 'interface4' '0x8271' > > ] > > [const uint 16 'interface5' '0x00A0' > > ] > > [const uint 32 'interface6' '0x2442DF7D' > > ] > > // 4.10.3.2.10 > > // The Controller and the Device generate the uuid for each AR > > (Application Relationship) and use them as long as the AR exists > > [const uint 32 'activity' > > ] > > [const uint 16 'activity2' '0x0000' > > ] > > [const uint 16 'activity3' '0x1010' > > ] > > [const uint 16 'activity4' '0xAA25' > > ] > > [const uint 32 'activity5' '0x606D3C3D' > > ] > > [const uint 16 'activity6' '0xA9A3' > > ] > > [const uint 32 'serverBootTime' > > ] > > [const uint 32 'interfaceVer' '0x00000001' > > ] > > [const uint 32 'sequenceNumber' > > ] > > [const DceRpc_Operation 'operation' > > ] > > [const uint 16 'interfaceHint' '0xFFFF' > > ] > > [const uint 16 'fragmentNum' '0x0000' > > ] > > [const uint 16 'activityHint' '0xFFFF' > > ] > > [const uint 16 'fragmentLength' > > 'payload.lengthInBytes'] > > [const uint 8 'authProto' '0x00' > > ] > > [const uint 8 'serialLow2' '0x00' > > ]// TODO: Check this ... > > [simple PnIoCm_Packet 'payload' ['packetType'] > > ] > > ] > > > > Thinking about it ... we might even have a third option: Explicitly > > defininig the endianess in the complex type (Just a quick thought perhaps > > name things differently): > > > > > > // Big Endian > > [discriminatedType 'PnIoCm_Block' endianess=BIG_ENDIAN > > [discriminator PnIoCm_BlockType 'blockType' ] > > [implicit uint 16 'blockLength' 'lengthInBytes - 4'] > > [simple uint 8 'blockVersionHigh' ] > > [simple uint 8 'blockVersionLow' ] > > ... > > > > I have to admit, that I sort of like option 1 and 3 ... but we might even > > support all 3 variants. The implementation shouldn't be too hard. > > > > And thinking even more about it ... perhaps this concept of adding > > name=value pairs to the type declaration and the fields could also be used > > to controll Sebasitan's "try" flag. > > > > Chris > > > > > > >