-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to write to UDT #116
Comments
|
Could you please consider this (write to UDT) as a new feature? |
I have had success writing UDTs in my library. I cheat. Before the first write, I make sure I do a read. I copy the type bytes into local memory and send them back unchanged on write. The base types like DINT take two bytes for type info. But UDTs and some other types take at least 4. Here is the C code (data is a pointer to bytes that points to the first byte of the type info in the returned read response): /* the first byte of the response is a type byte. */
pdebug(DEBUG_DETAIL, "type byte = %d (%x)", (int)*data, (int)*data);
/* handle the data type part. This can be long. */
/* check for a simple/base type */
if ((*data) >= AB_CIP_DATA_BIT && (*data) <= AB_CIP_DATA_STRINGI) {
/* copy the type info for later. */
if (tag->encoded_type_info_size == 0) {
tag->encoded_type_info_size = 2;
mem_copy(tag->encoded_type_info, data, tag->encoded_type_info_size);
}
/* skip the type byte and zero length byte */
data += 2;
} else if ((*data) == AB_CIP_DATA_ABREV_STRUCT || (*data) == AB_CIP_DATA_ABREV_ARRAY ||
(*data) == AB_CIP_DATA_FULL_STRUCT || (*data) == AB_CIP_DATA_FULL_ARRAY) {
/* this is an aggregate type of some sort, the type info is variable length */
int type_length = *(data + 1) + 2; /*
* MAGIC
* add 2 to get the total length including
* the type byte and the length byte.
*/
/* check for extra long types */
if (type_length > MAX_TAG_TYPE_INFO) {
pdebug(DEBUG_WARN, "Read data type info is too long (%d)!", type_length);
rc = PLCTAG_ERR_TOO_LARGE;
break;
}
/* copy the type info for later. */
if (tag->encoded_type_info_size == 0) {
tag->encoded_type_info_size = type_length;
mem_copy(tag->encoded_type_info, data, tag->encoded_type_info_size);
}
data += type_length; It is a pain. I cannot remember where I first saw this logic. Arrays and UDTs usually have a type ID that is two bytes (I think this corresponds to the type ID that you get when enumerating the tags in a PLC) but it can be a full description with many, many bytes. I have not seen that but it is possible apparently. What you see in the packet is that a UDT will generally have 4 type bytes. The first one is an indicator that the type is a structure. The next one contains the number of bytes of the type ID. Then you get two bytes of type ID. Total of four. The first two are actually an INT with various bit fields but it works out as above. I have not checked to see if the type bytes you get when reading a tag are the same as the ones you get when listing out tags. |
I know we've been down this road many many times about UDTs in many issues opened in the past. and prob many more... @dmroeder would you suggest that the best solution for @ramezanifar right now as the code stands is to parse the xml from the L5X file for the UDTs, and then use those tags with correct data type, provided they are base data types, if another UDT is within the UDT then it becomes more problematic. @ramezanifar the biggest problem about implementing UDT's logic, is that people will have to learn how to unpack and pack byte data as shown in the timer example, that alone can open up a big can of worms in terms of maintainability. |
I will be happy to pass the byte array because I already know the structure of my UDT. |
Right, _writeTag method is not meant for UDTs, hence the exception. The only UDT operation in pylogix is to get UDT names, which is _getUDT Pull Requests are welcome. |
Thank you for the sample.
Result:
Result: So PLC did not like it! |
Hi. I have few questions:
Q1)
Can you please provide an example how to write to a tag of type UDT having the values as an array of bytes?
There is an example how to read from a timer. I used it to read from a UDT and then tried to write it back to the same tag with the value I got from read (ret.Value) but it throws an error.
Q2)
In one of your examples you mention if the data type is provided, read and write become faster.
If I read from a tag of type UDT, what type should I use? I tried 163= SINT and 160= STRUCT
but it failed.
Q3) When reading from a UDT tag, the number of bytes returned are two more than that of UDT definition. Is this expected?
Thank you in advance
The text was updated successfully, but these errors were encountered: