Skip to content

Commit

Permalink
Types are matched to S7-definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
codepitbull committed Feb 6, 2025
1 parent 9d5c3b8 commit 6c2e43e
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 107 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.hivemq.edge.adapters.s7;

import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
import com.github.xingshuangs.iot.protocol.s7.service.MultiAddressRead;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import com.github.xingshuangs.iot.protocol.s7.utils.AddressUtil;
import com.hivemq.adapter.sdk.api.data.DataPoint;
import com.hivemq.adapter.sdk.api.factories.DataPointFactory;
import com.hivemq.edge.adapters.s7.config.S7AdapterConfig;
Expand Down Expand Up @@ -33,55 +35,61 @@ public S7Client(final @NotNull EPlcType elpcType, final @NotNull String hostname
this.dataPointFactory = dataPointFactory;
}


public DataPoint readByte(final String address) {
if(log.isTraceEnabled()) {
log.trace("Reading bytes from address {} with count {}", address, 1);
}
return dataPointFactory.create(address, s7PLC.readByte(address, 1)[0]);
}


public DataPoint readBytes(final String address, final int count) {
if(log.isTraceEnabled()) {
log.trace("Reading bytes from address {} with count {}", address, count);
}
return dataPointFactory.create(address, s7PLC.readByte(address, count));
}

public List<DataPoint> read(final @NotNull S7DataType type, final @NotNull List<String> addresses) {
if(log.isTraceEnabled()) {
log.trace("Reading data from addresses {} with type {}", addresses, type);
}
switch (type) {
case BOOL: return combine(dataPointFactory, addresses, s7PLC.readBoolean(addresses));
case BYTE: throw new IllegalArgumentException("Byte data type not supported by this method, use readBytes");
case WORD: return null;
case DWORD: return null;
case LWORD: return null;
case USINT: return combine(dataPointFactory, addresses, s7PLC.readUInt16(addresses));
case UINT: return null;
case BYTE: return addresses.stream().map(address -> dataPointFactory
.create(address, s7PLC.readByte(address)))
.collect(Collectors.toList());
case WORD: return combine(dataPointFactory, addresses, s7PLC.readInt16(addresses));
case DWORD: return combine(dataPointFactory, addresses, s7PLC.readInt32(addresses));
case LWORD: return combine(dataPointFactory, addresses, s7PLC.readInt64(addresses));
case USINT: return addresses.stream().map(address -> dataPointFactory
.create(address, Byte.toUnsignedInt(s7PLC.readByte(address))))
.collect(Collectors.toList());
case UINT: return combine(dataPointFactory, addresses, s7PLC.readUInt16(addresses));
case UDINT: return combine(dataPointFactory, addresses, s7PLC.readUInt32(addresses));
case ULINT: return null;
case SINT: return null;
case ULINT: return addresses.stream()
.map(address -> dataPointFactory.create(address, new BigInteger(Long.toUnsignedString(s7PLC.readInt64(address)))))
.collect(Collectors.toList());
case SINT: return addresses.stream().map(address -> dataPointFactory
.create(address, ((Byte)s7PLC.readByte(address)).shortValue()))
.collect(Collectors.toList());
case INT: return combine(dataPointFactory, addresses, s7PLC.readInt16(addresses));
case DINT: return combine(dataPointFactory, addresses, s7PLC.readInt32(addresses));
case LINT: return combine(dataPointFactory, addresses, s7PLC.readInt64(addresses));
case REAL: return combine(dataPointFactory, addresses, s7PLC.readFloat32(addresses));
case LREAL: return combine(dataPointFactory, addresses, s7PLC.readFloat64(addresses));
case CHAR: return null;
case WCHAR: return null;
case STRING: return combine(dataPointFactory, addresses, addresses.stream().map(s7PLC::readString).collect(Collectors.toList()));
case WSTRING: return null;
case CHAR: return addresses.stream().map(address -> dataPointFactory
.create(address, s7PLC.readByte(address)))
.collect(Collectors.toList());
case WCHAR: return addresses.stream()
.map(address -> {
final byte[] bytes = s7PLC.readByte(address, 2);
final char charValue = (char) ((bytes[0] & 0xff) << 8 | (bytes[1] & 0xff));
return dataPointFactory.create(address, charValue);
})
.collect(Collectors.toList());
case STRING:
case WSTRING: return combine(dataPointFactory, addresses, addresses.stream().map(s7PLC::readString).collect(Collectors.toList()));
case TIME: return combine(dataPointFactory, addresses, addresses.stream().map(s7PLC::readTime).collect(Collectors.toList()));
case LTIME: return null;
case LTIME: return combine(dataPointFactory, addresses, s7PLC.readInt64(addresses));
case DATE: return combine(dataPointFactory, addresses, addresses.stream().map(s7PLC::readDate).collect(Collectors.toList()));
case TOD: return combine(dataPointFactory, addresses, addresses.stream().map(s7PLC::readTimeOfDay).collect(Collectors.toList()));
case LTOD: return null;
case DT: return combine(dataPointFactory, addresses, addresses.stream().map(s7PLC::readDTL).collect(Collectors.toList()));
case LDT: return null;
case DTL: return null;
case ARRAY: return null;
case LTOD: return addresses.stream()
.map(address -> dataPointFactory.create(address, new BigInteger(Long.toUnsignedString(s7PLC.readInt64(address)))))
.collect(Collectors.toList());
case DT: return addresses.stream()
.map(address -> dataPointFactory.create(address, s7PLC.readDate(address)))
.collect(Collectors.toList());
case LDT:return addresses.stream()
.map(address -> dataPointFactory.create(address, new BigInteger(Long.toUnsignedString(s7PLC.readInt64(address)))))
.collect(Collectors.toList());
case DTL: return combine(dataPointFactory, addresses, addresses.stream().map(s7PLC::readDTL).collect(Collectors.toList()));
case ARRAY: throw new IllegalArgumentException("Arrays not supported");
default: {
log.error("Unspported tag-type {} at address {}", type, addresses);
throw new IllegalArgumentException("Unspported tag-type " + type + " at address " + addresses);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,7 @@ public void poll(@NotNull final PollingInput pollingInput, @NotNull final Pollin
S7TagDefinition tagDefinition = tagToRead.getDefinition();
//Every S7 address starts with a % but the iot-communications lib doesn't like it, so we are stripping it.
final String tagAddress = tagDefinition.getAddress().replace("%","");
final DataPoint dataPoint;
if(tagDefinition.getDataType() == S7DataType.BYTE) {
dataPoint = s7Client.readByte(tagAddress);
} else {
dataPoint = s7Client.read(tagDefinition.getDataType(), List.of(tagAddress)).get(0);
}
final DataPoint dataPoint = s7Client.read(tagDefinition.getDataType(), List.of(tagAddress)).get(0);

if(adapterConfig.getS7ToMqttConfig().getPublishChangedDataOnly()) {
if(dataPoints.containsKey(tagAddress)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,16 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class S7AdapterConfig implements ProtocolSpecificAdapterConfig {
import java.util.Objects;

private static final @NotNull String ID_REGEX = "^([a-zA-Z_0-9-_])*$";
public class S7AdapterConfig implements ProtocolSpecificAdapterConfig {

private static final int PORT_MIN = 1;
private static final int PORT_MAX = 65535;

public static final String DEFAULT_S7_PORT = "102";
public static final int DEFAULT_S7_PORT = 102;
public static final String DEFAULT_CONTROLER_TYPE = "S7_300";

public static final String PROPERTY_ID = "id";
public static final String PROPERTY_PORT = "port";
public static final String PROPERTY_HOST = "host";
public static final String PROPERTY_CONTROLLER_TYPE = "controllerType";
Expand All @@ -51,14 +50,14 @@ public enum ControllerType {
SINUMERIK_828D
}

@JsonProperty(value = PROPERTY_PORT, required = true)
@JsonProperty(value = PROPERTY_PORT)
@ModuleConfigField(title = "Port",
description = "The port number on the device to connect to",
required = true,
defaultValue = DEFAULT_S7_PORT,
defaultValue = "" + DEFAULT_S7_PORT,
numberMin = PORT_MIN,
numberMax = PORT_MAX)
private final int port;
private final @NotNull Integer port;

@JsonProperty(value = PROPERTY_HOST, required = true)
@ModuleConfigField(title = "Host",
Expand Down Expand Up @@ -91,27 +90,30 @@ public enum ControllerType {

@JsonProperty(value = PROPERTY_S_7_TO_MQTT, required = true)
@ModuleConfigField(title = "S7 To MQTT Config",
description = "The configuration for a data stream from S7 to MQTT",
required = true)
description = "The configuration for a data stream from S7 to MQTT")
private final @NotNull S7ToMqttConfig s7ToMqttConfig;

@JsonCreator
public S7AdapterConfig(
@JsonProperty(value = PROPERTY_ID, required = true) final @NotNull String id,
@JsonProperty(value = PROPERTY_PORT, required = true) final Integer port,
@JsonProperty(value = PROPERTY_PORT) final Integer port,
@JsonProperty(value = PROPERTY_HOST, required = true) final @NotNull String host,
@JsonProperty(value = PROPERTY_CONTROLLER_TYPE, required = true) final @NotNull ControllerType controllerType,
@JsonProperty(value = PROPERTY_REMOTE_RACK) final @Nullable Integer remoteRack,
@JsonProperty(value = PROPERTY_REMOTE_SLOT) final @Nullable Integer remoteSlot,
@JsonProperty(value = PROPERTY_PDU_LENGTH) final @Nullable Integer pduLength,
@JsonProperty(value = PROPERTY_S_7_TO_MQTT, required = true) final @NotNull S7ToMqttConfig s7ToMqttConfig) {
@JsonProperty(value = PROPERTY_S_7_TO_MQTT) final @Nullable S7ToMqttConfig s7ToMqttConfig) {
this.host = host;
this.controllerType = controllerType;
this.port = port;
this.port = Objects.requireNonNullElse(port, DEFAULT_S7_PORT);
this.remoteRack = remoteRack;
this.remoteSlot = remoteSlot;
this.pduLength = pduLength;
this.s7ToMqttConfig = s7ToMqttConfig;

if (s7ToMqttConfig == null) {
this.s7ToMqttConfig = new S7ToMqttConfig(null, null, null);
} else {
this.s7ToMqttConfig = s7ToMqttConfig;
}
}

public int getPort() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,35 +36,35 @@
public enum S7DataType {
BOOL(Boolean.class, 1, List.of(S7_300, S7_400, S7_1200, S7_1500), "Boolean", "https://support.industry.siemens.com/cs/mdm/109054417?c=46422035979&lc=en-GE"),
BYTE(Byte.class, 8, List.of(S7_300, S7_400, S7_1200, S7_1500), "Byte", "https://support.industry.siemens.com/cs/mdm/109054417?c=56595553163&lc=en-GE"),
WORD(Byte[].class, 16, List.of(S7_300, S7_400, S7_1200, S7_1500), "Word", "https://support.industry.siemens.com/cs/mdm/109054417?c=56595472523&lc=en-GE"),
DWORD(Byte[].class, 32, List.of(S7_300, S7_400, S7_1200, S7_1500), "Double Word", "https://support.industry.siemens.com/cs/mdm/109054417?c=56595322763&lc=en-GE"),
LWORD(Byte[].class, 64, List.of(S7_1500), "Long Word", "https://support.industry.siemens.com/cs/mdm/109054417?c=56595507211&lc=en-GE"),
USINT(Short.class, 8, List.of(S7_1200, S7_1500), "Unsigned Short Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=46521647883&lc=en-GE"),
WORD(Short.class, 16, List.of(S7_300, S7_400, S7_1200, S7_1500), "Word", "https://support.industry.siemens.com/cs/mdm/109054417?c=56595472523&lc=en-GE"),
DWORD(Integer.class, 32, List.of(S7_300, S7_400, S7_1200, S7_1500), "Double Word", "https://support.industry.siemens.com/cs/mdm/109054417?c=56595322763&lc=en-GE"),
LWORD(Long.class, 64, List.of(S7_1500), "Long Word", "https://support.industry.siemens.com/cs/mdm/109054417?c=56595507211&lc=en-GE"),
USINT(Integer.class, 8, List.of(S7_1200, S7_1500), "Unsigned Short Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=46521647883&lc=en-GE"),
UINT(Integer.class, 16, List.of(S7_1200, S7_1500), "Unsigned Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=46521834123&lc=en-GE"),
UDINT(Long.class, 32, List.of(S7_1200, S7_1500), "Unsigned Double Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=46521930763&lc=en-GE"),
ULINT(BigInteger.class, 64, List.of(S7_1500), "Unsigned Long Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=59653945739&lc=en-GE"),
SINT(Byte.class, 8, List.of(S7_1200, S7_1500), "Short Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=68894861835&lc=en-GE"),
SINT(Short.class, 8, List.of(S7_1200, S7_1500), "Short Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=68894861835&lc=en-GE"),
INT(Short.class, 16, List.of(S7_300, S7_400, S7_1200, S7_1500),"Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=63679745547&lc=en-GE"),
DINT(Integer.class, 32, List.of(S7_300, S7_400, S7_1200, S7_1500), "Double Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=46521869963&lc=en-GE"),
LINT(Long.class, 64, List.of(S7_1500), "Long Integer", "https://support.industry.siemens.com/cs/mdm/109054417?c=66825552267&lc=en-GE"),
REAL(Float.class, 32, List.of(S7_300, S7_400, S7_1200, S7_1500), "Real", "https://support.industry.siemens.com/cs/mdm/109054417?c=68826794251&lc=en-GE"),
LREAL(Float.class, 64, List.of(S7_1200, S7_1500), "Long Real", "https://support.industry.siemens.com/cs/mdm/109054417?c=68826903691&lc=en-GE"),
LREAL(Double.class, 64, List.of(S7_1200, S7_1500), "Long Real", "https://support.industry.siemens.com/cs/mdm/109054417?c=68826903691&lc=en-GE"),

CHAR(Character.class, 8, List.of(S7_300, S7_400, S7_1200, S7_1500), "Character", "https://support.industry.siemens.com/cs/mdm/109054417?c=57152595083&lc=en-GE"),
WCHAR(Short.class, 16, List.of(S7_1200, S7_1500), "Wide Character", "https://support.industry.siemens.com/cs/mdm/109054417?c=10488733835&lc=en-GE"),
CHAR(Byte.class, 8, List.of(S7_300, S7_400, S7_1200, S7_1500), "Character", "https://support.industry.siemens.com/cs/mdm/109054417?c=57152595083&lc=en-GE"),
WCHAR(Character.class, 16, List.of(S7_1200, S7_1500), "Wide Character", "https://support.industry.siemens.com/cs/mdm/109054417?c=10488733835&lc=en-GE"),
STRING(String.class, -1, List.of(S7_300, S7_400, S7_1200, S7_1500), "String, 0 to 254 characters only ASCII", "https://support.industry.siemens.com/cs/mdm/109054417?c=63689840011&lc=en-GE"),
WSTRING(String.class, -1, List.of(S7_1200, S7_1500), "Wide String, 0 to 254 characters only Unicode", "https://support.industry.siemens.com/cs/mdm/109054417?c=61472021771&lc=en-GE"), //

TIME(Long.class, 32, List.of(S7_300, S7_400, S7_1200, S7_1500), "IEC Time (ms)", "https://support.industry.siemens.com/cs/mdm/109054417?c=61085966091&lc=en-GE"),
LTIME(BigInteger.class, 64, List.of(S7_1500), "IEC Time (ns)", "https://support.industry.siemens.com/cs/mdm/109054417?c=61410814475&lc=en-GE"),
LTIME(Long.class, 64, List.of(S7_1500), "IEC Time (ns)", "https://support.industry.siemens.com/cs/mdm/109054417?c=61410814475&lc=en-GE"),
//TODO S5TIME https://support.industry.siemens.com/cs/mdm/109054417?c=63689295627&lc=en-GE

DATE(Short.class, 8, List.of(S7_300, S7_400, S7_1200, S7_1500), "IEC Date, since 01-01-1990 (Year-Month-Day)", "https://support.industry.siemens.com/cs/mdm/109054417?c=46522046859&lc=en-GE"),
TOD(Long.class, 32, List.of(S7_300, S7_400, S7_1200, S7_1500), "Time Of Day (hours:minutes:seconds.milliseconds)", "https://support.industry.siemens.com/cs/mdm/109054417?c=64869849355&lc=en-GE"),
LTOD(BigInteger.class, 64, List.of(S7_1500), "Time-of-day (hours:minutes:seconds.nanoseconds)", "https://support.industry.siemens.com/cs/mdm/109054417?c=64869390987&lc=en-GE"),
DT(BigInteger.class, 64, List.of(S7_1500), "Date and time (year-month-day-hour:minute:second:millisecond)", "https://support.industry.siemens.com/cs/mdm/109054417?c=61473284875&lc=en-GE"),
LDT(BigInteger.class, 64, List.of(S7_1500), "Date and time (year-month-day-hour:minute:second:nanoseconds)", "https://support.industry.siemens.com/cs/mdm/109054417?c=71834521483&lc=en-GE"),
DTL(BigInteger.class, 64, List.of(S7_1500), "Date and time (year-month-day-hour:minute:second:nanoseconds)", "https://support.industry.siemens.com/cs/mdm/109054417?c=64682916235&lc=en-GE"),
DT(LocalDate.class, 64, List.of(S7_1500), "Date and time (year-month-day-hour:minute:second:millisecond)", "https://support.industry.siemens.com/cs/mdm/109054417?c=61473284875&lc=en-GE"),
LDT(LocalDateTime.class, 64, List.of(S7_1500), "Date and time (year-month-day-hour:minute:second:nanoseconds)", "https://support.industry.siemens.com/cs/mdm/109054417?c=71834521483&lc=en-GE"),
DTL(LocalDateTime.class, 64, List.of(S7_1500), "Date and time (year-month-day-hour:minute:second:nanoseconds)", "https://support.industry.siemens.com/cs/mdm/109054417?c=64682916235&lc=en-GE"),
ARRAY(Byte[].class, -1, List.of(S7_300, S7_400, S7_1200, S7_1500), "Array of type", "https://support.industry.siemens.com/cs/mdm/109054417?c=52352205963&lc=en-GE");
//RAW_BYTE_ARRAY TODO: it's not an actual type but is there in the old implementation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public static void s7_300() {
S7Client s7Client = new S7Client(eplcType, "172.16.10.53", 102,
eplcType.getRack(), eplcType.getSlot(), eplcType.getPduLength(), DataPointImpl::new);
s7Client.connect();
final DataPoint dataPoint = s7Client.readBytes("IB1", 1);
System.out.println(((byte[])dataPoint.getTagValue())[0]); // => 122
final List<DataPoint> dataPoint = s7Client.read(S7DataType.BYTE, List.of("IB1"));
System.out.println(dataPoint.get(0).getTagValue()); // => 122
s7Client.disconnect();
}

Expand Down
Loading

0 comments on commit 6c2e43e

Please sign in to comment.