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:55 UTC
[plc4x] 10/13: fix(plc4j/profinet): Identified that the Application Ready request comes from the device.
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 40d4cc6263a9b8fb8b362bc5bfe32302500b9419
Author: Ben Hutcheson <be...@gmail.com>
AuthorDate: Sun Sep 18 08:34:19 2022 -0600
fix(plc4j/profinet): Identified that the Application Ready request comes from the device.
---
.../apache/plc4x/java/profinet/ProfinetDriver.java | 2 +-
.../profinet/discovery/ProfinetPlcDiscoverer.java | 23 ++--
.../profinet/protocol/ProfinetProtocolLogic.java | 128 ++++++++++++++++-----
.../resources/protocols/profinet/profinet.mspec | 12 +-
4 files changed, 123 insertions(+), 42 deletions(-)
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
index 05d96d8b4..0a311206d 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
@@ -85,7 +85,7 @@ public class ProfinetDriver extends GeneratedDriverBase<Ethernet_Frame> {
*/
@Override
protected boolean awaitSetupComplete() {
- return false;
+ return true;
}
/**
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 bc7ef865d..f0a1a3a43 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
@@ -206,12 +206,19 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
public CompletableFuture<PlcDiscoveryResponse> discoverWithHandler(PlcDiscoveryRequest discoveryRequest, PlcDiscoveryItemHandler handler) {
openDiscoverHandles();
startListener(handler);
- startLldpPoll();
- startPnDcpPoll();
+ startLldpPoll(5000L);
+ startPnDcpPoll(30000L);
CompletableFuture<PlcDiscoveryResponse> future = setDiscoveryEndTimer(discoveryRequest, 10000L);
return future;
}
+ public void ongoingDiscoverWithHandler(PlcDiscoveryRequest discoveryRequest, PlcDiscoveryItemHandler handler, long lldpPeriod, long dcpPeriod) {
+ openDiscoverHandles();
+ startListener(handler);
+ startLldpPoll(lldpPeriod);
+ startPnDcpPoll(dcpPeriod);
+ }
+
private void processPnDcp(PnDcp_Pdu pdu, EthernetPacket ethernetPacket, PlcDiscoveryItemHandler handler) {
// Inspect the PDU itself
// (in this case we only process identify response packets)
@@ -318,7 +325,7 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
logger.debug("Found new lldp device: '' with connection-url ''");
}
- public void startPnDcpPoll() {
+ public void startPnDcpPoll(long period) {
for (Map.Entry<MacAddress, PcapHandle> entry : openHandles.entrySet()) {
PcapHandle handle = entry.getValue();
MacAddress macAddress = entry.getKey();
@@ -366,8 +373,8 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
// Schedule to run after every 3 second(3000 millisecond)
timer.scheduleAtFixedRate(
new PeriodicTask(handle, pnDcpTimer),
- 5000,
- 5000);
+ 0,
+ period);
}
}
@@ -404,7 +411,7 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
- public void startLldpPoll() {
+ public void startLldpPoll(long period) {
for (Map.Entry<MacAddress, PcapHandle> entry : openHandles.entrySet()) {
PcapHandle handle = entry.getValue();
MacAddress macAddress = entry.getKey();
@@ -500,8 +507,8 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
// Schedule to run after every 3 second(3000 millisecond)
timer.scheduleAtFixedRate(
new PeriodicTask(handle, lldpTimer),
- 5000,
- 5000);
+ 0,
+ period);
}
}
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 3801c1dfa..efbac95c4 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
@@ -25,10 +25,12 @@ import org.apache.commons.lang3.NotImplementedException;
import org.apache.plc4x.java.api.exceptions.PlcException;
import org.apache.plc4x.java.api.messages.*;
import org.apache.plc4x.java.profinet.context.ProfinetDriverContext;
+import org.apache.plc4x.java.profinet.discovery.ProfinetPlcDiscoverer;
import org.apache.plc4x.java.profinet.readwrite.*;
import org.apache.plc4x.java.spi.ConversationContext;
import org.apache.plc4x.java.spi.Plc4xProtocolBase;
import org.apache.plc4x.java.spi.generation.*;
+import org.apache.plc4x.java.spi.messages.DefaultPlcDiscoveryRequest;
import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketChannel;
import org.pcap4j.core.PcapAddress;
import org.pcap4j.core.PcapNativeException;
@@ -53,6 +55,11 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
private final Logger logger = LoggerFactory.getLogger(ProfinetProtocolLogic.class);
private ProfinetDriverContext profinetDriverContext;
+ private boolean connected = false;
+
+ private DatagramSocket udpSocket;
+ private RawSocketChannel rawSocketChannel;
+ private Channel channel;
private static final Uuid ARUUID;
@@ -72,17 +79,17 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
@Override
public void onConnect(ConversationContext<Ethernet_Frame> context) {
- final Channel channel = context.getChannel();
+ channel = context.getChannel();
+ connected = false;
if (!(channel instanceof RawSocketChannel)) {
logger.warn("Expected a 'raw' transport, closing channel...");
context.getChannel().close();
return;
}
- RawSocketChannel rawSocketChannel = (RawSocketChannel) channel;
+ rawSocketChannel = (RawSocketChannel) channel;
// Create an udp socket
- DatagramSocket udpSocket;
try {
udpSocket = new DatagramSocket();
} catch (SocketException e) {
@@ -91,6 +98,19 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
return;
}
+ ProfinetPlcDiscoverer discoverer = new ProfinetPlcDiscoverer();
+ DefaultPlcDiscoveryRequest request = new DefaultPlcDiscoveryRequest(
+ discoverer,
+ new LinkedHashMap<>()
+ );
+
+ discoverer.ongoingDiscoverWithHandler(
+ request,
+ null,
+ 5000L,
+ 30000L
+ );
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Initialize some important datastructures, that will be used a lot.
@@ -225,6 +245,8 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
resultBuffer = new byte[profinetAdvancedConnectionApplicationReady.getLengthInBytes()];
connectResponsePacket = new DatagramPacket(resultBuffer, resultBuffer.length);
udpSocket.receive(connectResponsePacket);
+ context.fireConnected();
+ connected = true;
} catch (SerializationException | IOException | PlcException | ParseException e) {
logger.error("Error", e);
@@ -250,14 +272,85 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
return future;
}
+ private Ethernet_FramePayload_PnDcp createProfinetCyclicDataRequest() {
+ return new Ethernet_FramePayload_PnDcp(
+ new PnDcp_Pdu_RealTimeCyclic(
+ 0x8000,
+ new PnIo_CyclicServiceDataUnit((short) 0,(short) 0, (short) 0),
+ 16696,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false));
+ }
+
+
@Override
public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest subscriptionRequest) {
CompletableFuture<PlcSubscriptionResponse> future = new CompletableFuture<>();
- future.completeExceptionally(new NotImplementedException());
+ if (!connected) {
+ throw new RuntimeException("Not Connected");
+ }
+
+ final InetSocketAddress remoteAddress = (InetSocketAddress) rawSocketChannel.getRemoteAddress();
+
+ try {
+ // Create the packet
+ final Ethernet_FramePayload_PnDcp profinetConnectionRequest = createProfinetCyclicDataRequest();
+ // Serialize it to a byte-payload
+ WriteBufferByteBased writeBuffer = new WriteBufferByteBased(profinetConnectionRequest.getLengthInBytes());
+ profinetConnectionRequest.serialize(writeBuffer);
+ // Create a udp packet.
+ DatagramPacket connectRequestPacket = new DatagramPacket(writeBuffer.getData(), writeBuffer.getData().length);
+ connectRequestPacket.setAddress(remoteAddress.getAddress());
+ connectRequestPacket.setPort(remoteAddress.getPort());
+ // Send it.
+
+ udpSocket.send(connectRequestPacket);
+
+ // Receive the response.
+ byte[] resultBuffer = new byte[profinetConnectionRequest.getLengthInBytes()];
+ DatagramPacket connectResponsePacket = new DatagramPacket(resultBuffer, resultBuffer.length);
+ udpSocket.receive(connectResponsePacket);
+ ReadBufferByteBased readBuffer = new ReadBufferByteBased(resultBuffer);
+ final DceRpc_Packet dceRpc_packet = DceRpc_Packet.staticParse(readBuffer);
+ if ((dceRpc_packet.getOperation() == DceRpc_Operation.CONNECT) && (dceRpc_packet.getPacketType() == DceRpc_PacketType.RESPONSE)) {
+ if (dceRpc_packet.getPayload().getPacketType() == DceRpc_PacketType.RESPONSE) {
+ // Get the remote MAC address and store it in the context.
+ final PnIoCm_Packet_Res connectResponse = (PnIoCm_Packet_Res) dceRpc_packet.getPayload();
+ if ((connectResponse.getBlocks().size() > 0) && (connectResponse.getBlocks().get(0) instanceof PnIoCm_Block_ArRes)) {
+ final PnIoCm_Block_ArRes pnIoCm_block_arRes = (PnIoCm_Block_ArRes) connectResponse.getBlocks().get(0);
+ profinetDriverContext.setRemoteMacAddress(pnIoCm_block_arRes.getCmResponderMacAddr());
+
+ // Update the raw-socket transports filter expression.
+ ((RawSocketChannel) channel).setRemoteMacAddress(org.pcap4j.util.MacAddress.getByAddress(profinetDriverContext.getRemoteMacAddress().getAddress()));
+ } else {
+ throw new PlcException("Unexpected type of first block.");
+ }
+ } else {
+ throw new PlcException("Unexpected response");
+ }
+ } else if (dceRpc_packet.getPacketType() == DceRpc_PacketType.REJECT) {
+ throw new PlcException("Device rejected connection request");
+ } else {
+ throw new PlcException("Unexpected response");
+ }
+ } catch (SerializationException e) {
+ throw new RuntimeException(e);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ } catch (PlcException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
return future;
}
- @Override
+ @Override
protected void decode(ConversationContext<Ethernet_Frame> context, Ethernet_Frame msg) throws Exception {
super.decode(context, msg);
}
@@ -342,7 +435,7 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
new PnIoCm_Block_ExpectedSubmoduleReq((short) 1, (short) 0,
Collections.singletonList(
new PnIoCm_ExpectedSubmoduleBlockReqApi(0,
- 0x00000010, 0x00000000,
+ 0x00000001, 0x00000000,
Arrays.asList(
new PnIoCm_Submodule_NoInputNoOutputData(0x0001,
0x00000001, false, false,
@@ -411,29 +504,6 @@ public class ProfinetProtocolLogic extends Plc4xProtocolBase<Ethernet_Frame> {
(short) 1,
(short) 0,
MultipleInterfaceModeNameOfDevice.NAME_PROVIDED_BY_LLDP
- ),
- new IODWriteRequestHeader(
- (short) 1,
- (short) 0,
- 2,
- ARUUID,
- 0x00000000,
- 0x0000,
- 0x8001,
- 0x802b,
- 40
- ),
- new PDPortDataCheck(
- (short) 1,
- (short) 0,
- 0x0000,
- 0x8001,
- new CheckPeers(
- (short) 1,
- (short) 0,
- new PascalString("port-001"),
- new PascalString("plc4x")
- )
)
))
);
diff --git a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
index 2cabb832f..9a964a6e1 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
@@ -362,8 +362,8 @@
[virtual PnDcp_FrameId frameId 'STATIC_CALL("getFrameId", frameIdValue)']
[typeSwitch frameId
['RT_CLASS_1' PnDcp_Pdu_RealTimeCyclic
- // TODO: This type needs to be implemented ...
-// [simple PnIo_CyclicServiceDataUnit dataUnit ]
+ // TODO: This type needs to be implemented based of the configuration and gsd file ...
+ [simple PnIo_CyclicServiceDataUnit dataUnit ]
[simple uint 16 cycleCounter ]
// Data Status Start (4.7.2.1.3)
[simple bit ignore ]
@@ -488,8 +488,12 @@
]
]
-//[discriminatedType PnIo_CyclicServiceDataUnit
-//]
+[type PnIo_CyclicServiceDataUnit
+ [simple uint 8 dummyIOData1]
+ [simple uint 8 dummyIOData2]
+ [simple uint 8 dummyIOData3]
+ [padding uint 8 pad '0x00' '37']
+]
[discriminatedType PnDcp_Block
[discriminator PnDcp_BlockOptions option ]