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

== About PLC4Go

`PLC4Go` is a sub-project of `PLC4X` with implementations based on `Go`.

One of PLC4X's core principals is, that an application using PLC4X should be independent of the PLC or protocol being used.

When addressing a resource on a remote there are two parts that are dependent on the protocol and the type of PLC:

- Addressing the PLC itself
- Addressing a resource on the PLC

Providing this independence to addressing the PLC itself is completely handled by the `PlcDriverManager` the application requests a connection from.

Hereby the design of the `url string` passed to the `getConnection` method is greatly inspired by `JDBC`.

The protocol prefix of the url specifies the type of driver being used.

For example, when connecting to a Siemens PLC using the S7/Step7 Protocol, the url: `s7://192.42.0.98/1/2` causes the driver manager to create a S7 connection instance.
The part behind the `:` is hereby used by the driver implementation to configure that particular connection.

For a S7 connection, for example, this is `IP address/host name`/`rack number`/`slot number`. For different types of connections this url structure will greatly differ.

As mentioned above, the second platform dependent information is the address of resources on a PLC.
The format of an address greatly depends on the type of connection. Therefore `parseAddress` is one of the only methods defined in the `PlcConnection` interface any connection has to implement.

This method returns an object implementing the `Address` interface which then can be used by the same connection to identify remote resources.

[ditaa,plc4x-architecture]
....
+----------------------------------------------------------------------------------------------+
|c05A                                                                                          |
|                                                                                              |
|                              User Application                                                |
|                                                                                              |
|                                                                                              |
|                  +-----------+------------------+------------------+------------------+------+
|                  |           |                  |                  |                  |
|                  |           |                  |                  |                  |
|                  |           v                  v                  v                  v
|                  |    +-------------+    +-------------+    +-------------+    +-------------+
|                  |    |c0BA         |    |c0BA         |    |c0BA         |    |c0BA         |
|                  |    |   Apache    |    |   Apache    |    |   Apache    |    |   Apache    |
|                  |    |   Kafka     |    |    Camel    |    |   Edgent    |    |    Nifi     |
|                  |    |   Connect   |    | Integration |    | Integration |    | Integration |
|                  |    |             |    |             |    |             |    |             |
+---------+--------+    +------+------+    +------+------+    +------+------+    +------+------+
          |                    |                  |                  |                  |
          |                    |                  |                  |                  |
          v                    v                  v                  v                  v
+----------------------------------------------------------------------------------------------+
|cAAA                                                                                          |
|                                                                                              |
|                                             PLC4X API                                        |
|                                                                                              |
|                                                                                              |
+------+---------------+---------------+---------------+---------------+---------------+-------+
       |               |               |               |               |               |
       |               |               |               |               |               |
       v               v               v               v               v               v
 +-----------+   +-----------+   +-----------+   +-----------+   +-----------+   +-----------+
 |c0BA       |   |c0BA       |   |c0BA       |   |c0BA       |   |c0BA       |   |c05A       |
 |  Siemens  |   | Beckhoff  |   |  Modbus   |   |  OPC UA   |   |  Emerson  |   |   User    |
 |    S7     |   |   ADS     |   |  Driver   |   |  Driver   |   |  DeltaV   |   |  Driver   |
 |  Driver   |   |  Driver   |   |           |   |           |   |  Driver   |   |           |
 |           |   |           |   |           |   |           |   |           |   |           |
 +-----------+   +-----------+   +-----------+   +-----------+   +-----------+   +-----------+
....

=== Usage

Below code example connects to a remote Siemens S7 PLC using the S7/Step7 protocol and then reads the state of the `inputs` and `outputs` from this.

[source,go]
----
func HellpPlc4go() {
	driverManager := plc4go.NewPlcDriverManager()
	driverManager.RegisterDriver(modbus.NewModbusDriver())
	driverManager.RegisterTransport(tcp.NewTcpTransport())

	// Get a connection to a remote PLC
	crc := driverManager.GetConnection("modbus://192.168.23.30")

	// Wait for the driver to connect (or not)
	connectionResult := <-crc
	if connectionResult.Err != nil {
		t.Errorf("error connecting to PLC: %s", connectionResult.Err.Error())
		return
	}
	connection := connectionResult.Connection

	// Try to ping the remote device (This block is just optional)
	pingResultChannel := connection.Ping()
	pingResult := <-pingResultChannel
	if pingResult.Err != nil {
		t.Errorf("couldn't ping device: %s", pingResult.Err.Error())
		return
	}

	// Make sure the connection is closed at the end
	defer connection.Close()

	// Prepare a read-request
	rrb := connection.ReadRequestBuilder()
	rrb.AddItem("field1", "holding-register:1:REAL")
	rrb.AddItem("field2", "holding-register:3:REAL")
	readRequest, err := rrb.Build()
	if err != nil {
		t.Errorf("error preparing read-request: %s", connectionResult.Err.Error())
		return
	}

	// Execute a read-request
	rrc := readRequest.Execute()

	// Wait for the response to finish
	rrr := <-rrc
	if rrr.Err != nil {
		t.Errorf("error executing read-request: %s", rrr.Err.Error())
		return
	}

	// Do something with the response
	value := rrr.Response.GetValue("field")

	// Do something sensible with the information
	fmt.Printf("\n\nResult: %f\n", value)
}
----

