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
> > 
> > 
> > 
> 

Reply via email to