Logix Driver vs EthIP Driver Array of BOOLs

Was using pturmel's Ethernet/IP V2 module to import L5X files to build tag paths from fake host devices and came across this anomaly (?) - difference in OPC tag paths.

I have an array of BOOL values in the PLC at the address


Trying to access these tags with paths like so


results in a configuration error The node id refers to a node that does not exist in the server address space.

Using the OPC browser it looks like the driver expects a path like so


The path I originally generated was through the OPC browser using your Ethernet/IP module as a host simulator. Not sure if that matters.

Maybe not a bug because the tag is obviously published at that OPC address, but just something to be aware of

It matters. Real Logix doesn't have true BOOL arrays. Under the hood, they are all arrays of DWORD, each holding 32 of the bools.

My driver does support real boolean arrays (partly because Omron has them), so if it looks that way in my host driver, it won't be right for Logix.

This topic recently came up in the office when a colleague mentioned that a bool takes up as much memory as an integer, which in Logix can be used as multiple bools.

As much memory as DINT to be specific. In UDTs, the order of tags/data types can add to the memory as each BOOL that's not contiguous is another DINT.

Edit, DINT = 4 bytes, so each non-contiguous BOOL will eat another 4 bytes.

In Logix? No, not exactly.

In a UDT, BOOLs are assembled from SINTs, and the SINTs are marked as Hidden. Consecutive BOOLs are packed into SINTs. Those underlying SINTs pack in with other data types as normal. (My EtherNet/IP user manual has a detailed description of that.)

In an AOI definition, BOOLs are consolidated into 32-bit DWORD types, with the first 32 BOOLs in the DWORD at the beginning of the data type. The booleans do not have to be consecutive parameters or locals to be packed together.

The EtherNet/IP specification calls out BYTE, WORD, DWORD, and LWORD as "bit string" data types that are distinct from the signed SINT, INT, DINT, and LINT, and unsigned USINT, UINT, UDINT, and ULINT data types of the same sizes. My driver treats them like the unsigned variants.

1 Like

Yes, Phil in Logix... for UDTs. Look at the screenshots for the byte sizes.






That's because DINTs have to be 32-bit aligned, and the entire data type has to be a multiple of 32 bits, so DINT2 after BOOL2 causes three SINTs to be wasted on padding. Try DINT, then BOOL, then SINT, then INT. Will fit in 8 bytes.

As I said, described in my user manual.

If you wish to always minimize data type sizes, the simplest strategy is to group all members that have the same natural alignment together, and then order the groups by descending alignment size. LREAL, LINT, ULINT, and LWORD first, then REAL, DINT, UDINT, DWORD, then INT, UINT, and WORD, then SINT, USINT, and BYTE, with all of the BOOLs last. Natural alignment of any primitive type is its bit size.

For nested elements (in modern Logix):

  • Arrays and UDTs and AOI types containing any 64-bit types are aligned to 64 bits and padded to 64 bits.

  • Other arrays (of any type) and UDTs and AOI types not containing any 64-bit types are aligned to 32 bits and padded to 32 bits.

Phil, what I said in my post was correct. I'm not suggesting what you said isn't. I'll leave it at that.

1 Like

This is the conclusion we came to. It's more efficient to use a datatype that is compromised of bools than to add individual bools to the UDT.

That said, we weren't creating policy. It was just water cooler talk.

Unless you keep them together. Then they pack nicely.

1 Like

That makes sense. I believe the idea was that if you only need small number of bools or one bool, you might as well add whatever datatype fills up the space because it's consumed either way. During the discussion, I argued for keeping it simple, but I also reminisced about my early programming days [on a Commodore 128 and a 486] when such considerations were unavoidable. I had to commend my colleague, who still does retro stuff, for being so considerate.

When the bools reflect something that naturally has a name, like a state in a state machine, I almost always use a named boolean in a UDT. So that later re-arrangement and/or re-ordering of multiple states/conditions doesn't break the actual rung logic.

Me too. If need something like trap logic for diagnostic purposes, that's when I usually find myself throwing an integer into the controller for use as bools. test.0, test.1, ...