//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
:imagesdir: ../../images/users/protocols
:icons: font

= EtherNet/IP

EtherNet/IP is Rockwell Automation's implementation of CIP (Common Industrial Protocol)
over standard Ethernet/TCP-IP. It is used by Allen-Bradley/Rockwell PLCs and by other CIP
devices that address data through symbolic tag names rather than fixed memory addresses.

This page covers the `eip` driver, which speaks generic CIP symbolic addressing. The same
Java tag class also backs the `logix` driver code, registered by the same module - see
xref:protocols/logix.adoc[Logix] for that protocol's page.

== Supported Operations

[cols="2,2a,5a"]
|===
|Name |Value |Description

|
| `read`
| Go and Java. Reads one or more tags, or a selection of an array tag.

|
| `write`
| Go and Java. Writes one or more tags, or a selection of an array tag.

|
| `subscribe`
| Java only, polling-emulated. EtherNet/IP has no push mechanism here, so a
subscription is a periodic read underneath, not a device-initiated notification.

|
| `discover`
| Go and Java. Discovers devices on the network. This is the discovery API, not
`browse`: the driver has no tag-browsing support.

|===

== Connection String

The EtherNet/IP connection string has the following format:
----
eip://{ip-address}:{port}?{options}
----
`tcp` is the only supported transport and is the default, so it is omitted from the
connection string. The port defaults to `44818` and normally does not need to be given:
----
eip://192.168.24.32
----

== Connection String Options

include::partial$eip.adoc[]

== Tag Addresses

Addressing is implemented in Go and Java. See the
xref:protocols/index.adoc[protocol support matrix] for what each implementation does.

=== General Format

To read and write data to a PLC4X device, the EtherNet/IP driver uses symbolic segments.
This is used to refer to objects through their symbolic names. This makes reading data a
lot easier, as you do not need to specify the Datatype for reading.

----
{tagname}
{tagname}:{DataType}
{tagname}[{selection}]
{tagname}[{selection}]:{DataType}
----

[cols="2" ,options="header"]
|===
|Name |Description
|Tagname |symbolic name of the data. May optionally be prefixed with `%`.
|Selection (optional)|which elements of an array to read - a single index or an inclusive range. It follows the tag name, before the data type. See xref:array-notation.adoc[Addressing arrays].
|DataType (optional)|the data type of the value. Defaults to `DINT` when omitted, so for anything that is not a 32-bit integer it should be given explicitly - also when reading.
|===

NOTE: The selection comes *before* the data type, and a range says how many elements are read.
Reading four DINTs starting at index 0 is `myArray[0..3]:DINT`.

NOTE: A CIP array index travels in a `MemberID`, whose instance field is a `uint 8`, so a
selection cannot start past index 255. A range may run beyond it - the request carries a
start and a count - but it cannot begin there.

CAUTION: The Java driver's tag name does not require a leading `%` - `rate:DINT` parses in
Java. The Go driver's address pattern requires the tag name to start with `%`, so the same
address is rejected there. This page documents the Java syntax; consult the Go driver's own
source for what it accepts.

=== Data Types

These are the data types the driver can encode and decode:

[cols="2" ,options="header"]
|===
|To store a|Use this data type
|Bit|BOOL
|8-bit bit string|BYTE
|16-bit bit string|WORD
|32-bit bit string|DWORD
|64-bit bit string|LWORD
|8-bit integer|SINT
|16-bit integer|INT
|32-bit integer|DINT
|64-bit integer|LINT
|8-bit unsigned integer|USINT
|16-bit unsigned integer|UINT
|32-bit unsigned integer|UDINT
|64-bit unsigned integer|ULINT
|32-bit float|REAL
|64-bit float|LREAL
|Character string|STRING
|===

NOTE: The unsigned and bit string types cover their full range, so a `UDINT` or `DWORD` is returned
in the range 0 to 4294967295 and a `ULINT` or `LWORD` in the range 0 to 18446744073709551615. Their
signed counterparts are unchanged: a `DINT` of `0xFFFFFFFF` still reads as -1.

NOTE: Other CIP data types are accepted by the address parser but are not encoded or decoded by the
driver; reading such a tag results in a response code of `INTERNAL_ERROR` rather than a value.

=== Examples

.Examples
[cols="2,3" ,options="header"]
|===
|Address |Meaning
|`myTag` |a single element of `myTag`, decoded as `DINT`
|`myTag:REAL` |a single element of `myTag`, decoded as `REAL`
|`myTag[0..3]` |four elements of `myTag`, decoded as `DINT`
|`myArray[3]:DINT` |element 3 of `myArray`
|`myArray[0..3]:DINT` |elements 0 to 3 of `myArray`, returned as a list
|`%myTag:REAL` |a single element of `myTag`, decoded as `REAL` - the `%` prefix is optional
|===
