Logix 5000 : CIP Read Array into UDT

AMarks95

Member
Join Date
Jul 2018
Location
South Dakota
Posts
224
Hello,

Wondering if the following setup would work.

1. Local PLC on the network has an array of 25 REALs
2. Supervisory PLC on the network needs to read in these 25 REALs
2a. Set up a CIP data table read of the array with the destination being the first REAL of a UDT that contains 25 REALs. Will the CIP read fill in the REALs, or does it need to read directly into an array of 25 REALs and then I use a COP instruction to get it into the format?
 
Response data size is used by the read message to begin populating bytes of the destination element. If you point the message at a REAL, it stops there. If you set it to the UDT tag, it populates the UDT until reply data or destination data are exhausted, whichever comes first. The message may even error in the latter case for the response data being too large.

I can test in a bit.
 
Ok, so having worked with it a little more I have some clarification on my UDT and the data. So, the data to read is type REAL[24], so we'll say the first REAL is Data[0]. If I point the CIP read at Data[0] with a destination of the first real in the UDT (24 REAL members), and 24 elements, will the rest of the UDT populate?

Would appreciate any test results you come up with.
 
Last edited:
UDTs and arrays both carry a hidden size attribute that the message solicits while it’s doing its thing.
 
One other thing to be mindful of...

Back in the day, a COP instruction would blindly copy bits to the length specified, right or wrong. The thing that often catches people out (never me of course 🤥) was that the length was in terms of destination elements, not source elements. That is, if you have twelve 16-bit integers coming in from a Modbus device, and you need to assemble them into six 32-bit REALs, you would copy Source[0] to Destination[0] with a length of six. Six 32-bit REAL's, and it would grab twelve 16-bit integers to do it. Intuitively, it's easy to set the length to twelve, because you're mentally thinking "take these twelve integers and copy them over there".

Anyway, this mistake could cause a lot of problems because it would overwrite data arbitrarily without a care in the world. The PLC would, as PLC's always do, do exactly what you tell it to do and assume you know what you're doing.

Where this runs into real trouble is when you run off the end of an array. In the example above, if your destination array was only six REALs long, your PLC is going to write some meaningless data into the next 6*32 bits of memory in the PLC, which could be just about anything. And then you wind up with completely unrelated, unpredictable data changing in untraceable ways until you track down your mistake.

Anyway, in newer versions of hardware, they finally put a sanity check into the COP instruction which prevented it from copying past the end of an array or structure. So in the example above, you could put your length as 6 (correct), 12 (incorrect) or 65536 (wildly incorrect) and it would work as (presumably) intended, copying data from the source into the 6 REALs and then reaching the end of the array and stopping.

But of course, that only applies to newer hardware. Throw that code into a 5370 Compact Logix and You're Gonna Have A Bad Time.

All of that waffle goes to say - I don't know if MSG instructions have a similar sanity check involved, but if there is one, it may be hardware dependent. So if this is important, make sure you check it across a couple of different processor types!
 
That's one thing that I was unsure of here as well. Is the length still in terms of destination elements, or source elements?

If I'm reading the Data | REAL[24] into a UDT, would it be

a.
source = Data[0], destination = UDT_Instance.firstMember, length = 24

b.
source = Data, destination = UDT_Instance, length = 1

or something else?
 
Last edited:
That's one thing that I was unsure of here as well. Is the length still in terms of destination elements, or source elements?

If I'm reading the Data | REAL[24] into a UDT, would it be

a.
source = Data[0], destination = UDT_Instance.firstMember, length = 24

b.
source = Data, destination = UDT_Instance, length = 1?

I am reasonably confident the latter simply will not work. When using MSG with a UDT (as opposed to atomic member elements of the UDT) the source and destination type must exactly match -- if you have a UDT as the address on one end, the other end must be the same UDT.

cf this thread
 
I am reasonably confident the latter simply will not work. When using MSG with a UDT (as opposed to atomic member elements of the UDT) the source and destination type must exactly match -- if you have a UDT as the address on one end, the other end must be the same UDT.

cf this thread

Certainly true for Produce/Consume. Didn't get the chance this weekend to test for the kiddo, will try this evening.
 
That's one thing that I was unsure of here as well. Is the length still in terms of destination elements, or source elements?

If I'm reading the Data | REAL[24] into a UDT, would it be

a.
source = Data[0], destination = UDT_Instance.firstMember, length = 24

b.
source = Data, destination = UDT_Instance, length = 1

or something else?

After testing with emulate,
A works. B does not
 
Some test results.

Pass: Read array -> UDT array
Pass: Read UDT array -> array
Pass: Read array -> array
Fail: Read array -> UDT
Pass: Read array -> First (flat) UDT element
Pass: Read array -> Alias to UDT array
Pass: Read array -> Alias to first (flat) UDT element

(not pictured)

Fail: Read UDT -> Array
Fail: Read alias to UDT array -> Array
Fail: Read alias to (flat) UDT element -> Array
Fail: Read UDT -> Dissimilar UDT (same size)
Fail: Read SINT -> DINT
Fail: Read DINT -> SINT
Pass: Read UDT first element -> Dissimilar UDT (same size, same type of initial element)

CipDataTableRead_res.png
 
Last edited:
One other thing to be mindful of...

Anyway, in newer versions of hardware . . .

{snip}

But of course, that only applies to newer hardware. Throw that code into a 5370 Compact Logix and You're Gonna Have A Bad Time.

What does newer hardware mean? I've seen this issue with L7x series of ControlLogix and the only thing newer is the L8x (or its equivalent 5x80 CompactLogix
 
5580 Control Logix/Guard Logix (L8 Controllers) and 5380 Compact Logix/Compact Guard Logix (5069 Controllers)
 
Isn't this why we have a COP instruction?

Generally, yes. I think this thread shows why.

I've been exploring whether message service codes can be changed programmatically. At the least, this requires both COP and MSG working together in some creative way.

You can:
- COP a Message to a UDT

You can't:
- COP a UDT to a message
- MSG a UDT to a message
- MSG a message to a message
- MSG a message to a UDT

What I found out:
- messages don't actually sit in the Tag data table
- messages are really 1:1 references to instances of another CIP class

Which explains why one can't:
- make arrays of messages
- create a UDT with a message member
 

Similar Topics

hi , I need to sorry for my bad English first. I'm newbie at plc programming ,I had been asked about E/IP protocol information for some system...
Replies
3
Views
383
I have a question on a subject of etherent nodes in rslogix 5000 project tree for a project that I am working on. I am trying to read if read...
Replies
5
Views
4,685
I am trying to send an CIP MSG from a RSlogix 5000 to a 485/ethernetIp device. I have connected and got a response back giving me the vendor...
Replies
5
Views
2,994
AB Logix 5000 Controllers Compact Logix L24ER PLCs Can not use Produced / Consumed (due to network / bandwidth limitations) so this is not an...
Replies
2
Views
3,390
What do I need to do to pull the Date Datatype from an E&H Ph instrument using CIP Eth I/P ? I can pull strings and integers fine but there is no...
Replies
16
Views
6,679
Back
Top Bottom