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

= General Concepts



On this page we'll give a short introduction to the most important concepts that will help you understand Apache PLC4X better.

The most important concepts from a user perspective are in general:

- Connections
-- protocols
-- transports
-- configuration
- Addresses

The two parts where we have built abstractions from the real world in PLC4X API are the `connection strings` and the `tag address strings`.

Both are pretty dependent on the type of device you are planning to communicate with. However, these can both be easily configured in an external configuration or passed in as arguments.

If you are familiar with `JDBC` or `ODBC`, you will easily understand the concepts in PLC4X, as these were a great inspiration for the creation of Apache PLC4X.

== Connections

In general a connection is a physical or logical connection between two endpoints.

This connection uses a technical transport mechanism and passes data following a given protocol logic.
Therefore, we have modeled both of these aspects separately.

Let's start with the `Transports`:

The following transports are currently available, but they will probably be more soon:

- CAN
- PCAP replay
- Raw Socket
- Serial Port (RS232 and RS485)
- TCP
- UDP
- Test

While TCP, UDP are based on the normal TCP and UDP stack of the operating system, Raw sockets directly provide low-level access to `Ethernet Frames`.
This allows them to not only be used in what we call `passive-mode drivers` for simply reading all network traffic, it also allows communicating with protocols that are Ethernet based, but don't use TCP or UDP. This is usually the case with `Fieldbus` protocols, such as `PROFINET` or `EtherCAT`, which usually require lower latency than TCP and UDP can provide.

The Serial Port transport simply reads and writes data to a given serial port.

The probably most special forms of transport are currently the `PCAP replay` and the `Test` transport.

The `PCAP replay` transport allows playing back network traffic packets that were recorded using tools like `WireShark`. This is really helpful for writing new drivers (especially passive mode drivers) without having to be connected to the real device.

From a driver point of view there is actually no difference between a `Raw Socket` and a `PCAP replay` transport.

The `Test` transport is generally built for being used inside the PLC4X test framework as it allows fine-grained access to the input and output of the drivers. With the test transport we can explicitly control which data is passed into and retrieved from drivers and to validate this in unit- and integration-tests.

=== Connection Strings

A fully qualified PLC4X connection string would look like this:

----
{driver code}:{transport code}://{transport config}?{options}
----

The `driver code` generally selects the protocol we want to use, the `transport code` now selects the type of transport that should be used.

Depending on the selected transport mechanism the `transport config` tells the transport which resource it should use.

For example with a `TCP` and `UDP` transport, this will be the `IP address` or `hostname` optionally followed by the `Port`.

For a `Serial` transport this will be the `name of the serial interface`. `Raw Sockets` will require the `device name` or a `MAC address` and so on.

For a full description of all transports and their options, please consult the `Transport Documentation` xref:transports/index.adoc[here].

The last segment - `options` - can be used to fine tune some protocol or transport options to non-default values. Usually these vary quite a bit from protocol to protocol. For details on these options, please have a look at the `Protocol Documentation` xref:protocols/index.adoc[here]. Even if most transports also have common options, their defaults vary quite a bit, depending on the protocol being used. So, instead of having a look at the general `Transport Documentation` xref:transports/index.adoc[here], wach protocol documentation also contains a list of all supported transports as well as the transport configuration options and their defaults.

The general structure of this part is always the same:

----
?{option-1-name}={option-1-value}&{option-2-name}={option-2-value}&{option-3-name}={option-3-value}
----

So the options start with a `?` and are then followed by `name-value` pairs, which are separated by ampersand characters `&`.

A driver for a given protocol however usually has a `default transport`, so sometimes it is possible to omit the transport code. Also do most drivers define default values for the various configuration options, so in general you should only require to use configuration options, if you are using non-default settings.

The shortest version of a fully qualified connection string would look something like this:

----
{driver code}://{transport config}
----

For more information on the default settings for a given protocol or transport, please check the corresponding drivers documentation.

== Individual Resource Addresses (Tags)

Addresses for individual tags on a PLC are extremely dependent on the used protocol.
As we usually decided to stick to the address formats that are used in those particular environments, please check the `Protocol Documentation` on details about these address formats xref:protocols/index.adoc[here].

The tag syntax is fairly generic and can be summarized as `type:address`.
Some protocols might support tag attributes which are specified as key-value pairs after primary tag address.
For example `coil:1{unit-id: 10}`.
Tag attributes are additional elements which depend on actual protocol.

== Tag metadata

Starting from Apache PLC4X release 0.13 an experimental support for result set metadata is provided in plc4j.
This metadata is dedicated to provide additional information which might be available at protocol (sample timestamp) or driver level (i.e. packet receive time).
Consult again protocol documentation on specifics of this feature.

The common metadata keys currently defined are:

* timestamp - timestamp for tag value provided by other communication party.
* timestamp_source - source of timestamp or receive_timestamp field, if any of these is provided.
* receive_timestamp - timestamp assumed upon receiving of packet with data.



== Limits on Incoming Messages

A driver reads what the device sends it, and some protocols let a value contain further values of
its own kind - BACnet constructed data holds further constructed data, an OPC UA variant can hold
further variants, an ADS data type table entry can hold further entries.
How deeply such a message nests is decided by whoever sent it, and one level of nesting can cost as
little as a single byte on the wire.

PLC4X therefore reads at most 1024 levels deep and reports anything beyond that as a parse error,
in the same way it reports any other message it cannot make sense of.
The deepest message in the project's own test suites nests 36 levels, so this is far past anything
a real device is expected to send.

Should you meet a device whose messages genuinely nest deeper, set the `PLC4X_MAX_NESTING_DEPTH`
environment variable to the depth you need:

[source,shell]
----
export PLC4X_MAX_NESTING_DEPTH=4096
----

The variable means the same thing in every language binding, so a process talking to devices
through more than one of them needs to set it only once.
A value that is not a positive number is ignored, leaving the default in place, and says so in the
log.

Raise it to what the device actually needs rather than to a round number well above it.
The limit exists because the alternative to reporting a parse error is running out of stack, and
what that costs differs: plc4j and plc4py raise an error the driver can still report, while in
plc4go and plc4c an exhausted stack ends the process rather than the message.
