Studio 5K: UDTs and Strings as AOI Output Parameters

JeremyM

Lifetime Supporting Member
Join Date
May 2014
Location
Dallas, Texas
Posts
1,233
For those of you that like living on the bleeding edge of development, you can do this without the need to resort to In/Outs and dummy references when you don’t need to use the feature - just a bit more object-oriented programming.

🍻

I’ll attach a sample .L5X program soon.

Create an output parameter as an alias to the first member of your AOI’s local UDT or STRING (.LEN). I prefer naming it “Ptr_LocalTag”, but it doesn’t matter for this.

Outside the AOI, you can safely and successfully do
- COP(AOI_Instance.Ptr_LocalTag, OutsideUDT, 1);

If you get the destination type wrong, you won’t risk faulting the processor because of how COP works (relying upon the size of the destination type to avoid overrun).

I have an idea on how to achieve writing to the AOI’s local structures. I’ll try fleshing it out on my flight home and testing this evening. You may already get where I’m coming from.

Previously I posted a method of getting the processor to message itself but this is limited to an instance-by-instance thing, doubles your memory requirements, and is just cumbersome overall.
 
Last edited:
Interesting idea.
My only concern is that destination boundary check is done on regular tags and not on UDTs or structures, so I am not sure how this will actually work to avoid boundary crossing.
 
COP is byte-for-available-byte of any structure, IIRC.

In any case, my C++ background says that once you use pointers, you are responsible for what happens. :D
 
Last edited:
COP is byte-for-available-byte of any structure, IIRC.
If your target is UDT, then the following bytes are usually available beyond the member that you are targeting.
I can't speak for C++, I live in AOI creation/implementation world and every time we see some unexpected behavior, I know that we are crossing boundaries someplace.
 
I suspect COP just performs a sizeof() internally on the destination type before copying bytes. If you pass UDT.member instead of UDT, it will likely stop at the number of bytes of the member type.
 
alias to the first member of your AOI’s local UDT
One thing I am not sure is how do you know what is the first member of the Local tags? You can change Parameter order, but there is no way to specify what Local tag will be at the top in the memory. The Tag Browser sorting these by Name and it does not mean that these will be in the same order in the memory.
You can create another UDT for Local tags, then these will be all in the specified order. Complicates things if you want to make a change.
 
I don’t think the tag browser’s sorting has any affect on the controller’s internal addressing. At least I hope not.

An instantiated UDT is just the base address of the blob that follows. If you change the order within your UDT, you’ll of course need to update aliases that reference them.

Just keep your AOIs and their local types in lock-step. Strings are likely to be length-prefixed until the end of time so, in my opinion, a *user*-defined type is subject to *user* responsibility.
 
Last edited:
An instantiated UDT is just the base address of the blob that follows.
I agree, but how do you know the order of the Local tags?

Let say I created Local tag BBB, instantiated AOI, then then I created tag AAA.
Then you look at the browser, AAA will be first, then BBB, but in memory AAA can be second, in the order of creation. This is my pure guess, I am not sure.
 
It won’t matter - BBB is a blob of bytes enumerated by the template it’s instantiated on. A UDT instance is always contiguous in memory and ordered by members declared (atomic or otherwise). As long as your alias holds true to the first member (meaning you don’t change the order of members of the type), you’ll be okay.

The order and instantiation of the local members of the final AOI in memory will follow whatever Rockwell’s compiler ordains, but members within UDTs will remain ordered.

Moral of the story: The alias address into the AOI could change a million times as long as you don’t change the UDT member order.
 
Last edited:
Somebody is living dangerously.


Local tags in an AOI do not form a separate UDT. They are pooled in the same UDT along with Input and Output parameters. Local BOOLs get packed in the beginning of the AOI alongside EnableIn and EnableOut (hidden DWORDs instead of hidden SINTs), in particular.
 
The alias address into the AOI could change a million times as long as you don’t change the UDT member order.
I think order will change, if you export AOI or rung in XML then import it.
Local tag order in memory most likely will change.
 
Let me clarify: I’m referring to UDTs instantiated within the AOI, not the sum total AOI as a UDT; Logix definitely does not unpack a nested UDT’s members into some flat space. If you alias the first member of a nested UDT, it will reliably follow that member around, regardless of changes made to the encapsulating AOI.
 
Last edited:
I suspect COP just performs a sizeof() internally on the destination type before copying bytes. If you pass UDT.member instead of UDT, it will likely stop at the number of bytes of the member type.


No it won't.

COP (and CPS) will calculate the number of bytes to copy as the "size-of" the destination data-type times the Length you put into the instruction.

There is no check on "sizeof" performed at all.


error-checking is minimalised to make these instructions work as fast as possible.

The number of bytes copied from the source to the destination is purely calculated as the destination data-type size, multiplied by the Length parameter you declare in the instruction, ergo, no boundary testing is done.

The ONLY saviour is that the destination tag boundary is observed, but the "destination" may be a subset of the destination's tag, and in those circumstances you need to be certain of what you are doing, the compiler will not protect you if you have the numbers wrong.
 
Yes, that’s what sizeof() does - don’t take the mnemonic literally - it’s a function performed by COP to help determine the total write length by using the destination operand’s size.

Set up a UDT with a few DINTs. Create a couple instances of it.

Try: COP(source, dest, 1)
Now try: COP(source, dest.dint1, 1)

COP goes as far as [bytes of destination type] * [count].

If you’re parsing a single structure from the AOI, you’d only ever use 1 as the count.

The number of bytes copied from the source to the destination is purely calculated as the destination data-type size, multiplied by the Length parameter you declare in the instruction, ergo, no boundary testing is done.
… and we need little else. Extracting from objects a structure that ends up in the wrong data type should give one no more grief than had they assigned the wrong value to an operand - in this case they just picked the wrong operand upon which to assign a value.
 
Last edited:
Let me clarify: I’m referring to UDTs instantiated within the AOI, not the sum total AOI as a UDT; Logix definitely does not unpack a nested UDT’s members into some flat space. If you alias the first member of a nested UDT, it will reliably follow that member around, regardless of changes made to the encapsulating AOI.


Ok, I see what you mean now.
 

Similar Topics

I've used AOI and User Defined Data Types, but I haven't created one yet. I have a lot of repetitive MOV commands to take a select number of...
Replies
4
Views
375
Hi guys , I'm new with Allen Bradley, but I have experience with Tia portal (s7 1200 ,s7 1500) I want to convert my project from Tia portal to...
Replies
1
Views
92
Hi everyone, I have an issue with installation of Studio 5000 33.00.02 DVD Media disc 2 with View Designer on Windows 11. After installation...
Replies
0
Views
70
Hi all. My maintenance department is clamoring for the ability to look at the PLC programs (and we finally have some who can read it.) I have a...
Replies
13
Views
438
Anyone have problems/solutions with Rehosting Studio 5000 to a new computer. Our IT department successfully Rehosted 2 laptops, but the other 2...
Replies
1
Views
119
Back
Top Bottom