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.5ControlLogix, CompactLogix, GuardLogix and Micro800. This driver is not a generic EtherNet/IP client.
Configuration
| Field | Description |
|---|---|
| Name | Connection identifier. |
| Host | Controller IP address. |
| Port | 44818. |
| Slot | Backplane slot of the CPU. 0 for a CompactLogix; the actual slot in a ControlLogix chassis. |
| Connect / request timeout | Socket and request deadlines. |
| Auto-reconnect | Re-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.
| Form | Meaning |
|---|---|
Counter | A scalar controller tag. |
MyArray[5] | One element of an array. |
Matrix[2,4] | One element of a multi-dimensional array. |
Recipe.Setpoint | A member of a structure or UDT. |
Recipe.Steps[3].Duration | A member inside an array of structures. |
Program:MainProgram.Step | A program-scoped tag. |
StatusWord.5 | A 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.
| Where | Setting |
|---|---|
| General → Data type | int32 |
| Binding → Protocol | Allen-Bradley (EtherNet/IP) |
| Binding → Address | PartsMade |
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].
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.
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
2ormaybeto aBOOLused 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
| Symptom | Cause |
|---|---|
| Connects, one tag always fails | The tag name does not exist, or is program-scoped and missing its Program: prefix. |
path destination unknown | Wrong slot, or the tag path does not resolve. |
| Connection refused | Wrong IP, or the controller's EtherNet/IP port is not reachable. |
| Reads work, writes refused | The tag is read-only, or the controller is in Run with the key switch protecting it. |
| Throughput lower than expected | The 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.