Studio 5K: UDTs and Strings as AOI Output Parameters

How does your AOI work if I want to build an AOI that will concatenate 2 strings with custom string length?
Say STR1_50 (.Len=50) concat w STR2_100 (LEN=100) output to STR3_462(len=462)
and the next case:
STR4_60 (.Len=60) concat w STR5_110 (LEN=110) output to STR6_462(len=462)
 
Last edited:
How does your AOI work if I want to build an AOI that will concatenate 2 strings with custom string length?
Say STR1_50 (.Len=50) concat w STR2_100 (LEN=100) output to STR3_462(len=462)
and the next case:
STR4_60 (.Len=60) concat w STR5_110 (LEN=110) output to STR6_462(len=462)

This is more of a technique than an AOI. Basically, JeremyM has shown that it is possible to read and write to Strings (and technically, other objects like UDTs or arrays) without needing to make an InOut tag.

If your STR1_50 was needed by PLC code outside of the AOI (an HMI can access that string directly as a local parameter, provided its properties are set to Read/Write, which is not the default, IIRC), then you would create an output tag in your AOI that is aliased to the STR1_50.LEN tag that is a local tag in the AOI (STR1_LEN"), as well as another input tag aliased to STR1.DATA[0] ("STR1_DATA_Start").

In your AOI, you would also have a rung with a SIZE(STR1.DATA) instruction whose output is another output parameter to the AOI ("STR1_DATA_LEN").

Then, get the data from, say, a controller scoped string ("FirstPrefix") in the PLC into your AOI ("Concat_AOI"), you'd have an instruction COP(FirstPrefix, Concat_AOI.STR1_DATA_Start, Concat_AOI.STR1_DATA_LEN ). This would copy, byte by byte, the characters stored in FirstPrefix and put them in your AOI's STR1.
So that you don't have junk data $00/$00 in your string, you would also MOV the string length from the source to the destination:
MOV (FirstPrefix.LEN, Concat_AOI.STR_LEN ).

You'd do the same for any other tags that you want to move into the AOI's local tags.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To get the results of your concatenation out of your AOI without using an In/Out parameter, all you need is a tag in your AOI that is aliased to the desired output tags length (Tag: STR3_LEN, aliased to STR3.LEN, where STR3 is a STR3_110 data type that is a local scoped, not In/Out, in the AOI.

The instruction COP(Concat_AOI.STR3_LEN, CombinedString, 1) will start copying the data within your AOI, starting from STR3.LEN, putting it into CombinedString.LEN, and keep moving bytes until it has copied all the characters stored in STR3 into CombinedString.

Or, you could just let your strings be In/Out parameters. It can be cleaner and easier to understand. One advantage to JeremyM's method is that the data move can be done conditionally, whereas as an In/Out parameter, the copy happens every time the AOI is scanned.
 
I tried these methods with large Local UDT (17K+) and message instruction data.
But personally I would not to use it in any production systems for a very simple reason: while it works today, it does not mean it will work in any future version (Major or Minor) and boundary check added in firmware to flag these, faulting the controller.
 
If you use the same data type outside of the AOI as the target is on inside, there won't be any boundary issues.

And it's certainly better than what I once had to do, when I had a string in an AOI which was only for "HMI info only" and so was local-scoped, when the process engineer suddenly needed for something to happen outside of the AOI when the string changed, and I couldn't take the system down for a download.

I COP'ed the AOI tag to a INT[array], then COP'ed starting at just the right place into an external string (of the same data type). It worked, but if that AOI ever got changed, that code could break. That experience was why I've taken such an interest in JeremyM's technique. I can see myself making the alias tag for any embedded string.LEN going forward, whether that string is "supposed" to be needed by the main code or not. This will give me a hook to access it if the need should arise, and I can't make changes.

But this is an Advanced Technique, not for the faint of heart, and must be annotated to the max.
 
In/Out requires a declared external object, even if you don't plan to use it.

It makes the 'pass by reference' mechanism not quite so elegant, but that's more of a shortcoming of not having class methods by which you can pick and choose what to call.

For now, you call *all* of an AOI, or none of it.
 
Just curious, but what's wrong with using In/Out?

In general, nothing.

But....

The AOI performs two intrinsic COP's every time the AOI scan, one to move data from the outside tag to the inside one before the AOI logic is executed, and one to move data out afterwards. This nibbles at processor speed, especially if it's a large UDT that's going in and out. It was a bigger problem in the older days with the slower processors but once bitten, twice shy.

The intrinsic COPs happen EVERY time the AOI is scanned. Depending on how your program is structured with competing Periodic tasks, it is possible that a change to the data in the controller scoped tag by one task could get overwritten by the second COP, if the task the AOI is just happened to be mid AOI-scan when the higher priority task happened. I'm not 100% positive that this could occur, but I've been bitten by the asynchronous nature of multiple periodic tasks enough that I treat them as if they are in separate processors. And I would never write data in one processor that I know another processor will also write to, and expect the first one to use that data reliably. Other programmers may not have my caution.
 
Last edited:
In general, nothing.

But....

The AOI performs two intrinsic COP's every time the AOI scan, one to move data from the outside tag to the inside one before the AOI logic is executed, and one to move data out afterwards. This nibbles at processor speed, especially if it's a large UDT that's going in and out. It was a bigger problem in the older days with the slower processors but once bitten, twice shy.

The intrinsic COPs happen EVERY time the AOI is scanned. Depending on how your program is structured with competing Periodic tasks, it is possible that a change to the data in the controller scoped tag by one task could get overwritten by the second COP, if the task the AOI is just happened to be mid AOI-scan when the higher priority task happened. I'm not 100% positive that this could occur, but I've been bitten by the asynchronous nature of multiple periodic tasks enough that I treat them as if they are in separate processors. And I would never write data in one processor that I know another processor will also write to, and expect the first one to use that data reliably. Other programmers may not have my caution.

Using AOIs vs UDTs isn't a viable option all of the time though. Example, HMI/SCADA, see these posts that explains it better. I tested, and this is in fact a true case.

https://forum.inductiveautomation.com/t/tag-is-bad-quality-in-udt/47808/3
https://forum.inductiveautomation.com/t/cannot-read-some-tags-inside-rockwell-aoi/38393/19
 
Using AOIs vs UDTs isn't a viable option all of the time though. Example, HMI/SCADA, see these posts that explains it better. I tested, and this is in fact a true case.

https://forum.inductiveautomation.com/t/tag-is-bad-quality-in-udt/47808/3
https://forum.inductiveautomation.com/t/cannot-read-some-tags-inside-rockwell-aoi/38393/19

You can alleviate the hit by collecting pertinent AOI members into a UDT within the AOI. I’ve tested this in Ignition to be sure - reading a group of separate nested items vs. a nested UDT is night and day in performance. There could be other optimizations via ordering, but in a nutshell, a group reads significantly faster than individual items.

Attach the AOI parameters via aliasing on the AOI setup and you get the best of both worlds: optimized reads externally and giving single (and selective!) parameter access to non-AOI code.
 
Last edited:
You can alleviate the hit by collecting pertinent AOI members into a UDT within the AOI. I’ve tested this in Ignition to be sure - reading a group of separate nested items vs. a nested UDT is night and day in performance. There could be other optimizations via ordering, but in a nutshell, a group reads significantly faster than individual items.

Attach the AOI parameters via aliasing on the AOI setup and you get the best of both worlds: optimized reads externally and giving single (and selective!) parameter access to non-AOI code.

If you have time can you share an example or two on how this would look?
 
whereas as an In/Out parameter, the copy happens every time the AOI is scanned.


Um, no. In/Out parameters are not copied in either direction. The AOI manipulates their contents in place. Far more efficient than input or output parameters. I highly recommend them in AOI design.
 
You can alleviate the hit by collecting pertinent AOI members into a UDT within the AOI. I’ve tested this in Ignition to be sure - reading a group of separate nested items vs. a nested UDT is night and day in performance. There could be other optimizations via ordering, but in a nutshell, a group reads significantly faster than individual items.


Do look at the follow-up edit to my post on AOIs in Ignition:


https://forum.inductiveautomation.com/t/cannot-read-some-tags-inside-rockwell-aoi/38393/3?u=pturmel


The issue is the Ignition Logix driver too strictly (arguably) following Rockwell's Data Access manual, leaving it unable to optimize reads and writes to AOI types.


Vendors who have reverse engineering the AOI types can avoid this problem. (But not the problem of external access == None.)
 

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
388
Hello, i've been at this for months now, i tried creating accounts on the aveva website but it seems to never approve my accounts or at least when...
Replies
0
Views
28
Hi Everyone. Not posted on here for a long time, but I am hoping someone can help me. I am doing a differential pressure calculation in a L27ERM...
Replies
15
Views
237
Hi, how do I convert 2x Integer registers to a Real? The two integers are from Modbus registers that contain a floating point value, I need to...
Replies
2
Views
119
What is the best way to extract the hour and minute from the register that comes from Yaskawa VFD. In studio 5000 I have a register saved as INT...
Replies
3
Views
123
Back
Top Bottom