Skip to content

Commit

Permalink
feat: Added the ability to name expectations (helping debug missing r…
Browse files Browse the repository at this point in the history
…equests or replies). Continued working on the PN stuff.
  • Loading branch information
chrisdutz committed Dec 20, 2023
1 parent fc2d56b commit c31148d
Show file tree
Hide file tree
Showing 21 changed files with 212 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void fireDiscovered(Configuration c) {

@Override
public SendRequestContext<T> sendRequest(T packet) {
return new SendRequestContextWrapper<>(delegate.sendRequest(frameHandler.toCAN(packet)), wireType, adapter, frameHandler);
return new SendRequestContextWrapper<>("", delegate.sendRequest(frameHandler.toCAN(packet)), wireType, adapter, frameHandler);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,28 @@

public class DeferredRequestContextWrapper<T> implements SendRequestContext<T> {

private String name;

private final SendRequestContext<T> delegate;
private final Function<SendRequestContext<?>, SendRequestContext<?>> completer;
protected final Consumer<TimeoutException> onTimeoutConsumer;
protected final BiConsumer<?, ? extends Throwable> errorConsumer;

public DeferredRequestContextWrapper(SendRequestContext<T> delegate, Function<SendRequestContext<?>, SendRequestContext<?>> completer,
public DeferredRequestContextWrapper(String name, SendRequestContext<T> delegate, Function<SendRequestContext<?>, SendRequestContext<?>> completer,
Consumer<TimeoutException> onTimeoutConsumer, BiConsumer<?, ? extends Throwable> errorConsumer) {
this.name = name;
this.delegate = delegate;
this.completer = completer;
this.onTimeoutConsumer = onTimeoutConsumer;
this.errorConsumer = errorConsumer;
}

@Override
public SendRequestContext<T> name(String name) {
this.name = name;
return this;
}

@Override
public SendRequestContext<T> expectResponse(Class<T> clazz, Duration timeout) {
throw new IllegalStateException("Response type is already specified");
Expand All @@ -60,17 +69,17 @@ public ContextHandler handle(Consumer<T> packetConsumer) {

@Override
public SendRequestContext<T> onTimeout(Consumer<TimeoutException> packetConsumer) {
return new DeferredRequestContextWrapper<>(delegate, completer, packetConsumer, errorConsumer);
return new DeferredRequestContextWrapper<>(name, delegate, completer, packetConsumer, errorConsumer);
}

@Override
public <E extends Throwable> SendRequestContext<T> onError(BiConsumer<T, E> packetConsumer) {
return new DeferredRequestContextWrapper<>(delegate, completer, onTimeoutConsumer, errorConsumer);
return new DeferredRequestContextWrapper<>(name, delegate, completer, onTimeoutConsumer, errorConsumer);
}

@Override
public <R> SendRequestContext<R> unwrap(Function<T, R> unwrapper) {
return resolve(new DeferredRequestContextWrapper<>(delegate.unwrap(unwrapper), completer, onTimeoutConsumer, errorConsumer));
return resolve(new DeferredRequestContextWrapper<>(name, delegate.unwrap(unwrapper), completer, onTimeoutConsumer, errorConsumer));
}

private <R> SendRequestContext<R> resolve(DeferredRequestContextWrapper<R> contextWrapper) {
Expand All @@ -82,6 +91,7 @@ private <R> SendRequestContext<R> resolve(DeferredRequestContextWrapper<R> conte

@Override
public <R> SendRequestContext<R> only(Class<R> clazz) {
return resolve(new DeferredRequestContextWrapper<>(delegate.only(clazz), completer, onTimeoutConsumer, errorConsumer));
return resolve(new DeferredRequestContextWrapper<>(name, delegate.only(clazz), completer, onTimeoutConsumer, errorConsumer));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,26 @@

public class ResolvedSendRequestContextWrapper<T> implements SendRequestContext<T> {

private String name;

private final SendRequestContext<T> delegate;
private final DeferredErrorHandler<?, ?> errorHandler;
private final DeferredTimeoutHandler<?> timeoutHandler;

public ResolvedSendRequestContextWrapper(SendRequestContext<T> delegate, DeferredErrorHandler<?, ?> errorHandler,
public ResolvedSendRequestContextWrapper(String name, SendRequestContext<T> delegate, DeferredErrorHandler<?, ?> errorHandler,
DeferredTimeoutHandler<?> timeoutHandler) {
this.name = name;
this.delegate = delegate;
this.errorHandler = errorHandler;
this.timeoutHandler = timeoutHandler;
}

@Override
public SendRequestContext<T> name(String name) {
this.name = name;
return this;
}

@Override
public SendRequestContext<T> expectResponse(Class<T> clazz, Duration timeout) {
throw new IllegalStateException("Response type is already specified");
Expand Down Expand Up @@ -70,11 +79,11 @@ public <E extends Throwable> SendRequestContext<T> onError(BiConsumer<T, E> pack

@Override
public <R> SendRequestContext<R> unwrap(Function<T, R> unwrapper) {
return new ResolvedSendRequestContextWrapper<>(delegate.unwrap(unwrapper), errorHandler, timeoutHandler);
return new ResolvedSendRequestContextWrapper<>(name, delegate.unwrap(unwrapper), errorHandler, timeoutHandler);
}

@Override
public <R> SendRequestContext<R> only(Class<R> clazz) {
return new ResolvedSendRequestContextWrapper<>(delegate.only(clazz), errorHandler, timeoutHandler);
return new ResolvedSendRequestContextWrapper<>(name, delegate.only(clazz), errorHandler, timeoutHandler);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,32 @@

public class SendRequestContextWrapper<C, T> implements SendRequestContext<T> {

private String name;

private final SendRequestContext<C> delegate;
private final Class<C> wireType;
private final Function<C, FrameData> adapter;
private final FrameHandler<C, T> frameHandler;

public SendRequestContextWrapper(SendRequestContext<C> delegate, Class<C> wireType, Function<C, FrameData> adapter, FrameHandler<C, T> frameHandler) {
public SendRequestContextWrapper(String name, SendRequestContext<C> delegate, Class<C> wireType, Function<C, FrameData> adapter, FrameHandler<C, T> frameHandler) {
this.name = name;
this.delegate = delegate;
this.wireType = wireType;
this.adapter = adapter;
this.frameHandler = frameHandler;
}

@Override
public SendRequestContext<T> name(String name) {
this.name = name;
return this;
}

@Override
public SendRequestContext<T> expectResponse(Class<T> clazz, Duration timeout) {
DeferredErrorHandler<C, ?> errorHandler = new DeferredErrorHandler<>(null);
DeferredTimeoutHandler<?> timeoutHandler = new DeferredTimeoutHandler<>(null);
return new ResolvedSendRequestContextWrapper<>(
return new ResolvedSendRequestContextWrapper<>(name,
delegate.onError(errorHandler)
.onTimeout(timeoutHandler)
.expectResponse(wireType, timeout)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ public static PnIoCm_Packet staticParse(ReadBuffer readBuffer, DceRpc_PacketType
builder = PnIoCm_Packet_Rej.staticParsePnIoCm_PacketBuilder(readBuffer, packetType);
} else if (EvaluationHelper.equals(packetType, DceRpc_PacketType.WORKING)) {
builder = PnIoCm_Packet_Working.staticParsePnIoCm_PacketBuilder(readBuffer, packetType);
} else if (EvaluationHelper.equals(packetType, DceRpc_PacketType.CONNECTIONLESS_CANCEL)) {
builder =
PnIoCm_Packet_ConnectionlessCancel.staticParsePnIoCm_PacketBuilder(
readBuffer, packetType);
}
if (builder == null) {
throw new ParseException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public class ProfinetDriver extends GeneratedDriverBase<Ethernet_Frame> implemen
private final Logger logger = LoggerFactory.getLogger(ProfinetDriver.class);

public static final Pattern MAC_ADDRESS = Pattern.compile(
"^([0-9A-Fa-f]{2}[\\\\.:-]){5}?");
"^([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})?");

public static final String DRIVER_CODE = "profinet";

Expand Down Expand Up @@ -211,8 +211,8 @@ public PlcConnection getConnection(String connectionString, PlcAuthentication au
final String transportCode = (transportCodeMatch != null) ? transportCodeMatch : getDefaultTransport();
final String transportConfig = matcher.group("transportConfig");
final String paramString = matcher.group("paramString");
Matcher macMatcher = MAC_ADDRESS.matcher(connectionString);
if (!macMatcher.matches()) {
Matcher macMatcher = MAC_ADDRESS.matcher(transportConfig);
if (macMatcher.matches()) {
logger.info("Setting remote PROFINET device IP using DCP");
ConfigurationFactory configurationFactory = new ConfigurationFactory();
ProfinetConfiguration configuration = (ProfinetConfiguration) configurationFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public static Ethernet_Frame createIdentificationRequest(MacAddress localMacAddr
public static CompletableFuture<PnDcp_Pdu_IdentifyRes> sendIdentificationRequest(ConversationContext<Ethernet_Frame> context, MacAddress localMacAddress, MacAddress remoteMacAddress) {
CompletableFuture<PnDcp_Pdu_IdentifyRes> future = new CompletableFuture<>();
context.sendRequest(PnDcpPacketFactory.createIdentificationRequest(localMacAddress, remoteMacAddress))
.name("Expect Identification response")
.expectResponse(Ethernet_Frame.class, Duration.ofMillis(6000))
.onTimeout(future::completeExceptionally)
.onError((ethernetFrame, throwable) -> future.completeExceptionally(throwable))
Expand Down Expand Up @@ -96,6 +97,7 @@ public static CompletableFuture<PnIoCm_Block_IAndM0> sendReadIAndM0BlockRequest(
// TODO: Handle error responses quickly (If the device doesn't support PN CM, then we can abort a lot quicker.
CompletableFuture<PnIoCm_Block_IAndM0> future = new CompletableFuture<>();
context.sendRequest(PnDcpPacketFactory.createReadIAndM0BlockRequest(pnChannel, driverContext))
.name("Expect ReadIAndM0Block response")
.expectResponse(Ethernet_Frame.class, Duration.ofMillis(6000))
.onTimeout(future::completeExceptionally)
.onError((ethernetFrame, throwable) -> future.completeExceptionally(throwable))
Expand Down Expand Up @@ -155,6 +157,7 @@ public static CompletableFuture<PnIoCm_Block_IAndM1> sendReadIAndM1BlockRequest(
// TODO: Handle error responses quickly (If the device doesn't support PN CM, then we can abort a lot quicker.
CompletableFuture<PnIoCm_Block_IAndM1> future = new CompletableFuture<>();
context.sendRequest(PnDcpPacketFactory.createReadIAndM1BlockRequest(pnChannel, driverContext))
.name("Expect ReadIAndM1Block response")
.expectResponse(Ethernet_Frame.class, Duration.ofMillis(6000))
.onTimeout(future::completeExceptionally)
.onError((ethernetFrame, throwable) -> future.completeExceptionally(throwable))
Expand Down Expand Up @@ -214,6 +217,7 @@ public static Ethernet_Frame createReadRealIdentificationDataRequest(RawSocketCh
public static CompletableFuture<PnIoCm_Block_RealIdentificationData> sendRealIdentificationDataRequest(ConversationContext<Ethernet_Frame> context, RawSocketChannel pnChannel, ProfinetDriverContext driverContext) {
CompletableFuture<PnIoCm_Block_RealIdentificationData> future = new CompletableFuture<>();
context.sendRequest(createReadRealIdentificationDataRequest(pnChannel, driverContext))
.name("Expect RealIdentificationData response")
.expectResponse(Ethernet_Frame.class, Duration.ofMillis(6000))
.onTimeout(future::completeExceptionally)
.onError((ethernetFrame, throwable) -> future.completeExceptionally(throwable))
Expand Down Expand Up @@ -278,6 +282,7 @@ public static Ethernet_Frame createParameterEndRequest(RawSocketChannel pnChanne
public static CompletableFuture<PnIoCm_Control_Response_ParameterEnd> sendParameterEndRequest(ConversationContext<Ethernet_Frame> context, RawSocketChannel pnChannel, ProfinetDriverContext driverContext) {
CompletableFuture<PnIoCm_Control_Response_ParameterEnd> future = new CompletableFuture<>();
context.sendRequest(createParameterEndRequest(pnChannel, driverContext))
.name("Expect ParameterEnd response")
.expectResponse(Ethernet_Frame.class, Duration.ofMillis(6000))
.onTimeout(future::completeExceptionally)
.onError((ethernetFrame, throwable) -> future.completeExceptionally(throwable))
Expand Down Expand Up @@ -312,15 +317,15 @@ public static CompletableFuture<PnIoCm_Control_Response_ParameterEnd> sendParame
return future;
}

public static Ethernet_Frame createApplicationReadyResponse(RawSocketChannel pnChannel, ProfinetDriverContext driverContext, Uuid arUuid, int sessionKey) {
public static Ethernet_Frame createApplicationReadyResponse(RawSocketChannel pnChannel, ProfinetDriverContext driverContext, int sourcePort, DceRpc_ActivityUuid activityUuid, Uuid arUuid, int sessionKey) {
DceRpc_Packet packet = new DceRpc_Packet(
DceRpc_PacketType.RESPONSE, true, false, false,
IntegerEncoding.LITTLE_ENDIAN, CharacterEncoding.ASCII, FloatingPointEncoding.IEEE,
new DceRpc_ObjectUuid((byte) 0x00, (short) 0x0001, driverContext.getDeviceId(), driverContext.getVendorId()),
new DceRpc_InterfaceUuid_DeviceInterface(),
driverContext.getActivityUuid(),
new DceRpc_InterfaceUuid_ControllerInterface(),
activityUuid,
0,
0,
driverContext.getAndIncrementIdentification(),
DceRpc_Operation.CONTROL,
(short) 0,
new PnIoCm_Packet_Res((short) 0, (short) 0, (short) 0, (short) 0, 16696, (short) 0,
Expand All @@ -330,11 +335,69 @@ public static Ethernet_Frame createApplicationReadyResponse(RawSocketChannel pnC
)
);

return createEthernetFrame(pnChannel, driverContext, packet);
InetSocketAddress localAddress = (InetSocketAddress) pnChannel.getLocalAddress();
InetSocketAddress remoteAddress = (InetSocketAddress) pnChannel.getRemoteAddress();

// Serialize it to a byte-payload
Random rand = new Random();
Ethernet_FramePayload_IPv4 udpFrame = new Ethernet_FramePayload_IPv4(
rand.nextInt(65536),
true,
false,
(short) 64,
new IpAddress(localAddress.getAddress().getAddress()),
new IpAddress(remoteAddress.getAddress().getAddress()),
driverContext.getLocalPort(),
sourcePort,
packet
);
MacAddress srcAddress = new MacAddress(pnChannel.getLocalMacAddress().getAddress());
MacAddress dstAddress = new MacAddress(pnChannel.getRemoteMacAddress().getAddress());
return new Ethernet_Frame(
dstAddress,
srcAddress,
udpFrame);
}

public static void sendApplicationReadyResponse(ConversationContext<Ethernet_Frame> context, RawSocketChannel pnChannel, ProfinetDriverContext driverContext, int sourcePort, DceRpc_ActivityUuid activityUuid, Uuid arUuid, int sessionKey) {
context.sendToWire(createApplicationReadyResponse(pnChannel, driverContext, sourcePort, activityUuid, arUuid, sessionKey));
}

public static Ethernet_Frame createPingResponse(RawSocketChannel pnChannel, ProfinetDriverContext driverContext, Ethernet_FramePayload_IPv4 payloadIPv4) {
DceRpc_Packet pingRequest = payloadIPv4.getPayload();

DceRpc_Packet packet = new DceRpc_Packet(DceRpc_PacketType.WORKING,
false, false, false,
IntegerEncoding.BIG_ENDIAN, CharacterEncoding.ASCII, FloatingPointEncoding.IEEE,
pingRequest.getObjectUuid(), pingRequest.getInterfaceUuid(), pingRequest.getActivityUuid(),
0L, 0L, DceRpc_Operation.CONNECT, (short) 0, new PnIoCm_Packet_Working());

InetSocketAddress localAddress = (InetSocketAddress) pnChannel.getLocalAddress();
InetSocketAddress remoteAddress = (InetSocketAddress) pnChannel.getRemoteAddress();

// Serialize it to a byte-payload
Random rand = new Random();
Ethernet_FramePayload_IPv4 udpFrame = new Ethernet_FramePayload_IPv4(
rand.nextInt(65536),
true,
false,
(short) 64,
new IpAddress(localAddress.getAddress().getAddress()),
new IpAddress(remoteAddress.getAddress().getAddress()),
driverContext.getLocalPort(),
payloadIPv4.getSourcePort(),
packet
);
MacAddress srcAddress = new MacAddress(pnChannel.getLocalMacAddress().getAddress());
MacAddress dstAddress = new MacAddress(pnChannel.getRemoteMacAddress().getAddress());
return new Ethernet_Frame(
dstAddress,
srcAddress,
udpFrame);
}

public static void sendApplicationReadyResponse(ConversationContext<Ethernet_Frame> context, RawSocketChannel pnChannel, ProfinetDriverContext driverContext, Uuid arUuid, int sessionKey) {
context.sendToWire(createApplicationReadyResponse(pnChannel, driverContext, arUuid, sessionKey));
public static void sendPingResponse(ConversationContext<Ethernet_Frame> context, RawSocketChannel pnChannel, ProfinetDriverContext driverContext, Ethernet_FramePayload_IPv4 payloadIPv4) {
context.sendToWire(createPingResponse(pnChannel, driverContext, payloadIPv4));
}

/**
Expand Down
Loading

0 comments on commit c31148d

Please sign in to comment.