Skip to content

Commit

Permalink
Add support for unit-id option for modbus tags.
Browse files Browse the repository at this point in the history
Introduce support for tag config at the tag level.
Closes #1234.

Signed-off-by: Łukasz Dywicki <[email protected]>
  • Loading branch information
splatch committed Mar 23, 2024
1 parent 5d4d437 commit 4168452
Show file tree
Hide file tree
Showing 17 changed files with 239 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ public class ModbusAsciiConfiguration implements PlcConnectionConfiguration {
@Description("Default timeout for all types of requests.")
private int requestTimeout;

@ConfigurationParameter("unit-identifier")
@ConfigurationParameter("default-unit-identifier")
@IntDefaultValue(1)
@Description("Unit-identifier or slave-id that identifies the target PLC (On RS485 multiple Modbus Devices can be listening). Defaults to 1.")
private int unitIdentifier;
private short defaultUnitIdentifier;

public int getRequestTimeout() {
return requestTimeout;
Expand All @@ -43,19 +43,19 @@ public void setRequestTimeout(int requestTimeout) {
this.requestTimeout = requestTimeout;
}

public int getUnitIdentifier() {
return unitIdentifier;
public short getDefaultUnitIdentifier() {
return defaultUnitIdentifier;
}

public void setUnitIdentifier(int unitIdentifier) {
this.unitIdentifier = unitIdentifier;
public void setDefaultUnitIdentifier(short defaultUnitIdentifier) {
this.defaultUnitIdentifier = defaultUnitIdentifier;
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public ModbusAsciiProtocolLogic() {
@Override
public void setConfiguration(ModbusAsciiConfiguration configuration) {
this.requestTimeout = Duration.ofMillis(configuration.getRequestTimeout());
this.unitIdentifier = (short) configuration.getUnitIdentifier();
this.unitIdentifier = configuration.getDefaultUnitIdentifier();
this.tm = new RequestTransactionManager(1);
}

Expand All @@ -64,7 +64,8 @@ public CompletableFuture<PlcPingResponse> ping(PlcPingRequest pingRequest) {
// 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);
short unitId = getUnitId(pingAddress);
ModbusAsciiADU modbusTcpADU = new ModbusAsciiADU(unitId, readRequestPdu);

RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
transaction.submit(() -> context.sendRequest(modbusTcpADU)
Expand Down Expand Up @@ -99,8 +100,9 @@ public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
String tagName = request.getTagNames().iterator().next();
ModbusTag tag = (ModbusTag) request.getTag(tagName);
final ModbusPDU requestPdu = getReadRequestPdu(tag);
final short unitId = getUnitId(tag);

ModbusAsciiADU modbusAsciiADU = new ModbusAsciiADU(unitIdentifier, requestPdu);
ModbusAsciiADU modbusAsciiADU = new ModbusAsciiADU(unitId, requestPdu);
RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
transaction.submit(() -> context.sendRequest(modbusAsciiADU)
.expectResponse(ModbusAsciiADU.class, requestTimeout)
Expand Down Expand Up @@ -158,7 +160,8 @@ public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
String tagName = request.getTagNames().iterator().next();
PlcTag tag = request.getTag(tagName);
final ModbusPDU requestPdu = getWriteRequestPdu(tag, writeRequest.getPlcValue(tagName));
ModbusAsciiADU modbusAsciiADU = new ModbusAsciiADU(unitIdentifier, requestPdu);
final short unitId = getUnitId(tag);
ModbusAsciiADU modbusAsciiADU = new ModbusAsciiADU(unitId, requestPdu);
RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
transaction.submit(() -> context.sendRequest(modbusAsciiADU)
.expectResponse(ModbusAsciiADU.class, requestTimeout)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
package org.apache.plc4x.java.modbus.base.protocol;

import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
import org.apache.plc4x.java.api.messages.PlcPingRequest;
import org.apache.plc4x.java.api.messages.PlcPingResponse;
import org.apache.plc4x.java.api.messages.PlcReadResponse;
import org.apache.plc4x.java.api.model.PlcTag;
import org.apache.plc4x.java.api.value.*;
import org.apache.plc4x.java.api.types.PlcResponseCode;
Expand All @@ -40,7 +37,6 @@
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProtocolBase<T> {
Expand Down Expand Up @@ -97,6 +93,15 @@ protected PlcResponseCode getErrorCode(ModbusPDUError errorResponse) {
}
}

protected short getUnitId(PlcTag tag) {
if (tag instanceof ModbusTag) {
Short unitId = ((ModbusTag) tag).getUnitId();
return unitId == null ? unitIdentifier : unitId;
}

return unitIdentifier;
}

protected ModbusPDU getReadRequestPdu(PlcTag tag) {
if (tag instanceof ModbusTagDiscreteInput) {
ModbusTagDiscreteInput discreteInput = (ModbusTagDiscreteInput) tag;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@
import org.apache.plc4x.java.spi.utils.Serializable;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.regex.Pattern;

public abstract class ModbusTag implements PlcTag, Serializable {
Expand All @@ -47,6 +45,7 @@ public abstract class ModbusTag implements PlcTag, Serializable {
private final int quantity;

private final ModbusDataType dataType;
private final Short unitId;

public static ModbusTag of(String addressString) {
if (ModbusTagCoil.matches(addressString)) {
Expand Down Expand Up @@ -88,6 +87,10 @@ public String getAddressString() {
* @param dataType The type for the interpretation of the registers.
*/
protected ModbusTag(int address, Integer quantity, ModbusDataType dataType) {
this(address, quantity, dataType, new HashMap<>());
}

protected ModbusTag(int address, Integer quantity, ModbusDataType dataType, Map<String, String> config) {
this.address = address;
if (getLogicalAddress() <= 0) {
throw new IllegalArgumentException("address must be greater than zero. Was " + getLogicalAddress());
Expand All @@ -97,6 +100,9 @@ protected ModbusTag(int address, Integer quantity, ModbusDataType dataType) {
throw new IllegalArgumentException("quantity must be greater than zero. Was " + this.quantity);
}
this.dataType = dataType != null ? dataType : ModbusDataType.INT;
this.unitId = Optional.ofNullable(config.get("unit-id"))
.map(Short::parseShort)
.orElse(null);
}

/**
Expand All @@ -107,6 +113,10 @@ public int getAddress() {
return address;
}

public Short getUnitId() {
return unitId;
}

/**
* Get the logical (configured) address
* @return The address which was configured and is different from what is used on the wire.
Expand Down Expand Up @@ -154,12 +164,13 @@ public boolean equals(Object o) {
return address == that.address &&
quantity == that.quantity &&
dataType == that.dataType &&
unitId == that.unitId &&
getClass() == that.getClass(); // MUST be identical
}

@Override
public int hashCode() {
return Objects.hash(this.getClass(), address, quantity, dataType);
return Objects.hash(this.getClass(), address, quantity, dataType, unitId);
}

@Override
Expand All @@ -168,6 +179,7 @@ public String toString() {
"address=" + address +
", quantity=" + quantity +
", dataType=" + dataType +
", unitId=" + unitId +
" }";
}

Expand All @@ -182,6 +194,9 @@ public void serialize(WriteBuffer writeBuffer) throws SerializationException {
dataType.getBytes(StandardCharsets.UTF_8).length * 8,
dataType, WithOption.WithEncoding(StandardCharsets.UTF_8.name()));

if (unitId != null) {
writeBuffer.writeUnsignedInt("unitId", 8, unitId);
}
writeBuffer.popContext(getClass().getSimpleName());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@

import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException;
import org.apache.plc4x.java.modbus.readwrite.ModbusDataType;
import org.apache.plc4x.java.spi.tag.TagConfigParser;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ModbusTagCoil extends ModbusTag {

public static final String ADDRESS_PREFIX = "0x";
public static final Pattern ADDRESS_PATTERN = Pattern.compile("coil:" + ModbusTag.ADDRESS_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("0" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("0x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_PATTERN = Pattern.compile("coil:" + ModbusTag.ADDRESS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("0" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("0x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);

protected static final int REGISTER_MAXADDRESS = 65535;

public ModbusTagCoil(int address, Integer quantity, ModbusDataType dataType) {
super(address, quantity, dataType);
public ModbusTagCoil(int address, Integer quantity, ModbusDataType dataType, Map<String, String> config) {
super(address, quantity, dataType, config);
}

protected String getAddressStringPrefix() {
Expand Down Expand Up @@ -88,7 +90,7 @@ public static ModbusTagCoil of(String addressString) {

ModbusDataType dataType = (matcher.group("datatype") != null) ? ModbusDataType.valueOf(matcher.group("datatype")) : ModbusDataType.BOOL;

return new ModbusTagCoil(address, quantity, dataType);
return new ModbusTagCoil(address, quantity, dataType, TagConfigParser.parse(addressString));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@

import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException;
import org.apache.plc4x.java.modbus.readwrite.ModbusDataType;
import org.apache.plc4x.java.spi.tag.TagConfigParser;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ModbusTagDiscreteInput extends ModbusTag {

public static final String ADDRESS_PREFIX = "1x";
public static final Pattern ADDRESS_PATTERN = Pattern.compile("discrete-input:" + ModbusTag.ADDRESS_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("1" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("1x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_PATTERN = Pattern.compile("discrete-input:" + ModbusTag.ADDRESS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("1" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("1x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);

protected static final int REGISTER_MAX_ADDRESS = 65535;

public ModbusTagDiscreteInput(int address, Integer quantity, ModbusDataType dataType) {
super(address, quantity, dataType);
public ModbusTagDiscreteInput(int address, Integer quantity, ModbusDataType dataType, Map<String, String> config) {
super(address, quantity, dataType, config);
}

protected String getAddressStringPrefix() {
Expand Down Expand Up @@ -88,6 +90,6 @@ public static ModbusTagDiscreteInput of(String addressString) {

ModbusDataType dataType = (matcher.group("datatype") != null) ? ModbusDataType.valueOf(matcher.group("datatype")) : ModbusDataType.BOOL;

return new ModbusTagDiscreteInput(address, quantity, dataType);
return new ModbusTagDiscreteInput(address, quantity, dataType, TagConfigParser.parse(addressString));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@

import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException;
import org.apache.plc4x.java.modbus.readwrite.ModbusDataType;
import org.apache.plc4x.java.spi.tag.TagConfigParser;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ModbusTagExtendedRegister extends ModbusTag {

public static final String ADDRESS_PREFIX = "6x";
public static final Pattern ADDRESS_PATTERN = Pattern.compile("extended-register:" + ModbusTag.ADDRESS_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("6" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("6x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_PATTERN = Pattern.compile("extended-register:" + ModbusTag.ADDRESS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("6" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("6x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);

protected static final int REGISTER_MAXADDRESS = 655359999;

protected ModbusTagExtendedRegister(int address, Integer quantity, ModbusDataType dataType) {
super(address, quantity, dataType);
protected ModbusTagExtendedRegister(int address, Integer quantity, ModbusDataType dataType, Map<String, String> config) {
super(address, quantity, dataType, config);
}

protected String getAddressStringPrefix() {
Expand Down Expand Up @@ -89,6 +91,6 @@ public static ModbusTagExtendedRegister of(String addressString) {

ModbusDataType dataType = (matcher.group("datatype") != null) ? ModbusDataType.valueOf(matcher.group("datatype")) : ModbusDataType.INT;

return new ModbusTagExtendedRegister(address, quantity, dataType);
return new ModbusTagExtendedRegister(address, quantity, dataType, TagConfigParser.parse(addressString));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@

import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException;
import org.apache.plc4x.java.modbus.readwrite.ModbusDataType;
import org.apache.plc4x.java.spi.tag.TagConfigParser;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ModbusTagHoldingRegister extends ModbusTag {

public static final String ADDRESS_PREFIX = "4x";
public static final Pattern ADDRESS_PATTERN = Pattern.compile("holding-register:" + ModbusTag.ADDRESS_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("4" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("4x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_PATTERN = Pattern.compile("holding-register:" + ModbusTag.ADDRESS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("4" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("4x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);

protected static final int REGISTER_MAXADDRESS = 65535;

protected ModbusTagHoldingRegister(int address, Integer quantity, ModbusDataType dataType) {
super(address, quantity, dataType);
protected ModbusTagHoldingRegister(int address, Integer quantity, ModbusDataType dataType, Map<String, String> config) {
super(address, quantity, dataType, config);
}

protected String getAddressStringPrefix() {
Expand Down Expand Up @@ -87,7 +89,7 @@ public static ModbusTagHoldingRegister of(String addressString) {

ModbusDataType dataType = (matcher.group("datatype") != null) ? ModbusDataType.valueOf(matcher.group("datatype")) : ModbusDataType.INT;

return new ModbusTagHoldingRegister(address, quantity, dataType);
return new ModbusTagHoldingRegister(address, quantity, dataType, TagConfigParser.parse(addressString));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@

import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException;
import org.apache.plc4x.java.modbus.readwrite.ModbusDataType;
import org.apache.plc4x.java.spi.tag.TagConfigParser;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ModbusTagInputRegister extends ModbusTag {

public static final String ADDRESS_PREFIX = "3x";
public static final Pattern ADDRESS_PATTERN = Pattern.compile("input-register:" + ModbusTag.ADDRESS_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("3" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("3x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN);
public static final Pattern ADDRESS_PATTERN = Pattern.compile("input-register:" + ModbusTag.ADDRESS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("3" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);
public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("3x" + ModbusTag.FIXED_DIGIT_MODBUS_PATTERN + TagConfigParser.TAG_CONFIG_PATTERN);

protected static final int REGISTER_MAXADDRESS = 65535;

protected ModbusTagInputRegister(int address, Integer quantity, ModbusDataType dataType) {
super(address, quantity, dataType);
protected ModbusTagInputRegister(int address, Integer quantity, ModbusDataType dataType, Map<String, String> config) {
super(address, quantity, dataType, config);
}

protected String getAddressStringPrefix() {
Expand Down Expand Up @@ -87,6 +89,6 @@ public static ModbusTagInputRegister of(String addressString) {

ModbusDataType dataType = (matcher.group("datatype") != null) ? ModbusDataType.valueOf(matcher.group("datatype")) : ModbusDataType.INT;

return new ModbusTagInputRegister(address, quantity, dataType);
return new ModbusTagInputRegister(address, quantity, dataType, TagConfigParser.parse(addressString));
}
}
Loading

0 comments on commit 4168452

Please sign in to comment.