Skip to content

Commit

Permalink
feat: Added a pingAddress config option to the modbus driver, which a…
Browse files Browse the repository at this point in the history
…llows providing an address string, that can be used for ping-operations (Defaults to reading holding-register:1)
  • Loading branch information
chrisdutz committed Feb 15, 2024
1 parent ec7a614 commit fa615dc
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 19 deletions.
1 change: 1 addition & 0 deletions plc4j/drivers/all/src/site/generated/modbus-tcp.adoc
Expand Up @@ -38,6 +38,7 @@
5+|Config options:
|`request-timeout` |INT |5000| |Default timeout for all types of requests.
|`unit-identifier` |INT |1| |Unit-identifier that identifies the target PLC (On RS485 multiple Modbus Devices can be listening). Defaults to 1.
|`ping-address` |STRING |4x00001:BOOL| |Simple address, that the driver will use to check, if the connection to a given device is active (Defaults to reading holding-register 1).
5+|Transport config options:
5+|
+++
Expand Down
Expand Up @@ -60,12 +60,11 @@ public void close(ConversationContext<ModbusAsciiADU> context) {
public CompletableFuture<PlcPingResponse> ping(PlcPingRequest pingRequest) {
CompletableFuture<PlcPingResponse> future = new CompletableFuture<>();

// 0x00 should be the "vendor-id" and is part of the basic level
// This is theoretically required, however have I never come across
// an implementation that actually provides it.
final ModbusPDU identificationRequestPdu = new ModbusPDUReadDeviceIdentificationRequest(
ModbusDeviceInformationLevel.BASIC, (short) 0x00);
ModbusAsciiADU modbusTcpADU = new ModbusAsciiADU(unitIdentifier, identificationRequestPdu);
// As it seems that even, if Modbus defines a DeviceIdentificationRequest, no device actually implements this.
// So we fall back to a request, that most certainly is implemented by any device. Even if the device doesn't
// have any holding-register:1, it should still gracefully respond.
ModbusPDU readRequestPdu = getReadRequestPdu(pingAddress);
ModbusAsciiADU modbusTcpADU = new ModbusAsciiADU(unitIdentifier, readRequestPdu);

RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
transaction.submit(() -> context.sendRequest(modbusTcpADU)
Expand Down
Expand Up @@ -48,6 +48,8 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
protected final DriverType driverType;
protected Duration requestTimeout;
protected short unitIdentifier;
protected PlcTag pingAddress;

protected RequestTransactionManager tm;
protected final AtomicInteger transactionIdentifierGenerator = new AtomicInteger(1);
protected final static int FC_EXTENDED_REGISTERS_GROUP_HEADER_LENGTH = 2;
Expand Down
Expand Up @@ -60,12 +60,11 @@ public void close(ConversationContext<ModbusRtuADU> context) {
public CompletableFuture<PlcPingResponse> ping(PlcPingRequest pingRequest) {
CompletableFuture<PlcPingResponse> future = new CompletableFuture<>();

// 0x00 should be the "vendor-id" and is part of the basic level
// This is theoretically required, however have I never come across
// an implementation that actually provides it.
final ModbusPDU identificationRequestPdu = new ModbusPDUReadDeviceIdentificationRequest(
ModbusDeviceInformationLevel.BASIC, (short) 0x00);
ModbusRtuADU modbusRtuADU = new ModbusRtuADU(unitIdentifier, identificationRequestPdu);
// As it seems that even, if Modbus defines a DeviceIdentificationRequest, no device actually implements this.
// So we fall back to a request, that most certainly is implemented by any device. Even if the device doesn't
// have any holding-register:1, it should still gracefully respond.
ModbusPDU readRequestPdu = getReadRequestPdu(pingAddress);
ModbusRtuADU modbusRtuADU = new ModbusRtuADU(unitIdentifier, readRequestPdu);

RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
transaction.submit(() -> context.sendRequest(modbusRtuADU)
Expand Down
Expand Up @@ -22,6 +22,7 @@
import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter;
import org.apache.plc4x.java.spi.configuration.annotations.Description;
import org.apache.plc4x.java.spi.configuration.annotations.defaults.IntDefaultValue;
import org.apache.plc4x.java.spi.configuration.annotations.defaults.StringDefaultValue;

public class ModbusTcpConfiguration implements PlcConnectionConfiguration {

Expand All @@ -35,6 +36,11 @@ public class ModbusTcpConfiguration implements PlcConnectionConfiguration {
@Description("Unit-identifier that identifies the target PLC (On RS485 multiple Modbus Devices can be listening). Defaults to 1.")
private int unitIdentifier;

@ConfigurationParameter("ping-address")
@StringDefaultValue("4x00001:BOOL")
@Description("Simple address, that the driver will use to check, if the connection to a given device is active (Defaults to reading holding-register 1).")
private String pingAddress;

public int getRequestTimeout() {
return requestTimeout;
}
Expand All @@ -51,11 +57,16 @@ public void setUnitIdentifier(int unitIdentifier) {
this.unitIdentifier = unitIdentifier;
}

public String getPingAddress() {
return pingAddress;
}

@Override
public String toString() {
return "ModbusTcpConfiguration{" +
"requestTimeout=" + requestTimeout +
", unitIdentifier=" + unitIdentifier +
", pingAddress=" + pingAddress +
'}';
}

Expand Down
Expand Up @@ -25,6 +25,7 @@
import org.apache.plc4x.java.api.value.PlcValue;
import org.apache.plc4x.java.modbus.base.tag.ModbusTag;
import org.apache.plc4x.java.modbus.base.protocol.ModbusProtocolLogic;
import org.apache.plc4x.java.modbus.base.tag.ModbusTagHandler;
import org.apache.plc4x.java.modbus.readwrite.*;
import org.apache.plc4x.java.modbus.tcp.config.ModbusTcpConfiguration;
import org.apache.plc4x.java.spi.ConversationContext;
Expand All @@ -48,6 +49,7 @@ public ModbusTcpProtocolLogic() {
public void setConfiguration(ModbusTcpConfiguration configuration) {
this.requestTimeout = Duration.ofMillis(configuration.getRequestTimeout());
this.unitIdentifier = (short) configuration.getUnitIdentifier();
this.pingAddress = new ModbusTagHandler().parseTag(configuration.getPingAddress());
this.tm = new RequestTransactionManager(1);
}

Expand All @@ -60,17 +62,16 @@ public void close(ConversationContext<ModbusTcpADU> context) {
public CompletableFuture<PlcPingResponse> ping(PlcPingRequest pingRequest) {
CompletableFuture<PlcPingResponse> future = new CompletableFuture<>();

// 0x00 should be the "vendor-id" and is part of the basic level
// This is theoretically required, however have I never come across
// an implementation that actually provides it.
final ModbusPDU identificationRequestPdu = new ModbusPDUReadDeviceIdentificationRequest(
ModbusDeviceInformationLevel.BASIC, (short) 0x00);
// As it seems that even, if Modbus defines a DeviceIdentificationRequest, no device actually implements this.
// So we fall back to a request, that most certainly is implemented by any device. Even if the device doesn't
// have any holding-register:1, it should still gracefully respond.
ModbusPDU readRequestPdu = getReadRequestPdu(pingAddress);
int transactionIdentifier = transactionIdentifierGenerator.getAndIncrement();
// If we've reached the max value for a 16 bit transaction identifier, reset back to 1
if (transactionIdentifierGenerator.get() == 0xFFFF) {
transactionIdentifierGenerator.set(1);
}
ModbusTcpADU modbusTcpADU = new ModbusTcpADU(transactionIdentifier, unitIdentifier, identificationRequestPdu);
ModbusTcpADU modbusTcpADU = new ModbusTcpADU(transactionIdentifier, unitIdentifier, readRequestPdu);

RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
transaction.submit(() -> context.sendRequest(modbusTcpADU)
Expand Down
Expand Up @@ -57,8 +57,8 @@ export interface ApplicationEvent extends EventObject {
}

export interface OptionMetadata {
options: Option[];
requiredOptions: Option[];
options: Option[];
}

export interface EventObject extends Serializable {
Expand Down

0 comments on commit fa615dc

Please sign in to comment.