libplctag / libplctag.NET

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

How to write an UDT subset #354

Open CrineTech opened 8 months ago

CrineTech commented 8 months ago

Hi, is there any way (even with the NativeImport section of the library) to write in "raw mode" only a portion of a UDT, using tag path and an offset in bytes?

timyhac commented 8 months ago

Even without the raw tags you can write directly to individual tag members by specifying that in the Name e.g. MyUdt.TheDintMember.

By writing to a portion of a UDT what problem are you trying to solve?

CrineTech commented 8 months ago

I'm using libplctag as part of a bigger application that needs to communicate with many tipes of devices, and is higly configurable.

The user have the ability to define one or more custom types, and use them to read or write from one of the supported devices (so not only allen bradley), however, i only have the structure of the type, since i've no warranty on the fact that the name used by the user in the type configuration for the elements is the same of the one on the allenbradley side.

At the moment i'm reading and writing the whole UDT as a single block, but for the write portion i need to write the singular changed elements, in order to be sure to not override data changed between the last read and the write.

As a workaround i can force the user to use the same names as the allen bradley side in type definition, or i can add some kind of configurable mapping to map type elements to allenbradley tags, however, but this is not the perfect solution.

Since i already have the type structure and the routines needed to calculate the correct padding added by AB after some types, it will be simpler (at least simpler in the settings for the user) to just be able to write N bytes at X bytes offset from the begin of the tag addressing the whole UDT

This seems to be supported by the AB protocol, but i've found nothing about it in the library. Do you know if is something possible, at least using the direct NativeImport library, or if it is not supported?

kyle-github commented 8 months ago

Can you point to where the AB protocol that does this is documented? I haven't seen anything like that but would love to see any docs on it.

Note that you can get the UDT definitions from the PLC. That is supported in the core library and the .Net library has examples of how to do that. All you need to start with is the tag name. Then you read all the tags, look up the tag name and get the UDT type ID. Then you can look up the UDT definition and any nested definitions you need.

If you get the definitions, then you can create individual tag handles for the fields of the UDT (as well as the UDT as a whole) and use those to write to parts of the UDT. The library does not prevent you from having more than one handle to a tag.

CrineTech commented 7 months ago

Can you point to where the AB protocol that does this is documented? I haven't seen anything like that but would love to see any docs on it.

Search for "Write Tag Fragmented Service" inside this PDF file. 1756-pm020_-en-p.pdf

This should be used to write long tags that do not fit into a single packet, but, if there is no restriction, it should be possible to use this also to write a part of a tag.

This PDF comes from original rockwell website, i've uploaded it there just to be sure to leave it accessible if it will be removed by rockwell. This is the original address: https://literature.rockwellautomation.com/idc/groups/literature/documents/pm/1756-pm020_-en-p.pdf

Note that you can get the UDT definitions from the PLC. That is supported in the core library and the .Net library has examples of how to do that. All you need to start with is the tag name. Then you read all the tags, look up the tag name and get the UDT type ID. Then you can look up the UDT definition and any nested definitions you need.

I was not aware of this possibility, i will probably go down this way, thank you! From samples and docs it seems that i need to read all the tags in order to obtain the UDT ID of a particular tag, can you confirm me that the library / AB protocol don't support the operation to read the info about a single tag?

kyle-github commented 7 months ago

Ah, yes, the library currently uses the fragmented read/write on tags that support it (it is not supported on some types of PLC). But only for tags that will not fit in the request packet. I had not considered using it like this. That is a very interesting idea... I could set up a "only send changed bytes" type of write. I will think on this to see how that might work.

I am actually certain that the AB PLCs do have some sort of command to get type info about a single tag but I have never seen examples or found any documentation for it. Nor has anyone I communicate with. There is a little group of us who have implemented parts of the protocol who share information when we find things. I get a lot from the pylogix project and from pycomm3. We all want to find out how to do this because reading an entire tag list from a PLC is very time consuming and is only accurate at the time of reading.

The inconsistencies of the AB protocol for tag type information are really frustrating. You can only read all tags at once. But you can only read one UDT at a time. So you have to scan through all tags, get all the UDT IDs and then read those one at a time. It is the worst of both options. If you could get the type information for one tag and then the type info for its UDT type, that would be fine. If you could get all the tags at once and then all the UDTs at once, that would also be useful. But you cannot. At least not in any documented or found way we have seen.