Skip to content

Commit bde8b15

Browse files
committed
chore(plc4j/profinet): Continued implementing the subscription logic
1 parent 5249c5c commit bde8b15

File tree

2 files changed

+249
-34
lines changed

2 files changed

+249
-34
lines changed

plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDriverContext.java

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import org.apache.plc4x.java.profinet.gsdml.ProfinetModuleItem;
2626
import org.apache.plc4x.java.profinet.gsdml.ProfinetVirtualSubmoduleItem;
2727
import org.apache.plc4x.java.profinet.readwrite.DceRpc_ActivityUuid;
28+
import org.apache.plc4x.java.profinet.readwrite.DceRpc_ObjectUuid;
29+
import org.apache.plc4x.java.profinet.readwrite.MacAddress;
2830
import org.apache.plc4x.java.profinet.readwrite.Uuid;
2931
import org.apache.plc4x.java.spi.context.DriverContext;
3032
import org.apache.plc4x.java.spi.generation.*;
@@ -37,13 +39,36 @@
3739
public class ProfinetDriverContext implements DriverContext {
3840

3941
public static final int DEFAULT_UDP_PORT = 34964;
42+
public static final int DEFAULT_ARGS_MAXIMUM = 16696;
43+
public static final int DEFAULT_MAX_ARRAY_COUNT = 16696;
44+
public static final int DEFAULT_ACTIVITY_TIMEOUT = 600;
45+
public static final int UDP_RT_PORT = 0x8892;
46+
public static final short BLOCK_VERSION_HIGH = 1;
47+
public static final short BLOCK_VERSION_LOW = 0;
48+
public static final MacAddress DEFAULT_EMPTY_MAC_ADDRESS;
49+
static {
50+
try {
51+
DEFAULT_EMPTY_MAC_ADDRESS = new MacAddress(Hex.decodeHex("000000000000"));
52+
} catch (DecoderException e) {
53+
throw new RuntimeException(e);
54+
}
55+
}
56+
57+
public static final int DEFAULT_IO_DATA_SIZE = 40;
4058

4159
private String deviceType;
4260
private String deviceName;
4361
private List<String> roles;
4462
private int vendorId;
4563
private int deviceId;
4664

65+
private boolean nonLegacyStartupMode;
66+
private int sessionKey;
67+
private int sendClockFactor;
68+
private int reductionRatio;
69+
private int watchdogFactor;
70+
private int dataHoldFactor;
71+
4772
private String dapId;
4873
private ProfinetDeviceAccessPointItem dap;
4974
private Map<Integer, ProfinetModuleItem> moduleIndex;
@@ -69,7 +94,7 @@ public ProfinetDriverContext() {
6994
* Generates a new UUID for this connection.
7095
* @return UUID
7196
*/
72-
protected static DceRpc_ActivityUuid generateActivityUuid() {
97+
public static DceRpc_ActivityUuid generateActivityUuid() {
7398
UUID number = UUID.randomUUID();
7499
try {
75100
WriteBufferByteBased wb = new WriteBufferByteBased(128);
@@ -132,6 +157,56 @@ public void setDeviceId(int deviceId) {
132157
this.deviceId = deviceId;
133158
}
134159

160+
public boolean isNonLegacyStartupMode() {
161+
return nonLegacyStartupMode;
162+
}
163+
164+
// TODO: Setup the nonLegacyStartupMode variable.
165+
public void setNonLegacyStartupMode(boolean nonLegacyStartupMode) {
166+
this.nonLegacyStartupMode = nonLegacyStartupMode;
167+
}
168+
169+
public int getSessionKey() {
170+
return sessionKey;
171+
}
172+
173+
// TODO: Setup the sessionKey variable.
174+
public void setSessionKey(int sessionKey) {
175+
this.sessionKey = sessionKey;
176+
}
177+
178+
public int getSendClockFactor() {
179+
return sendClockFactor;
180+
}
181+
182+
public void setSendClockFactor(int sendClockFactor) {
183+
this.sendClockFactor = sendClockFactor;
184+
}
185+
186+
public int getReductionRatio() {
187+
return reductionRatio;
188+
}
189+
190+
public void setReductionRatio(int reductionRatio) {
191+
this.reductionRatio = reductionRatio;
192+
}
193+
194+
public int getWatchdogFactor() {
195+
return watchdogFactor;
196+
}
197+
198+
public void setWatchdogFactor(int watchdogFactor) {
199+
this.watchdogFactor = watchdogFactor;
200+
}
201+
202+
public int getDataHoldFactor() {
203+
return dataHoldFactor;
204+
}
205+
206+
public void setDataHoldFactor(int dataHoldFactor) {
207+
this.dataHoldFactor = dataHoldFactor;
208+
}
209+
135210
public String getDapId() {
136211
return dapId;
137212
}
@@ -188,4 +263,18 @@ public int getAndIncrementIdentification() {
188263
return id;
189264
}
190265

266+
public DceRpc_ObjectUuid getCmInitiatorObjectUuid() {
267+
return new DceRpc_ObjectUuid((byte) 0x00, 0x0001,
268+
Integer.decode("0x" + getDeviceId()),
269+
Integer.decode("0x" + getVendorId()));
270+
}
271+
272+
public Uuid generateUuid() {
273+
try {
274+
return new Uuid(Hex.decodeHex(UUID.randomUUID().toString().replace("-", "")));
275+
} catch (DecoderException e) {
276+
throw new RuntimeException(e);
277+
}
278+
}
279+
191280
}

plc4j/drivers/profinet-ng/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetProtocolLogic.java

Lines changed: 159 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.slf4j.Logger;
4444
import org.slf4j.LoggerFactory;
4545

46+
import java.net.InetSocketAddress;
4647
import java.util.*;
4748
import java.util.concurrent.CompletableFuture;
4849

@@ -402,14 +403,14 @@ public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionReque
402403
// Create one PnIoCm_Block_ExpectedSubmoduleReq for every slot being referenced.
403404
// Create one PnIoCm_Block_AlarmCrReq
404405

405-
406406
// Go through the sorted slots and subslots and fill the datastructures.
407407
int inputFrameOffset = 0;
408408
int outputFrameOffset = 0;
409-
/*List<PnIoCm_IoDataObject> inputMessageDataObjects = new ArrayList<>();
409+
List<PnIoCm_IoDataObject> inputMessageDataObjects = new ArrayList<>();
410410
List<PnIoCm_IoCs> inputMessageCs = new ArrayList<>();
411-
//List<PnIoCm_IoDataObject> outputMessageDataObjects = new ArrayList<>();
412-
//List<PnIoCm_IoCs> outputMessageCs = new ArrayList<>();
411+
List<PnIoCm_IoDataObject> outputMessageDataObjects = new ArrayList<>();
412+
List<PnIoCm_IoCs> outputMessageCs = new ArrayList<>();
413+
// TODO: Create and fill the expectedSubmodules list.
413414
List<PnIoCm_Block_ExpectedSubmoduleReq> expectedSubmodules = new ArrayList<>();
414415
for (Map.Entry<Integer, Map<Integer, Map<ProfinetTag.Direction, Map<Integer, ProfinetTag>>>> slotEntry : slots.entrySet()) {
415416
int slotNumber = slotEntry.getKey();
@@ -418,53 +419,178 @@ public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionReque
418419
int subslotNumber = subslotEntry.getKey();
419420
Map<ProfinetTag.Direction, Map<Integer, ProfinetTag>> direction = subslotEntry.getValue();
420421

422+
int iocsLength = driverContext.getSubmoduleIndex().get(slotNumber).get(subslotNumber).getIoData().getIocsLength();
423+
// The default is 1
424+
if(iocsLength == 0) {
425+
iocsLength = 1;
426+
}
427+
int iopsLength = driverContext.getSubmoduleIndex().get(slotNumber).get(subslotNumber).getIoData().getIopsLength();
428+
// The default is 1
429+
if(iopsLength == 0) {
430+
iopsLength = 1;
431+
}
421432

422433
if(direction.containsKey(ProfinetTag.Direction.INPUT)) {
423434
Map<Integer, ProfinetTag> inputTags = direction.get(ProfinetTag.Direction.INPUT);
424435
for (Map.Entry<Integer, ProfinetTag> inputTag : inputTags.entrySet()) {
436+
ProfinetTag tag = inputTag.getValue();
437+
int dataLength = (getDataTypeLengthInBytes(tag.getPlcValueType()) * tag.getNumElements());
438+
425439
PnIoCm_IoDataObject input = new PnIoCm_IoDataObject(slotNumber, subslotNumber, inputFrameOffset);
426440
inputMessageDataObjects.add(input);
427-
// TODO: Get the iops-length from the IoData element
428-
inputFrameOffset += 1;
429-
// TODO: Get the data-length + iops-length
430-
outputFrameOffset += 1;
441+
PnIoCm_IoCs output = new PnIoCm_IoCs(slotNumber, subslotNumber, outputFrameOffset);
442+
outputMessageCs.add(output);
443+
444+
// Get the iops-length from the IoData element and the binary length of the input
445+
inputFrameOffset += dataLength + iocsLength;
446+
// Get the data-length + iops-length
447+
outputFrameOffset += iocsLength;
431448
}
432449
}
450+
433451
if(direction.containsKey(ProfinetTag.Direction.OUTPUT)) {
434452
Map<Integer, ProfinetTag> outputTags = direction.get(ProfinetTag.Direction.OUTPUT);
435453
for (Map.Entry<Integer, ProfinetTag> outputTag : outputTags.entrySet()) {
454+
ProfinetTag tag = outputTag.getValue();
455+
int dataLength = (getDataTypeLengthInBytes(tag.getPlcValueType()) * tag.getNumElements());
456+
436457
PnIoCm_IoDataObject output = new PnIoCm_IoDataObject(slotNumber, subslotNumber, inputFrameOffset);
437458
outputMessageDataObjects.add(output);
438-
// TODO: Get the data-length + iocs-length from the IoData element
439-
inputFrameOffset += 1;
440-
// TODO: Get the iops-length
441-
outputFrameOffset += 1;
459+
PnIoCm_IoCs input = new PnIoCm_IoCs(slotNumber, subslotNumber, outputFrameOffset);
460+
inputMessageCs.add(input);
461+
462+
// Get the data-length + iocs-length from the IoData element
463+
inputFrameOffset += iopsLength;
464+
// Get the iops-length and the binary length of the output
465+
outputFrameOffset += dataLength + iopsLength;
442466
}
443467
}
444468
}
445469
}
446470

447-
for (String tagName : subscriptionRequest.getTagNames()) {
448-
ProfinetTag profinetTag = (ProfinetTag) subscriptionRequest.getTag(tagName);
449-
450-
451-
452-
453-
PlcValueType plcValueType = profinetTag.getPlcValueType();
454-
int numElements = profinetTag.getNumElements();
455-
int iopsLength = driverContext.getSubmoduleIndex().get(slot).get(subSlot).getIoData().getIopsLength();
456-
// The default is 1
457-
if(iopsLength == 0) {
458-
iopsLength = 1;
459-
}
460-
461-
PnIoCm_IoDataObject input = new PnIoCm_IoDataObject(slot, subSlot, inputFrameOffset);
462-
inputDataObjects.add(input);
463-
464-
// Increment the frame offset.
465-
inputFrameOffset += (getDataTypeLengthInBytes(plcValueType) * numElements) + iopsLength;
466-
}*/
467-
471+
RawSocketChannel rawSocketChannel = (RawSocketChannel) context.getChannel();
472+
MacAddress remoteMacAddress = new MacAddress(rawSocketChannel.getRemoteMacAddress().getAddress());
473+
InetSocketAddress remoteAddress = (InetSocketAddress) rawSocketChannel.getRemoteAddress();
474+
MacAddress localMacAddress = new MacAddress(rawSocketChannel.getLocalMacAddress().getAddress());
475+
InetSocketAddress localAddress = (InetSocketAddress) rawSocketChannel.getLocalAddress();
476+
List<PnIoCm_Block> blocks = new ArrayList<>();
477+
blocks.add(new PnIoCm_Block_ArReq(
478+
ProfinetDriverContext.BLOCK_VERSION_HIGH, ProfinetDriverContext.BLOCK_VERSION_LOW,
479+
PnIoCm_ArType.IO_CONTROLLER,
480+
driverContext.generateUuid(),
481+
driverContext.getSessionKey(),
482+
localMacAddress,
483+
driverContext.getCmInitiatorObjectUuid(),
484+
false,
485+
driverContext.isNonLegacyStartupMode(),
486+
false,
487+
false,
488+
PnIoCm_CompanionArType.SINGLE_AR,
489+
false,
490+
true,
491+
false,
492+
PnIoCm_State.ACTIVE,
493+
ProfinetDriverContext.DEFAULT_ACTIVITY_TIMEOUT,
494+
ProfinetDriverContext.UDP_RT_PORT,
495+
"plc4x"));
496+
if(!inputMessageDataObjects.isEmpty() || !inputMessageCs.isEmpty()) {
497+
blocks.add(new PnIoCm_Block_IoCrReq(
498+
ProfinetDriverContext.BLOCK_VERSION_HIGH, ProfinetDriverContext.BLOCK_VERSION_LOW,
499+
PnIoCm_IoCrType.INPUT_CR,
500+
0x0001,
501+
ProfinetDriverContext.UDP_RT_PORT,
502+
false,
503+
false,
504+
false,
505+
false,
506+
PnIoCm_RtClass.RT_CLASS_2,
507+
ProfinetDriverContext.DEFAULT_IO_DATA_SIZE,
508+
driverContext.getAndIncrementIdentification(),
509+
driverContext.getSendClockFactor(),
510+
driverContext.getReductionRatio(),
511+
1,
512+
0,
513+
0xffffffffL,
514+
driverContext.getWatchdogFactor(),
515+
driverContext.getDataHoldFactor(),
516+
0xC000,
517+
ProfinetDriverContext.DEFAULT_EMPTY_MAC_ADDRESS,
518+
Collections.singletonList(
519+
new PnIoCm_IoCrBlockReqApi(inputMessageDataObjects, inputMessageCs)
520+
)
521+
));
522+
}
523+
if(!outputMessageDataObjects.isEmpty() || !outputMessageCs.isEmpty()) {
524+
blocks.add(new PnIoCm_Block_IoCrReq(
525+
ProfinetDriverContext.BLOCK_VERSION_HIGH, ProfinetDriverContext.BLOCK_VERSION_LOW,
526+
PnIoCm_IoCrType.OUTPUT_CR,
527+
0x0002,
528+
ProfinetDriverContext.UDP_RT_PORT,
529+
false,
530+
false,
531+
false,
532+
false,
533+
PnIoCm_RtClass.RT_CLASS_2,
534+
ProfinetDriverContext.DEFAULT_IO_DATA_SIZE,
535+
driverContext.getAndIncrementIdentification(),
536+
driverContext.getSendClockFactor(),
537+
driverContext.getReductionRatio(),
538+
1,
539+
0,
540+
0xffffffffL,
541+
driverContext.getWatchdogFactor(),
542+
driverContext.getDataHoldFactor(),
543+
0xC000,
544+
ProfinetDriverContext.DEFAULT_EMPTY_MAC_ADDRESS,
545+
Collections.singletonList(
546+
new PnIoCm_IoCrBlockReqApi(outputMessageDataObjects, outputMessageCs)
547+
)
548+
));
549+
}
550+
blocks.addAll(expectedSubmodules);
551+
blocks.add(new PnIoCm_Block_AlarmCrReq(
552+
ProfinetDriverContext.BLOCK_VERSION_HIGH, ProfinetDriverContext.BLOCK_VERSION_LOW,
553+
PnIoCm_AlarmCrType.ALARM_CR,
554+
ProfinetDriverContext.UDP_RT_PORT,
555+
false,
556+
false,
557+
1,
558+
3,
559+
0x0000,
560+
200,
561+
0xC000,
562+
0xA000));
563+
PnIoCm_Packet_Req request = new PnIoCm_Packet_Req(
564+
16696L, 16696L, 0L, blocks);
565+
DceRpc_Packet packet = new DceRpc_Packet(
566+
DceRpc_PacketType.WORKING,
567+
false, false, false,
568+
IntegerEncoding.BIG_ENDIAN, CharacterEncoding.ASCII, FloatingPointEncoding.IEEE,
569+
new DceRpc_ObjectUuid((byte) 0x00, 0x0001, Integer.decode("0x" + driverContext.getDeviceId()), Integer.decode("0x" + driverContext.getVendorId())),
570+
new DceRpc_InterfaceUuid_DeviceInterface(),
571+
driverContext.getActivityUuid(),
572+
0L, 0L,
573+
DceRpc_Operation.CONNECT,
574+
(short) 0,
575+
request
576+
);
577+
Random rand = new Random();
578+
// Serialize it to a byte-payload
579+
Ethernet_FramePayload_IPv4 udpFrame = new Ethernet_FramePayload_IPv4(
580+
rand.nextInt(65536),
581+
true,
582+
false,
583+
(short) 64,
584+
new IpAddress(localAddress.getAddress().getAddress()),
585+
new IpAddress(remoteAddress.getAddress().getAddress()),
586+
driverContext.getLocalPort(),
587+
driverContext.getRemotePortImplicitCommunication(),
588+
packet
589+
);
590+
Ethernet_Frame ethernetFrame = new Ethernet_Frame(
591+
remoteMacAddress,
592+
localMacAddress,
593+
udpFrame);
468594

469595
return null;
470596
}

0 commit comments

Comments
 (0)