Skip to main content
Version: 1.0.8

Allen-Bradley (EtherNet/IP)

QUBIQ talks to Rockwell Logix controllers with EtherNet/IP and CIP (TCP port 44818). It reads and writes the controller's own symbolic tags — there is no byte offset to work out, because the controller knows its own tag names and types and QUBIQ asks it.

New in 1.0.5
Rockwell controllers only

ControlLogix, CompactLogix, GuardLogix and Micro800. This driver is not a generic EtherNet/IP client.

Configuration​

FieldDescription
NameConnection identifier.
HostController IP address.
Port44818.
SlotBackplane slot of the CPU. 0 for a CompactLogix; the actual slot in a ControlLogix chassis.
Connect / request timeoutSocket and request deadlines.
Auto-reconnectRe-establishes a dropped link with backoff. On by default.

A Logix controller has a finite number of connection slots shared with every other client on the plant — including the engineer's Studio 5000 session. QUBIQ opens one CIP session per configured connection and multiplexes every tag onto it.

Browsing the controller​

You do not have to know the tag names. Open the binding form and use Browse: QUBIQ reads the controller's symbol table — paginated, so a controller with thousands of tags is fine — along with UDT templates, and shows the tree with each tag's own data type.

Picking a tag from the browse fills in both the address and the tag's data type, taking the type from the controller rather than from whatever was in the form. A tag typed by hand and then browsed ends up correct.

Programs and UDTs open. 1.0.8 A program's tags and a structure's members are read when you expand them, and until 1.0.8 neither the browser nor the tag import drew an expander for them — so only controller-scoped tags could be reached at all. They now expand, and the folder you opened shows a spinner while it loads, rather than a Reading… line at the foot of the dialog.

The tag reference grammar​

The address is the tag reference, exactly as the controller knows it.

FormMeaning
CounterA scalar controller tag.
MyArray[5]One element of an array.
Matrix[2,4]One element of a multi-dimensional array.
Recipe.SetpointA member of a structure or UDT.
Recipe.Steps[3].DurationA member inside an array of structures.
Program:MainProgram.StepA program-scoped tag.
StatusWord.5A single bit of an integer tag.

Case is preserved as the controller has it. Program: scoping is one wire token, which is why a leading member may be longer than the 40 characters every other member is limited to.

Worked examples: a tag for each shape​

As with any binding: create the tag, set its data type on General, bind it on Binding. If you browse for the address, the data type is filled in for you.

A scalar​

A production count held in a controller-scoped DINT named PartsMade.

WhereSetting
General → Data typeint32
Binding → ProtocolAllen-Bradley (EtherNet/IP)
Binding → AddressPartsMade

A REAL named OvenTemp is the same with data type float.

A single array element​

Element 5 of a REAL[100] named Zone: address Zone[5], data type float.

Element [2,4] of a two-dimensional array: address Matrix[2,4].

Bind elements, not whole arrays

Each tag addresses one element. To trend eight zones, create eight tags — Zone[0] through Zone[7]. That keeps each tag's type, scaling, alarm and history independent, which is what you want the moment one zone needs a different range.

A UDT member​

A setpoint inside a UDT instance named Recipe: address Recipe.Setpoint, with the data type the controller declares for that member — browse and it is filled in.

Nested further: Recipe.Steps[3].Duration.

A program-scoped tag​

A tag that lives inside MainProgram rather than at controller scope: address Program:MainProgram.Step.

The Program: prefix is required — a program-scoped tag is not reachable by its bare name.

A single bit​

Bit 5 of an integer tag: address StatusWord.5, data type boolean.

A string​

A Logix STRING is a structure — a DINT length followed by a fixed character array. Address it by name, RecipeName, with data type string. QUBIQ handles the structure.

Writing​

Writes go through the same binding, and there is one trap this driver guards for you.

An EtherNet/IP write of the wrong width is not an error

It is a write of the wrong number of elements. The controller derives the count from the length of the value and the type it reported, so on an array reference a too-long value silently overwrites the next element.

A Logix STRING is the concrete case. It is a fixed-width structure, so writing only the encoded bytes sets the new length and leaves the tail of the previous, longer value in place: overwrite "SHUTDOWN" with "RUN" and it reads back "RUN" while still holding TDOWN.

QUBIQ probes the element size and fits every write to it, zero-padding a string to the full declared width. You do not have to do anything — but it is worth knowing why, because a driver that does not do this looks like it works.

That probe is re-learned on every reconnect. Changed in 1.0.6 A program download can change a tag's width without changing anything about the connection, so the learned size used to survive a download and reopen exactly the silent partial write the probe exists to close. The cached sizes are now tied to the session rather than to the configuration, and a reconnect discards them.

What happens to a setpoint while the driver is busy Changed in 1.0.6​

  • A write goes in front of queued polling. The driver talks to a controller one exchange at a time, and an operator's setpoint used to wait behind however many scheduled reads were queued. Nothing can interrupt an exchange already on the wire, but the wait is now bounded.
  • One unreachable controller no longer stalls writes to the others. Requests used to be handled in sequence across every connection, so a handler dialling a dead panel held up everybody else's write — and the caller was told worker unavailable about a worker that was perfectly healthy. Each request is now handled on its own.
  • A value whose meaning is not obvious is refused, not guessed. Writing 2 or maybe to a BOOL used to be a successful write of OFF — a wrong value that reports success, which is worse than a refusal because nobody goes looking for it.

An unreachable controller does not cost the others their sessions Changed in 1.0.7​

A controller drops a CIP connection that misses its keepalive, so the keepalive is a correctness setting rather than housekeeping. The driver used to ping every controller one after another: a single slow or unreachable controller spent the sweep waiting out socket timeouts, the controllers after it got their keepalive late, and their sessions were dropped. A network segment going down could take healthy controllers elsewhere offline with it.

Controllers are now pinged side by side, a bounded number at a time — in the case that pins it, thirty-two endpoints behind one hung controller went from 3.2 seconds to about 0.2. Changing one connection's configuration also no longer stalls the others while its poller winds down, and every kind of request to the worker — not only writes — is now handled per connection rather than in one queue.

Confirming an address before you bind it​

The binding form has a Read now button beside the address. It reads that one tag on the session the driver already holds and shows the decoded value together with the raw bytes.

The bytes are the useful half when a value looks wrong: a type mismatch is obvious in hex and invisible in the number. A read that succeeds with a decode that fails means the address is right and the declared type is wrong.

Diagnostics​

SymptomCause
Connects, one tag always failsThe tag name does not exist, or is program-scoped and missing its Program: prefix.
path destination unknownWrong slot, or the tag path does not resolve.
Connection refusedWrong IP, or the controller's EtherNet/IP port is not reachable.
Reads work, writes refusedThe tag is read-only, or the controller is in Run with the key switch protecting it.
Throughput lower than expectedThe controller refused a Class 3 connection and the driver fell back to unconnected messaging — roughly eight times less payload per packet. It is logged when it happens.

A CIP error concerns only the tag that caused it. The session stays up and every other tag keeps updating.