libplctag / libplctag.NET

A .NET wrapper for libplctag.
https://libplctag.github.io/
Mozilla Public License 2.0
221 stars 56 forks source link

Raw Tag Read and Writes on a Kinetix 5100 Servo Controller #414

Closed LMansor23 closed 2 months ago

LMansor23 commented 2 months ago

Hello,

This is my first time using this library and it may get used to displace the current EEIP.dll that we are currently using at my workplace. I did look into the ExampleRaw.cs, and I tried to use it to communicate to the Kinetix 5100 servo controller / drive. I was not successful with the setting up the connection manager based on a Wireshark capture that I ran when I executed the console program.

I am interested in knowing whether or not it is possible to communicate with the Kinetix 5100 Servo controller at all using this wrapper library for .net? I have the information for the input and output assemblies, and the EDS file which contains all information related to the class, instances, and attributes.

Please let me know if you have any insight on this issue, otherwise, I will try to stick with the much older library.

kyle-github commented 2 months ago

Try turning off the connection attempt. All that should happen then is that the EIP session should be set up but nothing else. I am not sure what that attribute maps to, but the C library uses "use_connected_msg=0" to configure this. It might be UseConnectedMsg=false?

Can you attach the capture or turn on the debugging so we can see if it is the C DLL that is reporting the error or something higher up?

LMansor23 commented 2 months ago

Kinetix Testing.zip Here is an attached capture with the Kinetix Servo Drives, the captures were taken when running some of the example code. I also attached in the zip file the EDS file for those servos drives. They're freely available from Rockwell Automation albeit you will have to scour their database to find the name of the EDS file itself. I can also provide a capture based on the EEIP.dll and its communication and see if that helps with connecting the dots.

Also the Kinetix Servo Drives have two specified assemblies based on the manual:

Input Assembly: 104 Output Assembly: 154

No specified Configuration Assembly.

I am unsure as to where these Assembly values go and how they are used in this library, I would suspect they would have some usage but no example is clear about this.

LMansor23 commented 2 months ago

eeip.zip

Here is a Wireshark capture using the EEIP.dll to communicate to the servo controller if that helps with comparing and contrasting. I do not know which tag property needs to be changed in order to change from a large forward open to a normal forward open. I am still looking into that.

kyle-github commented 2 months ago

It looks like the EEIP.dll capture shows a failure of ForwardOpen there too. Very short RPI. But it still continues after that with the DLL still making individual calls to various class/instances.

In order to force the library to suppress use of the newer Forward Open, use the conn_only_use_old_forward_open tag attribute. Set that to 1. If you want to suppress a Forward Open connection set up completely, use the use_connected_msg attribute and set it to 0 (zero).

kyle-github commented 2 months ago

I did a detailed decoding of the capture of the EEIP.dll packets.

First request read a single attribute:

0000 34 c0 f9 fc 09 f6 08 92 04 ed 5c cd 08 00 45 00 0010 00 58 0f 6b 40 00 80 06 00 00 c0 a8 00 32 c0 a8 0020 00 ad dc b9 af 12 e8 8a be 1f c6 29 b6 a9 50 18 0030 10 0a 82 7a 00 00 6f 00 18 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 02 00 00 00 00 00 b2 00 08 00 0e 03 0060 20 04 24 68 30 03

Class 0x04 - Assembly class Instance 0x68 Attribute 0x03

Response:

0000 08 92 04 ed 5c cd 34 c0 f9 fc 09 f6 08 00 45 6c 0010 00 7c 6a 4d 40 00 40 06 4d 93 c0 a8 00 ad c0 a8 0020 00 32 af 12 dc b9 c6 29 b6 a9 e8 8a be 4f 50 18 0030 0b 1c 56 b0 00 00 6f 00 3c 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 02 00 00 00 00 00 b2 00 2c 00 8e 00 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0080 00 00 00 00 00 00 00 00 00 00

42 bytes of zeros:

0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0080 00 00 00 00 00 00 00 00 00 00

Next Request read single attribute:

0000 34 c0 f9 fc 09 f6 08 92 04 ed 5c cd 08 00 45 00 0010 00 58 0f 6c 40 00 80 06 00 00 c0 a8 00 32 c0 a8 0020 00 ad dc b9 af 12 e8 8a be 4f c6 29 b6 fd 50 18 0030 10 09 82 7a 00 00 6f 00 18 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 02 00 00 00 00 00 b2 00 08 00 0e 03 0060 20 04 24 9a 30 03

Class 0x04 Instance 0x9a Attribute 0x03

Response:

0000 08 92 04 ed 5c cd 34 c0 f9 fc 09 f6 08 00 45 6c 0010 00 88 6a 4e 40 00 40 06 4d 86 c0 a8 00 ad c0 a8 0020 00 32 af 12 dc b9 c6 29 b6 fd e8 8a be 7f 50 18 0030 0a ec 3e 50 00 00 6f 00 48 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 02 00 00 00 00 00 b2 00 38 00 8e 00 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0090 00 00 00 00 00 00

54 bytes of zeros.

Then an attempt at Forward Open:

0000 34 c0 f9 fc 09 f6 08 92 04 ed 5c cd 08 00 45 00 0010 00 96 0f 6d 40 00 80 06 00 00 c0 a8 00 32 c0 a8 0020 00 ad dc b9 af 12 e8 8a be 7f c6 29 b7 5d 50 18 0030 10 09 82 b8 00 00 6f 00 56 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 03 00 00 00 00 00 b2 00 32 00 54 02 0060 20 06 24 01 03 fa e6 e3 46 06 e7 e3 46 06 6f 64 0070 ff 00 ff ff ff ff 03 00 00 00 50 00 00 00 2e 48 0080 50 00 00 00 36 c8 01 04 20 04 24 bf 2c 68 2c 9a 0090 01 80 10 00 00 02 09 5b 00 00 00 00 00 00 00 00 00a0 00 00 00 00

CPF header:

0054 03 00 - three items

  1. 00 00 00 00 — null address/unconnected address

005a b2 00 — unconnected data item 005c 32 00 — 50 bytes of data follows. 005e 54 02 20 06 24 01 - Forward open to the message router object 0064 03 — seconds per tick = 3 0065 fa — timeout ticks = 250 ticks = 750 seconds (!) 0066 e6 e3 46 06 - Originator to Target connection handle/PC side 006a e7 e3 46 06 - Target to Originator connection handle, why are we setting this?? 006e. 6f 64 - our connection serial number 0070 ff 00 - vendor ID

  1. ff ff ff ff - vendor serial number (looks sketchy)
  2. 03 - timeout multiplier (multiplied by RPI)
  3. 00 00 00 - reserved/not used 007a. 50 00 00 00 - requested RPI (us to target) in microseconds, 80 us? Uhh….
  4. 2e 48 - The lower 9 bits is the connection size = 46 bytes, point-to-point 0080 50 00 00 00 - RPI from target to us, again 80us, no way that will work. 0084 36 c8 - lower 9 bits = 54 bytes, point-to-point 0086 01 - transport class 0x01 with sequence ID prepended. 0087 04 20 04 24 bf 2c 68 2c 9a - Connection path: Class 0x04 - assembly class Instance 0xbf Logical Segment/Connection Point: 0x68 Logical Segment/Connection Point: 0x9a

That’s the end of the FO request. But there is still more data:

This is the 3rd part of the CPF

0090 01 80 - Logical segment, Sockaddr info item 0092 10 00 - length of data, 16 bytes. 0094 00 02 - socket family, note network byte order, 2 = UDP. 0096 09 5b - port 2396 (bit endian/network order) 0098 00 00 00 00 - IP address, 0.0.0.0 means point to point? 009c 00 00 00 00 00 00 00 00 - reserved, set to zero.

However, this Forward Open fails. The RPI is too small.

The EEIP library seems to give up at that point and does the following:

  1. Write to attribute

0000 34 c0 f9 fc 09 f6 08 92 04 ed 5c cd 08 00 45 00 0010 00 5c 0f 6e 40 00 80 06 00 00 c0 a8 00 32 c0 a8 0020 00 ad dc b9 af 12 e8 8a be ed c6 29 b7 b1 50 18 0030 10 09 82 7e 00 00 6f 00 1c 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 02 00 00 00 00 00 b2 00 0c 00 10 04 0060 20 0f 25 00 0c 01 30 01 01 00

This writes to class 0x0F, instance 0x10c and attribute 0x01 with the value 0x0001. Possibly turning something on?

Class 0x0f is the parameter object class. Each parameter (generally config?) of a device has an instance of this class.

Then it writes again:

0000 34 c0 f9 fc 09 f6 08 92 04 ed 5c cd 08 00 45 00 0010 00 5c 0f 6f 40 00 80 06 00 00 c0 a8 00 32 c0 a8 0020 00 ad dc b9 af 12 e8 8a bf 21 c6 29 b7 dd 50 18 0030 10 08 82 7e 00 00 6f 00 1c 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 02 00 00 00 00 00 b2 00 0c 00 10 04 0060 20 0f 25 00 19 01 30 01 01 00

This writes to class 0x0F, instance 0x119, attribute 0x01 with the value 0x0001.

Then the library starts reading attributes:

0000 34 c0 f9 fc 09 f6 08 92 04 ed 5c cd 08 00 45 00 0010 00 5a 0f 71 40 00 80 06 00 00 c0 a8 00 32 c0 a8 0020 00 ad dc b9 af 12 e8 8a bf 55 c6 29 b8 09 50 18 0030 10 08 82 7c 00 00 6f 00 1a 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 02 00 00 00 00 00 b2 00 0a 00 0e 04 0060 20 0f 25 00 2c 01 30 01

This is reading class 0x0f, instance 0x12c, attribute 0x01.

That returns:

0000 08 92 04 ed 5c cd 34 c0 f9 fc 09 f6 08 00 45 6c 0010 00 56 6a 52 40 00 40 06 4d b4 c0 a8 00 ad c0 a8 0020 00 32 af 12 dc b9 c6 29 b8 09 e8 8a bf 87 50 18 0030 09 e4 20 28 00 00 6f 00 16 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 02 00 00 00 00 00 b2 00 06 00 8e 00 0060 00 00 81 4e

Which is an INT value of 0x4e81.

Then it reads another attribute:

0000 34 c0 f9 fc 09 f6 08 92 04 ed 5c cd 08 00 45 00 0010 00 58 0f 72 40 00 80 06 00 00 c0 a8 00 32 c0 a8 0020 00 ad dc b9 af 12 e8 8a bf 87 c6 29 b8 37 50 18 0030 10 08 82 7a 00 00 6f 00 18 00 03 00 00 00 00 00 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 00 00 02 00 00 00 00 00 b2 00 08 00 0e 03 0060 20 0f 24 65 30 01

Class 0x0f, instance 0x65, attribute 0x01

Which returns: INT value 0x0000

Then it reads class 0x0f, instance 0x134, attribute 0x01.

This returns 0x58, 0x80, 0x04, 0x00, not sure if that is supposed to be 4 USINT, 2 UINT, or one UDINT value.

The we read class 0x0f, instance 0x6b, attribute 0x01 and get 0x0197 back.

I’ll go with more shorthand here.

Read 0x0f/0x12c/0x01 -> 0x4e81 (same as before)

Read 0x0f/0x65/0x01 -> 0x0000

Read 0x0f/0x134/0x01 -> 0x58, 0x80, 0x04, 0x00

Read 0x0f/0x6b/0x01 -> 0x0197

Read 0x0f/0x12c/0x01 -> 0x4e81

Read 0x0f/0x65/0x01 -> 0x0000

Read 0x0f/0x134/0x01 -> 0x58, 0x80, 0x04, 0x00

Read 0x0f/0x6b/0x01 -> 0x0197

And it just keeps reading attribute 0x01 of those four instances.

kyle-github commented 2 months ago

I think what is happening here is that the EEIP DLL reads the assemblies first, and then tries a Forward Open. Why it reads the assemblies first I do not know, but my guess is to see if they actually exist. The Forward Open tries to set up a connection to the assemblies themselves. The connection sizes are basically the same as the assembly data sizes with a few bytes of overhead. The DLL tries to set up a connection using point-to-point UDP so that the device will send UDP packets of the assembly instance/connection endpoint 0x9a to the PC periodically.

At least I think that is what is going on.

What I do not understand is why the EEIP DLL, after the Forward Open fails, goes on reading the same four parameter instances over and over. It seems like it should read the assemblies.

The assemblies make sense to me as those are collections of parameters etc. that are bundled together in single units.

kyle-github commented 2 months ago

One thing to try here is the following:

  1. Use the Micro800 PLC type as this does not need a path.
  2. set use_connected_msg to false (zero). This prevents libplctag from attempting to do a Forward Open.
  3. Read the assemblies as was done in the first two requests in the packet dump.

If anyone knows why the EEIP DLL keeps reading the same parameters over and over, please let me know!

kyle-github commented 2 months ago

It looks like I should add another PLC "type" which is "generic CIP". It should have nothing extra turned on.

LMansor23 commented 2 months ago

The constant reading of the same values is done by the program that is using the EEIP dll. Instance 0x134 is PR308 on the drive's parameter, which allows us to initialize the Servo at a specific PR on the statement list being used.

Anyways, thank you for your time I will try to see If I can use this library for handling communication with these servos.

kyle-github commented 2 months ago

Do you have any examples where the Forward Open works? It looks like if it worked the controller would be sending the PC client a stream of UDP packets with data. But I am not sure.

LMansor23 commented 2 months ago

Kistler Capture.zip Here's a forward open that works, but it is not connected to the Kinetix 5100 Servo Drive. The communication is done on a Kistler 5074A charge amplifier which connects to two load cell sensors.

kyle-github commented 2 months ago

Hmmm... This is interesting. The FO does work. The RPI is every 10ms. That is fast, but possible on a hardwired network. The T->O packets seem to be pretty close to 10ms apart.

The data flow after the FO is exactly what I was hoping. The size is equivalent to the initial data results received doing the standalone attribute reads.

kyle-github commented 2 months ago

@LMansor23 what do you want to do here? It looks like it should be possible to read the assembly instances directly without having the FO set up the UDP data flow. At least with the library the way it is now. If you want to get packets as in the Kistler capture, that is going to take modifications to the core library. I am planning on doing those anyway because I want to support produced/consumed tags and things like this.

LMansor23 commented 2 months ago

@kyle-github I believe I got what I needed to make this library work with the servo drives, so I don't believe I need anything else for the time being, so we can consider the issue closed.

kyle-github commented 2 months ago

Please let us know if it works out. If you have any more problems, please reach out and either reopen this issue or open a new one. Yours is a use case that should be supported by the library!