//
//  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

= IEC-60870

IEC 60870-5-104 is a telecontrol protocol used to monitor and control geographically
distributed process equipment - substations, RTUs and similar equipment in electric
power systems. It runs over TCP/IP, typically on the well-known port `2404`.

The protocol is push driven: once a session is established, the remote station (RTU)
sends unsolicited application service data units (ASDUs) for the information objects it
holds. There is nothing for a client to actively read or write - it only subscribes and
receives what the station reports.

== Supported Operations

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

|
| `subscribe`
| Go and Java. The only supported operation. A subscription's tag address selects which
information objects of which station(s) are delivered to it; the station itself decides
what and when to send.
|===

IMPORTANT: Reading, writing and browsing are not implemented and a request for any of
them is rejected.

== Connection String

IEC 60870-5-104 has the following connection string format:
----
iec-60870-5-104:tcp://{ip-address}:{port}?{options}
----
The only supported transport is `tcp`, defaulting to port `2404`:
----
iec-60870-5-104:tcp://192.168.178.101:2404
----

== Connection String Options

include::partial$iec-60870-5-104.adoc[]

== Tag Addresses

Addressing is implemented in Go and Java. The protocol is push driven, so tags are used
with subscriptions only. See the xref:protocols/index.adoc[protocol support matrix] for
what each implementation does.

=== General Format

A tag address names one information object of one station and is written as `<asdu>/<ioa>`:

* `<asdu>` is the 2 octet *common address of ASDU* (the station address). Write it either as one
  decimal number `0..65535` or octet by octet as `<low>/<high>`, each `0..255`.
* `<ioa>` is the 3 octet *information object address*. Write it either as one decimal number
  `0..16777215` or octet by octet as `<low>.<middle>.<high>`, each `0..255`.

[WARNING]
====
The octet-wise forms are written *least significant octet first*, the order the octets appear in on
the wire. So `1/2` as an ASDU address means `1 + 2 * 256 = 513`, not 258.

This is the *opposite* order of the identically shaped `a/b/c` address of the KNX driver, where the
most significant part (main group) comes first. A KNX-style reading of an IEC-60870 address is
silently a valid address of a different station, so double-check the order when porting addresses or
copying examples between the two drivers.
====

A `+*+` may take the place of any number and makes that position a wildcard, so that one subscription
can cover a whole station, a whole octet range, or everything the connection reports.

Surrounding whitespace is trimmed and leading zeros are accepted, up to the number of digits the
maximum of that component has (3 for an octet, 5 for a whole ASDU address, 8 for a whole information
object address). So `007/002.03.004` is accepted while `000007/2` is not. Whitespace *inside* an
address is not accepted.

Every incoming information object is matched against the address of each subscription and only
delivered to the subscriptions that cover it - the station itself reports everything it has, the
filtering happens in the driver.

[IMPORTANT]
====
Malformed and out-of-range addresses are rejected when the request is built, with a
`PlcInvalidTagException`.

Earlier versions of this driver ignored the address entirely: any string was accepted and every
subscription received every incoming ASDU, leaving the filtering to the consumer. Existing code
therefore needs its addresses reviewed - in particular a bare `+*+` is no longer an address, the
"everything" address is `+*/*+` - and consumer-side filtering can now be dropped.
====

=== Data Types

A tag address carries no type information: the datatype of an information object follows from the
type identification of the ASDU that delivers it, which is only known at runtime, not from the
address itself.

Both drivers attach the information object's *quality descriptor* to the delivered value as
metadata alongside it, rather than silently folding it into the value: `invalid`, `notTopical`,
`substituted`, `blocked` and, where the ASDU carries it, `overflow`. A reading the station marked
invalid, blocked, substituted or not topical therefore does not arrive looking like a good one -
check this metadata before trusting a value.

=== Examples

.Examples
[cols="1,3"]
|===
| Address | Meaning

| `1/2`            | ASDU 1, information object 2
| `65535/16777215` | the widest address both fields can carry
| `1/2/3`          | ASDU 513 (low octet 1, high octet 2), information object 3
| `1/2.3.4`        | ASDU 1, information object 262914 (low 2, middle 3, high 4)
| `1/2/3.4.5`      | ASDU 513, information object 328707
| `+*/*+`            | every information object of every station
| `+1/*+`            | every information object of ASDU 1
| `+*/3.4.5+`        | information object 328707 of every station
| `+1/2/3.*.5+`      | low and high octet pinned, middle octet wildcarded
|===
