You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by hu...@apache.org on 2022/10/06 15:23:51 UTC
[plc4x] 06/13: fix(plc4j(profinet): Finished the connection setup.
This is an automated email from the ASF dual-hosted git repository.
hutcheb pushed a commit to branch plc4j/profinet
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit d133842cef1e39ece146eab300435b6edfe94987
Author: Ben Hutcheson <be...@gmail.com>
AuthorDate: Fri Sep 9 11:20:59 2022 -0600
fix(plc4j(profinet): Finished the connection setup.
---
.../profinet/discovery/ProfinetPlcDiscoverer.java | 144 +++++++++++++++++----
.../profinet/protocol/ProfinetProtocolLogic.java | 51 +++++++-
.../profinet/readwrite/utils/StaticHelper.java | 33 +++++
.../resources/protocols/profinet/profinet.mspec | 58 ++++++---
4 files changed, 243 insertions(+), 43 deletions(-)
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
index 96b2dba67..35681f795 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
@@ -18,6 +18,8 @@
*/
package org.apache.plc4x.java.profinet.discovery;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
import org.apache.plc4x.java.api.exceptions.PlcException;
import org.apache.plc4x.java.api.messages.PlcDiscoveryItem;
import org.apache.plc4x.java.api.messages.PlcDiscoveryItemHandler;
@@ -47,6 +49,8 @@ import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
public class ProfinetPlcDiscoverer implements PlcDiscoverer {
@@ -56,6 +60,8 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
// The constants for the different block names and their actual meaning.
private static final String DEVICE_TYPE_NAME = "DEVICE_PROPERTIES_OPTION-1";
private static final String DEVICE_NAME_OF_STATION = "DEVICE_PROPERTIES_OPTION-2";
+ private static final String PLC4X_LLDP_IDENTIFIER = "PLC4X PROFINET Controller Client";
+ private static final String PLC4X_LLDP_PORT = "port001.plc4x";
private static final String DEVICE_ID = "DEVICE_PROPERTIES_OPTION-3";
private static final String DEVICE_ROLE = "DEVICE_PROPERTIES_OPTION-4";
private static final String DEVICE_OPTIONS = "DEVICE_PROPERTIES_OPTION-5";
@@ -327,14 +333,14 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
ReadBuffer reader = new ReadBufferByteBased(ethernetPacket.getRawData());
try {
Ethernet_Frame ethernetFrame = Ethernet_Frame.staticParse(reader);
- PnDcp_Pdu pdu;
+ Lldp_Pdu pdu;
// Access the pdu data (either directly or by
// unpacking the content of the VLAN packet.
if (ethernetFrame.getPayload() instanceof Ethernet_FramePayload_VirtualLan) {
Ethernet_FramePayload_VirtualLan vlefpl = (Ethernet_FramePayload_VirtualLan) ethernetFrame.getPayload();
- pdu = ((Ethernet_FramePayload_PnDcp) vlefpl.getPayload()).getPdu();
+ pdu = ((Ethernet_FramePayload_LLDP) vlefpl.getPayload()).getPdu();
} else {
- pdu = ((Ethernet_FramePayload_PnDcp) ethernetFrame.getPayload()).getPdu();
+ pdu = ((Ethernet_FramePayload_LLDP) ethernetFrame.getPayload()).getPdu();
}
// Inspect the PDU itself
// (in this case we only process identify response packets)
@@ -351,28 +357,102 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
Task t = new Task(handle, listener);
pool.execute(t);
- // Construct and send the LLDP Probe
+ Function<Object, Boolean> lldpTimer =
+ message -> {
+ // Construct and send the LLDP Probe
+ TlvOrgSpecificProfibus portStatus = new TlvOrgSpecificProfibus(
+ new TlvProfibusSubTypePortStatus(0x00)
+ );
+
+ TlvOrgSpecificProfibus chassisMac = new TlvOrgSpecificProfibus(
+ new TlvProfibusSubTypeChassisMac(new MacAddress(linkLayerAddress.getAddress()))
+ );
+
+ TlvOrgSpecificIeee8023 ieee = new TlvOrgSpecificIeee8023(
+ (short) 0x01,
+ (short) 0x03,
+ 0x0020,
+ 0x0010
+ );
+
+ Ethernet_Frame identificationRequest = null;
+ try {
+ identificationRequest = new Ethernet_Frame(
+ // Pre-Defined LLDP discovery MAC address
+ new MacAddress(new byte[]{0x01, (byte) 0x80, (byte) 0xc2, 0x00, 0x00, 0x0e}),
+ toPlc4xMacAddress(macAddress),
+ new Ethernet_FramePayload_LLDP(
+ new Lldp_Pdu(
+ Arrays.asList(
+ new TlvChassisId(
+ PLC4X_LLDP_IDENTIFIER.length() + 1,
+ (short) 7,
+ PLC4X_LLDP_IDENTIFIER
+ ),
+ new TlvPortId(
+ PLC4X_LLDP_PORT.length() + 1,
+ (short) 7,
+ PLC4X_LLDP_PORT
+ ),
+ new TlvTimeToLive(2, 20),
+ new TlvOrganizationSpecific(
+ portStatus.getLengthInBytes(),
+ portStatus
+ ),
+ new TlvOrganizationSpecific(
+ chassisMac.getLengthInBytes(),
+ chassisMac
+ ),
+ new TlvOrganizationSpecific(
+ ieee.getLengthInBytes(),
+ ieee
+ ),
+ new TlvManagementAddress(
+ 12,
+ ManagementAddressSubType.IPV4,
+ new IpAddress(Hex.decodeHex("c0a8006e")),
+ (short) 0x03,
+ 0x01L,
+ (short) 0x00
+ ),
+ new EndOfLldp(0)
+ )
+ )));
+ } catch (DecoderException e) {
+ throw new RuntimeException(e);
+ }
+ WriteBufferByteBased buffer = new WriteBufferByteBased(identificationRequest.getLengthInBytes());
+ try {
+ identificationRequest.serialize(buffer);
+ } catch (SerializationException e) {
+ throw new RuntimeException(e);
+ }
+ Packet packet = null;
+ try {
+ packet = EthernetPacket.newPacket(buffer.getData(), 0, identificationRequest.getLengthInBytes());
+ } catch (IllegalRawDataException e) {
+ throw new RuntimeException(e);
+ }
+ try {
+ handle.sendPacket(packet);
+ } catch (PcapNativeException e) {
+ throw new RuntimeException(e);
+ } catch (NotOpenException e) {
+ throw new RuntimeException(e);
+ }
+ return null;
+ };
+ Timer timer = new Timer();
- Ethernet_Frame identificationRequest = new Ethernet_Frame(
- // Pre-Defined PROFINET discovery MAC address
- new MacAddress(new byte[]{0x01, 0x0E, (byte) 0xCF, 0x00, 0x00, 0x00}),
- toPlc4xMacAddress(macAddress),
- new Ethernet_FramePayload_VirtualLan(VirtualLanPriority.BEST_EFFORT, false, 0,
- new Ethernet_FramePayload_PnDcp(
- new PnDcp_Pdu_IdentifyReq(PnDcp_FrameId.DCP_Identify_ReqPDU.getValue(),
- 1,
- 256,
- Collections.singletonList(
- new PnDcp_Block_ALLSelector()
- )))));
- WriteBufferByteBased buffer = new WriteBufferByteBased(34);
- identificationRequest.serialize(buffer);
- Packet packet = EthernetPacket.newPacket(buffer.getData(), 0, 34);
- handle.sendPacket(packet);
+ // Schedule to run after every 3 second(3000 millisecond)
+ timer.scheduleAtFixedRate(
+ new LLDPTask(handle, lldpTimer),
+ 3000,
+ 3000);
}
}
}
- } catch (IllegalRawDataException | NotOpenException | PcapNativeException | SerializationException e) {
+ } catch (NotOpenException | PcapNativeException e) {
logger.error("Got an exception while processing raw socket data", e);
for (PcapHandle openHandle : openHandles) {
@@ -411,10 +491,28 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
}
}
+ private static class LLDPTask extends TimerTask {
+
+ private final Logger logger = LoggerFactory.getLogger(Task.class);
+
+ private final PcapHandle handle;
+ private final Function<Object, Boolean> operator;
+
+ public LLDPTask(PcapHandle handle, Function<Object, Boolean> operator) {
+ this.handle = handle;
+ this.operator = operator;
+ }
+
+ @Override
+ public void run() {
+ operator.apply(null);
+ }
+ }
+
public static void main(String[] args) throws Exception {
ProfinetPlcDiscoverer discoverer = new ProfinetPlcDiscoverer();
- discoverer.discover(null);
-
+ //discoverer.discover(null);
+ discoverer.lldpProbe();
Thread.sleep(10000);
}
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
index 8e4e666ab..d3c1d1024 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java
@@ -184,6 +184,31 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
udpSocket.send(connectRequestPacket);
+ // Receive the response.
+ resultBuffer = new byte[profinetAdvancedConnectionWriteRequest.getLengthInBytes()];
+ connectResponsePacket = new DatagramPacket(resultBuffer, resultBuffer.length);
+ udpSocket.receive(connectResponsePacket);
+
+
+ // Create the packet
+ final DceRpc_Packet profinetAdvancedConnectionParameterEnd = createProfinetAdvancedConnectionParameterEnd();
+ // Serialize it to a byte-payload
+ writeBuffer = new WriteBufferByteBased(profinetAdvancedConnectionParameterEnd.getLengthInBytes());
+ profinetAdvancedConnectionParameterEnd.serialize(writeBuffer);
+ // Create a udp packet.
+ connectRequestPacket = new DatagramPacket(writeBuffer.getData(), writeBuffer.getData().length);
+ connectRequestPacket.setAddress(remoteAddress.getAddress());
+ connectRequestPacket.setPort(remoteAddress.getPort());
+ // Send it.
+
+ udpSocket.send(connectRequestPacket);
+
+ // Receive the response.
+ resultBuffer = new byte[profinetAdvancedConnectionParameterEnd.getLengthInBytes()];
+ connectResponsePacket = new DatagramPacket(resultBuffer, resultBuffer.length);
+ udpSocket.receive(connectResponsePacket);
+
+
} catch (SerializationException | IOException | PlcException | ParseException e) {
logger.error("Error", e);
}
@@ -255,7 +280,7 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
// This actually needs to be set to this value and not the real port number.
0x8892,
// It seems that it must be set to this value, or it won't work.
- "controller"),
+ "plc4x"),
new PnIoCm_Block_IoCrReq((short) 1, (short) 0, PnIoCm_IoCrType.INPUT_CR,
0x0001,
0x8892,
@@ -383,13 +408,35 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
(short) 1,
(short) 0,
new PascalString("port-001"),
- new PascalString("controller")
+ new PascalString("plc4x")
)
)
))
);
}
+ private DceRpc_Packet createProfinetAdvancedConnectionParameterEnd() throws PlcException {
+
+ return new DceRpc_Packet(
+ DceRpc_PacketType.REQUEST, true, false, false,
+ IntegerEncoding.BIG_ENDIAN, CharacterEncoding.ASCII, FloatingPointEncoding.IEEE,
+ new DceRpc_ObjectUuid((byte) 0x00, 0x0001, 0x0904, 0x002A),
+ new DceRpc_InterfaceUuid_DeviceInterface(),
+ profinetDriverContext.getDceRpcActivityUuid(),
+ 0, 1, DceRpc_Operation.CONTROL,
+ new PnIoCm_Packet_Req(16696, 16696, 0, 244,
+ Arrays.asList(
+ new PnIoCm_Control_Request(
+ (short) 1,
+ (short) 0,
+ ARUUID,
+ 0x0001,
+ 0x0001
+ )
+ ))
+ );
+ }
+
protected static DceRpc_ActivityUuid generateActivityUuid() {
UUID number = UUID.randomUUID();
try {
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/readwrite/utils/StaticHelper.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/readwrite/utils/StaticHelper.java
index 97678c957..7331df69b 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/readwrite/utils/StaticHelper.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/readwrite/utils/StaticHelper.java
@@ -19,7 +19,11 @@
package org.apache.plc4x.java.profinet.readwrite.utils;
import org.apache.plc4x.java.profinet.readwrite.IpAddress;
+import org.apache.plc4x.java.profinet.readwrite.LldpUnit;
import org.apache.plc4x.java.profinet.readwrite.PnDcp_FrameId;
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.List;
public class StaticHelper {
@@ -153,4 +157,33 @@ public class StaticHelper {
return PnDcp_FrameId.RESERVED;
}
+ public static boolean isSysexEnd(ReadBuffer io) {
+ byte[] test = ((ReadBufferByteBased) io).getBytes(io.getPos(), io.getPos() + 2);
+ return ((ReadBufferByteBased) io).getBytes(io.getPos(), io.getPos() + 2)[0] == (byte) 0x00;
+ }
+
+ public static LldpUnit parseSysexString(ReadBuffer io) {
+ try {
+ LldpUnit unit = LldpUnit.staticParse(io);
+ return unit;
+ } catch (ParseException e) {
+ return null;
+ }
+ }
+
+ public static void serializeSysexString(WriteBuffer io, LldpUnit unit) {
+ try {
+ unit.serialize(io);
+ } catch (SerializationException e) {
+ }
+ }
+
+ public static int lengthSysexString(List<LldpUnit> data) {
+ int lengthInBytes = 0;
+ for (LldpUnit unit : data) {
+ lengthInBytes += unit.getLengthInBytes();
+ }
+ return lengthInBytes;
+ }
+
}
diff --git a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
index 19dcdcfee..57f3ced3a 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
@@ -83,34 +83,34 @@
[simple PnDcp_Pdu pdu ]
]
['0x88cc' Ethernet_FramePayload_LLDP
- [simple Lldp_Pdu pdu ]
+ [simple Lldp_Pdu pdu ]
]
]
]
[type Lldp_Pdu
- [array LldpUnit lldpParameters]
+ [manualArray LldpUnit lldpParameters terminated 'STATIC_CALL("isSysexEnd", readBuffer)' 'STATIC_CALL("parseSysexString", readBuffer)' 'STATIC_CALL("serializeSysexString", writeBuffer, _value)' 'STATIC_CALL("lengthSysexString", lldpParameters)']
]
[discriminatedType LldpUnit
- [disciminator uint 7 tlvId ]
- [implicit uint 9 tlvIdLength 'lengthInBytes' ] ]
- [typeSwitch idSubType
+ [discriminator TlvType tlvId ]
+ [simple uint 9 tlvIdLength ]
+ [typeSwitch tlvId
['END_OF_LLDP' EndOfLldp
- [
- ['CHASSIS_ID' TlvChassisId
- [simple uint 8 chassisIdSubType ]
- [simple vstring '(tlvIdLength * 8) + 1' chassisId ]
]
- ['PORT_ID' TlvPortId
+ ['CHASSIS_ID' TlvChassisId(uint 9 tlvIdLength)
+ [simple uint 8 chassisIdSubType ]
+ [simple vstring '(tlvIdLength - 1) * 8' chassisId ]
+ ]
+ ['PORT_ID' TlvPortId(uint 9 tlvIdLength)
[simple uint 8 portIdSubType ]
- [simple vstring '(tlvIdLength * 8) + 1' portId ]
+ [simple vstring '(tlvIdLength - 1) * 8' portId ]
]
- ['PORT_ID' TlvPortId
- [simple uint 16 tlvTimeToLive ]
+ ['TIME_TO_LIVE' TlvTimeToLive
+ [simple uint 16 tlvTimeToLiveUnit ]
]
['MANAGEMENT_ADDRESS' TlvManagementAddress
- [implicit uint 8 addressStringLength ]
+ [implicit uint 8 addressStringLength '5' ]
[simple ManagementAddressSubType addressSubType ]
[simple IpAddress ipAddress ]
[simple uint 8 interfaceSubType ]
@@ -121,15 +121,15 @@
[simple TlvOrganizationSpecificUnit organizationSpecificUnit ]
]
]
-[
+]
-[type TlvOrganizationSpecificUnit(uint 9 unitLength)
+[discriminatedType TlvOrganizationSpecificUnit
[discriminator uint 24 uniqueCode]
[typeSwitch uniqueCode
['0x000ECF' TlvOrgSpecificProfibus
[simple TlvOrgSpecificProfibusUnit specificUnit ]
]
- [´0x00120F' TlvOrgSpecificIeee8023
+ ['0x00120F' TlvOrgSpecificIeee8023
[simple uint 8 subType ]
[simple uint 8 negotiationSupport ]
[simple uint 16 negotiationCapability ]
@@ -141,12 +141,18 @@
[discriminatedType TlvOrgSpecificProfibusUnit
[discriminator TlvProfibusSubType subType]
[typeSwitch subType
+ ['PORT_STATUS' TlvProfibusSubTypePortStatus
+ [simple uint 16 rtClassPortStatus]
+ ]
+ ['CHASSIS_MAC' TlvProfibusSubTypeChassisMac
+ [simple MacAddress macAddress]
+ ]
]
]
[enum TlvProfibusSubType
['0x02' PORT_STATUS]
- [´0x05' CHASSIS_MAC]
+ ['0x05' CHASSIS_MAC]
]
// 4.10.3.2
@@ -823,6 +829,22 @@
[simple MacAddress cmResponderMacAddr ]
[simple uint 16 responderUDPRTPort ]
]
+ ['IOD_CONTROL_REQ' PnIoCm_Control_Request
+ [reserved uint 16 '0x0000' ]
+ [simple Uuid arUuid ]
+ [simple uint 16 sessionKey ]
+ [reserved uint 16 '0x0000' ]
+ [simple uint 16 controlCommand ]
+ [reserved uint 16 '0x0000' ]
+ ]
+ ['IOD_CONTROL_RES' PnIoCm_Control_Response
+ [reserved uint 16 '0x0000' ]
+ [simple Uuid arUuid ]
+ [simple uint 16 sessionKey ]
+ [reserved uint 16 '0x0000' ]
+ [simple uint 16 controlCommand ]
+ [reserved uint 16 '0x0000' ]
+ ]
['IO_CR_BLOCK_REQ' PnIoCm_Block_IoCrReq
[simple PnIoCm_IoCrType ioCrType ]
[simple uint 16 ioCrReference ]