diff --git a/nl-common/src/main/java/org/nl/common/exception/ExceptionConstant.java b/nl-common/src/main/java/org/nl/common/exception/ExceptionConstant.java
new file mode 100644
index 0000000..b140ce1
--- /dev/null
+++ b/nl-common/src/main/java/org/nl/common/exception/ExceptionConstant.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.nl.common.exception;
+
+/**
+ * 异常 相关常量
+ *
+ * @author pnoker
+ * @version 2025.9.0
+ * @since 2022.1.0
+ */
+public class ExceptionConstant {
+
+ /**
+ * 公共类实例化错误提示
+ */
+ public static final String UTILITY_CLASS = "Utility class";
+
+ /**
+ * 没有可用的服务
+ */
+ public static final String NO_AVAILABLE_SERVER = "No available server for client";
+
+ /**
+ * 租户, 用户信息不匹配
+ */
+ public static final String NO_AVAILABLE_AUTH = "Tenant, user information does not match";
+
+ private ExceptionConstant() {
+ throw new IllegalStateException(ExceptionConstant.UTILITY_CLASS);
+ }
+}
diff --git a/nl-common/src/main/java/org/nl/common/util/DecodeUtil.java b/nl-common/src/main/java/org/nl/common/util/DecodeUtil.java
new file mode 100644
index 0000000..d3d5bb6
--- /dev/null
+++ b/nl-common/src/main/java/org/nl/common/util/DecodeUtil.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.nl.common.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.nl.common.exception.ExceptionConstant;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.HexFormat;
+
+/**
+ * 编码 相关工具类
+ *
+ * @author pnoker
+ * @version 2025.9.0
+ * @since 2022.1.0
+ */
+@Slf4j
+public class DecodeUtil {
+
+ private DecodeUtil() {
+ throw new IllegalStateException(ExceptionConstant.UTILITY_CLASS);
+ }
+
+ /**
+ * 字节转字符串
+ *
+ * UTF-8
+ *
+ * @param bytes 字节数组
+ * @return 字符串
+ */
+ public static String byteToString(byte[] bytes) {
+ return new String(bytes, StandardCharsets.UTF_8);
+ }
+
+ /**
+ * 字符串转字节
+ *
+ * UTF-8
+ *
+ * @param content 字符串
+ * @return 字节数组
+ */
+ public static byte[] stringToByte(String content) {
+ return content.getBytes(StandardCharsets.UTF_8);
+ }
+
+ /**
+ * 获取 MD5 编码
+ *
+ * @param content 字符串
+ * @return MD5 字符串
+ */
+ public static String md5(String content) {
+ return DigestUtils.md5Hex(content);
+ }
+
+ /**
+ * 获取 MD5 编码
+ *
+ * @param content 字符串
+ * @param salt 盐值
+ * @return MD5 字符串
+ */
+ public static String md5(String content, String salt) {
+ return md5(content + salt);
+ }
+
+ /**
+ * 将字节流进行Base64编码
+ *
+ * @param bytes Byte Array
+ * @return Byte Array
+ */
+ public static byte[] encode(byte[] bytes) {
+ return Base64.getEncoder().encode(bytes);
+ }
+
+ /**
+ * 将字符串进行Base64编码
+ *
+ * @param content 字符串
+ * @return Byte Array
+ */
+ public static byte[] encode(String content) {
+ return encode(stringToByte(content));
+ }
+
+ /**
+ * 必须配合encode使用, 用于encode编码之后解码
+ *
+ * @param bytes Byte Array
+ * @return Byte Array
+ */
+ public static byte[] decode(byte[] bytes) {
+ return Base64.getDecoder().decode(bytes);
+ }
+
+ /**
+ * 必须配合encode使用, 用于encode编码之后解码
+ *
+ * @param content 字符串
+ * @return Byte Array
+ */
+ public static byte[] decode(String content) {
+ return decode(stringToByte(content));
+ }
+
+ /**
+ * 将字符串进行16进制编码
+ *
+ * @param content 字符串
+ * @return String
+ */
+ public static String enHexCode(String content) {
+ return HexFormat.of().formatHex((stringToByte(content)));
+ }
+
+ /**
+ * 必须配合enHexCode使用, 用于enHexCode编码之后解码
+ *
+ * @param content 字符串
+ * @return Byte Array
+ */
+ public static byte[] deHexCode(String content) {
+ return HexFormat.of().parseHex(content);
+ }
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/PlcS7ProtocolDriverImpl.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/PlcS7ProtocolDriverImpl.java
new file mode 100644
index 0000000..82c60c0
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/PlcS7ProtocolDriverImpl.java
@@ -0,0 +1,167 @@
+package org.nl.iot.core.driver.protocol.plcs7;
+
+import jakarta.annotation.Resource;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.nl.common.exception.CommonException;
+import org.nl.iot.core.driver.bo.AttributeBO;
+import org.nl.iot.core.driver.entity.RValue;
+import org.nl.iot.core.driver.entity.WValue;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.PlcS7PointVariable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Connector;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializer;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.factory.S7ConnectorFactory;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.factory.S7SerializerFactory;
+import org.nl.iot.core.driver.service.DriverCustomService;
+import org.nl.iot.modular.iot.entity.IotConfig;
+import org.nl.iot.modular.iot.entity.IotConnect;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ *
+ * @author: lyd
+ * @date: 2026/3/3
+ */
+@Slf4j
+@Service
+public class PlcS7ProtocolDriverImpl implements DriverCustomService {
+
+ /**
+ * Plc Connector Map
+ * 仅供参考
+ */
+ private Map connectMap;
+ @Override
+ public void initial() {
+ connectMap = new ConcurrentHashMap<>(16);
+ }
+
+ @Override
+ public void schedule() {
+
+ }
+
+ @Override
+ public RValue read(Map driverConfig, Map pointConfig, IotConnect connect, IotConfig config) {
+ /*
+ * PLC S7 数据读取逻辑
+ *
+ * 提示: 此处逻辑仅供参考, 请务必结合实际应用场景进行修改。
+ * 该方法用于从 PLC S7 设备中读取指定点位的数据。
+ * 1. 获取设备的 S7 连接器。
+ * 2. 加锁以确保线程安全。
+ * 3. 使用 S7 序列化器读取点位数据。
+ * 4. 将读取到的数据封装为 RValue 对象返回。
+ * 5. 捕获并记录异常, 确保锁在 finally 块中释放。
+ */
+ log.debug("Plc S7 Read, device: {}, point: {}", driverConfig, pointConfig);
+ MyS7Connector myS7Connector = getS7Connector(connect.getId().toString(), driverConfig);
+
+ try {
+ myS7Connector.lock.writeLock().lock();
+ S7Serializer serializer = S7SerializerFactory.buildSerializer(myS7Connector.getConnector());
+ String type = pointConfig.get("data_type").getValueByClass(String.class);
+ PlcS7PointVariable plcs7PointVariable = getPointVariable(pointConfig, type);
+ return new RValue(config, connect, String.valueOf(serializer.dispense(plcs7PointVariable)));
+ } catch (Exception e) {
+ log.error("Plc S7 Read Error: {}", e.getMessage());
+ return null;
+ } finally {
+ myS7Connector.lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public Boolean write(Map driverConfig, Map pointConfig, IotConnect device, IotConfig point, WValue wValue) {
+ return null;
+ }
+
+ /**
+ * 获取 PLC S7 连接器
+ *
+ * 该方法用于从缓存中获取指定设备的 S7 连接器。如果缓存中不存在该设备的连接器,
+ * 则会根据驱动配置信息创建一个新的连接器, 并将其缓存以供后续使用。
+ *
+ * 连接器创建过程中, 会从驱动配置中获取主机地址和端口号, 并初始化读写锁以确保线程安全。
+ * 如果连接器创建失败, 将抛出 {@link CommonException} 异常。
+ *
+ * @param connectId 设备ID, 用于标识唯一的设备连接器
+ * @param driverConfig 驱动配置信息, 包含连接 PLC 所需的主机地址和端口号等参数
+ * @return 返回与设备ID对应的 {@link MyS7Connector} 对象, 包含 S7 连接器和读写锁
+ * @throws CommonException 如果连接器创建失败, 抛出此异常
+ */
+ private MyS7Connector getS7Connector(String connectId, Map driverConfig) {
+ MyS7Connector myS7Connector = connectMap.get(connectId);
+ if (Objects.isNull(myS7Connector)) {
+ myS7Connector = new MyS7Connector();
+
+ log.debug("Plc S7 Connection Info {}", driverConfig);
+ try {
+ S7Connector s7Connector = S7ConnectorFactory.buildTCPConnector()
+ .withHost(driverConfig.get("host").getValueByClass(String.class))
+ .withPort(driverConfig.get("port").getValueByClass(Integer.class))
+ .build();
+ myS7Connector.setLock(new ReentrantReadWriteLock());
+ myS7Connector.setConnector(s7Connector);
+ } catch (Exception e) {
+ throw new CommonException("new s7connector fail" + e.getMessage());
+ }
+ connectMap.put(connectId, myS7Connector);
+ }
+ return myS7Connector;
+ }
+
+ /**
+ * 获取 PLC S7 点位变量信息
+ *
+ * 该方法用于从点位配置中提取 PLC S7 点位变量信息, 并封装为 {@link PlcS7PointVariable} 对象。
+ * 点位配置中应包含以下关键属性:
+ * - dbNum: 数据块编号
+ * - byteOffset: 字节偏移量
+ * - bitOffset: 位偏移量
+ * - blockSize: 数据块大小
+ * - type: 点位数据类型
+ *
+ * 如果点位配置中缺少上述任一属性, 将抛出 {@link NullPointerException} 异常。
+ *
+ * @param pointConfig 点位配置信息, 包含点位变量的相关属性
+ * @param type 点位数据类型, 用于标识点位数据的类型
+ * @return 返回封装好的 {@link PlcS7PointVariable} 对象, 包含点位变量的详细信息
+ * @throws NullPointerException 如果点位配置中缺少必要的属性, 抛出此异常
+ */
+ private PlcS7PointVariable getPointVariable(Map pointConfig, String type) {
+ log.debug("Plc S7 Point Attribute Config {}", pointConfig);
+ return new PlcS7PointVariable(
+ pointConfig.get("dbNum").getValueByClass(Integer.class),
+ pointConfig.get("byteOffset").getValueByClass(Integer.class),
+ pointConfig.get("bitOffset").getValueByClass(Integer.class),
+ pointConfig.get("blockSize").getValueByClass(Integer.class),
+ type);
+ }
+
+ /**
+ * MyS7Connector 内部类
+ *
+ * 该类用于封装与 PLC S7 连接相关的信息, 包括读写锁和 S7 连接器。
+ * 读写锁 {@link ReentrantReadWriteLock} 用于确保在多线程环境下对 S7 连接器的操作是线程安全的。
+ * S7 连接器 {@link S7Connector} 用于与 PLC S7 设备进行通信。
+ *
+ * 该类提供了无参构造函数和全参构造函数, 并使用了 Lombok 注解自动生成 getter 和 setter 方法。
+ */
+ @Getter
+ @Setter
+ @NoArgsConstructor
+ @AllArgsConstructor
+ private static class MyS7Connector {
+ private ReentrantReadWriteLock lock;
+ private S7Connector connector;
+ }
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/PlcS7PointVariable.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/PlcS7PointVariable.java
new file mode 100644
index 0000000..5a1e1a4
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/PlcS7PointVariable.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * @author pnoker
+ * @version 2025.9.0
+ * @since 2022.1.0
+ */
+@Getter
+@Setter
+public class PlcS7PointVariable {
+ private int dbNum;
+ private int byteOffset;
+ private int bitOffset;
+ private int size;
+ private S7Type type;
+ private Class> fieldType;
+
+ public PlcS7PointVariable(int dbNum, int byteOffset, int bitOffset, int size, String s7Type) {
+ this.dbNum = dbNum;
+ this.byteOffset = byteOffset;
+ this.bitOffset = bitOffset;
+ this.size = size;
+ getS7TypeAndType(s7Type);
+
+ }
+
+ private void getS7TypeAndType(String s7Type) {
+ switch (s7Type) {
+ case "bool":
+ this.type = S7Type.BOOL;
+ this.fieldType = Boolean.class;
+ break;
+ case "byte":
+ this.type = S7Type.BYTE;
+ this.fieldType = Byte.class;
+ break;
+ case "int":
+ this.type = S7Type.INT;
+ this.fieldType = Short.class;
+ break;
+ case "dint":
+ this.type = S7Type.DINT;
+ this.fieldType = Long.class;
+ break;
+ case "word":
+ this.type = S7Type.WORD;
+ this.fieldType = Integer.class;
+ break;
+ case "dword":
+ this.type = S7Type.DWORD;
+ this.fieldType = Long.class;
+ break;
+ case "real":
+ this.type = S7Type.REAL;
+ this.fieldType = Float.class;
+ break;
+ case "date":
+ this.type = S7Type.DATE;
+ this.fieldType = Date.class;
+ break;
+ case "time":
+ this.type = S7Type.TIME;
+ this.fieldType = Long.class;
+ break;
+ case "datetime":
+ this.type = S7Type.DATE_AND_TIME;
+ this.fieldType = Long.class;
+ break;
+ default:
+ this.type = S7Type.STRING;
+ this.fieldType = Boolean.class;
+ break;
+ }
+ }
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/S7Exception.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/S7Exception.java
new file mode 100644
index 0000000..ba47783
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/S7Exception.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7;
+
+/**
+ * The Class S7Exception is an exception related to S7 Communication
+ *
+ * @author Thomas Rudin
+ */
+public final class S7Exception extends RuntimeException {
+
+ /**
+ * The Constant serialVersionUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Instantiates a new s7 exception.
+ */
+ public S7Exception() {
+ }
+
+ /**
+ * Instantiates a new s7 exception.
+ *
+ * @param message the message
+ */
+ public S7Exception(final String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new s7 exception.
+ *
+ * @param message the message
+ * @param cause the cause
+ */
+ public S7Exception(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Instantiates a new s7 exception.
+ *
+ * @param cause the cause
+ */
+ public S7Exception(final Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/DaveArea.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/DaveArea.java
new file mode 100644
index 0000000..2a7eefd
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/DaveArea.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api;
+
+/**
+ * @author Thomas Rudin
+ */
+public enum DaveArea {
+ ANALOGINPUTS200(6), // System info of 200 family
+ ANALOGOUTPUTS200(7), // System flags of 200 family
+ COUNTER(28), // analog inputs of 200 family
+ COUNTER200(30), // analog outputs of 200 family
+ DB(0x84), // Peripheral I/O
+ DI(0x85),
+ FLAGS(0x83),
+ INPUTS(0x81),
+ LOCAL(0x86), // data blocks
+ OUTPUTS(0x82), // instance data blocks
+ P(0x80), // not tested
+ SYSTEM_INFO(3), // local of caller
+ SYSTEM_FLAGS(5), // S7 counters
+ TIMER(29), // S7 timers
+ TIMER200(31), // IEC counters (200 family)
+ V(0x87); // IEC timers (200 family)
+
+ /**
+ * Function Code
+ */
+ final int code;
+
+ DaveArea(final int code) {
+ this.code = code;
+ }
+
+ /**
+ * Returns the function code as associated
+ *
+ * @return code
+ */
+ public int getCode() {
+ return this.code;
+ }
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Connector.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Connector.java
new file mode 100644
index 0000000..6fb9c32
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Connector.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api;
+
+import java.io.Closeable;
+
+/**
+ * @author Thomas Rudin
+ */
+public interface S7Connector extends Closeable {
+ /**
+ * Reads an area
+ *
+ * @param area DaveArea
+ * @param areaNumber Area Number
+ * @param bytes Byte Number
+ * @param offset Byte Offset
+ * @return Byte Array
+ */
+ public byte[] read(DaveArea area, int areaNumber, int bytes, int offset);
+
+ /**
+ * Writes an area
+ *
+ * @param area DaveArea
+ * @param areaNumber Area Number
+ * @param offset Byte Offset
+ * @param buffer Write Byte Array
+ */
+ public void write(DaveArea area, int areaNumber, int offset, byte[] buffer);
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Serializable.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Serializable.java
new file mode 100644
index 0000000..5db3e52
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Serializable.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api;
+
+/**
+ * The Interface S7Serializable API
+ *
+ * @author Thomas Rudin
+ */
+public interface S7Serializable {
+
+ /**
+ * Extracts a java type from a byte buffer.
+ *
+ * @param the generic type
+ * @param targetClass the target class
+ * @param buffer the buffer
+ * @param byteOffset the byte offset
+ * @param bitOffset the bit offset
+ * @return the t
+ */
+ public T extract(Class targetClass, byte[] buffer, int byteOffset, int bitOffset);
+
+ /**
+ * Returns the S7-Type.
+ *
+ * @return the s7 type
+ */
+ public S7Type getS7Type();
+
+ /**
+ * Returns the size of the s7 type bytes.
+ *
+ * @return the size in bits
+ */
+ public int getSizeInBits();
+
+ /**
+ * Returns the size of the s7 type bytes.
+ *
+ * @return the size in bytes
+ */
+ public int getSizeInBytes();
+
+ /**
+ * Inserts a Java Object to the byte buffer.
+ *
+ * @param javaType the java type
+ * @param buffer the buffer
+ * @param byteOffset the byte offset
+ * @param bitOffset the bit offset
+ * @param size the size
+ */
+ public void insert(Object javaType, byte[] buffer, int byteOffset, int bitOffset, int size);
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Serializer.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Serializer.java
new file mode 100644
index 0000000..0284d7a
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Serializer.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api;
+
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.PlcS7PointVariable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.S7Exception;
+
+/**
+ * @author Thomas Rudin
+ */
+public interface S7Serializer {
+
+ /**
+ * Dispenses an Object from the mapping of the Datablock.
+ *
+ * @param the generic type
+ * @param beanClass the bean class
+ * @param dbNum the db num
+ * @param byteOffset the byte offset
+ * @return the t
+ * @throws S7Exception the s7 exception
+ */
+ T dispense(Class beanClass, int dbNum, int byteOffset) throws S7Exception;
+
+ /**
+ * Dispense.
+ *
+ * @param the generic type
+ * @param beanClass the bean class
+ * @param dbNum the db num
+ * @param byteOffset the byte offset
+ * @param blockSize the block size
+ * @return the t
+ * @throws S7Exception the s7 exception
+ */
+ T dispense(Class beanClass, int dbNum, int byteOffset, int blockSize) throws S7Exception;
+
+
+ /**
+ * Dispense.
+ *
+ * @param plcs7PointVariable the point
+ * @return Object
+ * @throws S7Exception the s7 exception
+ */
+ Object dispense(PlcS7PointVariable plcs7PointVariable) throws S7Exception;
+
+ /**
+ * Stores an Object to the Datablock.
+ *
+ * @param bean the bean
+ * @param dbNum the db num
+ * @param byteOffset the byte offset
+ */
+ void store(Object bean, int dbNum, int byteOffset);
+
+}
\ No newline at end of file
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Type.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Type.java
new file mode 100644
index 0000000..8a509e1
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/S7Type.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter.*;
+
+/**
+ * Type of the Address
+ *
+ * @author Thomas Rudin Libnodave:
+ * libnodave.sourceforge.net
+ */
+public enum S7Type {
+ /**
+ * Boolean type
+ */
+ BOOL(BitConverter.class, 0, 1),
+
+ /**
+ * Byte type
+ */
+ BYTE(ByteConverter.class, 1, 0),
+
+ /**
+ * A INT-type
+ */
+ INT(ShortConverter.class, 2, 0),
+
+ /**
+ * A DINT-type (same as DWORD-type)
+ */
+ DINT(LongConverter.class, 4, 0),
+
+ /**
+ * A Word-type (same as int-type)
+ */
+ WORD(IntegerConverter.class, 2, 0),
+ /**
+ * Double word
+ */
+ DWORD(LongConverter.class, 4, 0),
+
+ /**
+ * Real-type, corresponds to float or double
+ */
+ REAL(RealConverter.class, 4, 0),
+
+ /**
+ * String type, size must be specified manually
+ */
+ STRING(StringConverter.class, 2, 0),
+
+ /**
+ * Simple Date with 2 bytes in length
+ */
+ DATE(DateConverter.class, 2, 0),
+
+ /**
+ * Time-type, 4 bytes in length, number of millis
+ */
+ TIME(TimeConverter.class, 4, 0),
+
+ /**
+ * Full Date and time format with precision in milliseconds
+ */
+ DATE_AND_TIME(DateAndTimeConverter.class, 8, 0),
+
+ /**
+ * Structure type
+ */
+ STRUCT(StructConverter.class, 0, 0);
+
+ private final int byteSize;
+ private final int bitSize;
+
+ private final Class extends S7Serializable> serializer;
+
+ /**
+ * Enum Constructor
+ *
+ * @param serializer S7Serializable
+ * @param byteSize A Byte Size
+ * @param bitSize A bit Size
+ */
+ S7Type(final Class extends S7Serializable> serializer, final int byteSize, final int bitSize) {
+ this.serializer = serializer;
+ this.bitSize = bitSize;
+ this.byteSize = byteSize;
+ }
+
+ public int getBitSize() {
+ return this.bitSize;
+ }
+
+ public int getByteSize() {
+ return this.byteSize;
+ }
+
+ public Class extends S7Serializable> getSerializer() {
+ return this.serializer;
+ }
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/SiemensPLCS.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/SiemensPLCS.java
new file mode 100644
index 0000000..b0f8ca0
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/SiemensPLCS.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api;
+
+/**
+ * @author pnoker
+ * @version 2025.9.0
+ * @since 2022.1.0
+ */
+public enum SiemensPLCS {
+
+ /**
+ * S200
+ */
+ S_200,
+
+ /**
+ * S200Smart
+ */
+ S_200_SMART,
+
+ /**
+ * except the 200 series
+ */
+ S_NON_200,
+
+ /**
+ * S300
+ */
+ S_300,
+
+ /**
+ * S400
+ */
+ S_400,
+
+ /**
+ * S1200
+ */
+ S_1200,
+
+ /**
+ * S1500
+ */
+ S_1500,
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/annotation/Array.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/annotation/Array.java
new file mode 100644
index 0000000..069e573
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/annotation/Array.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation for array-declaration
+ *
+ * @author Thomas Rudin
+ */
+@Target(value = {ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Array {
+ int size();
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/annotation/Datablock.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/annotation/Datablock.java
new file mode 100644
index 0000000..f7e37f1
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/annotation/Datablock.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation for a datablock
+ *
+ * @author Thomas Rudin
+ */
+@Target(value = {ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Datablock {
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/annotation/S7Variable.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/annotation/S7Variable.java
new file mode 100644
index 0000000..7a143ac
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/annotation/S7Variable.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.annotation;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+import java.lang.annotation.*;
+
+/**
+ * Defines an Offset in a DB
+ *
+ * @author Thomas Rudin
+ */
+@Target(value = {ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface S7Variable {
+ /**
+ * The size of the array
+ *
+ * @return Size
+ */
+ int arraySize() default 1;
+
+ /**
+ * The bit offset, if any
+ *
+ * @return Offset
+ */
+ int bitOffset() default 0;
+
+ /**
+ * The Byte Offset
+ *
+ * @return Offset
+ */
+ int byteOffset();
+
+ /**
+ * The specified size (for String)
+ *
+ * @return Size
+ */
+ int size() default 0;
+
+ /**
+ * The corresponding S7 Type
+ *
+ * @return S7Type
+ */
+ S7Type type();
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/factory/S7ConnectorFactory.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/factory/S7ConnectorFactory.java
new file mode 100644
index 0000000..f8a122a
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/factory/S7ConnectorFactory.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.factory;
+
+import org.nl.common.exception.ExceptionConstant;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Connector;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.SiemensPLCS;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.S7TCPConnection;
+
+/**
+ * S7 connector factory, currently only for TCP connections
+ *
+ * @author Thomas Rudin
+ */
+public class S7ConnectorFactory {
+
+ private S7ConnectorFactory() {
+ throw new IllegalStateException(ExceptionConstant.UTILITY_CLASS);
+ }
+
+ /**
+ * @param type choose a siemens plc type to build a tcp connector.
+ * @return returns a new TCP connection builder
+ */
+ public static TCPConnectionBuilder buildTCPConnector(SiemensPLCS type) {
+ return new TCPConnectionBuilder(type);
+ }
+
+ public static TCPConnectionBuilder buildTCPConnector() {
+ return new TCPConnectionBuilder(SiemensPLCS.S_NON_200);
+ }
+
+ /**
+ * TCP Connection builder
+ */
+ public static class TCPConnectionBuilder {
+
+ private final SiemensPLCS plcsType;
+ private String host;
+ private int rack = 0;
+ private int slot = 2;
+ private int port = 102;
+ private int timeout = 2000;
+
+ TCPConnectionBuilder(SiemensPLCS type) {
+ this.plcsType = type;
+ }
+
+ /**
+ * Builds a connection with given params
+ *
+ * @return S7Connector
+ */
+ public S7Connector build() {
+ return new S7TCPConnection(this.host, this.rack, this.slot, this.port, this.timeout, this.plcsType);
+ }
+
+ /**
+ * use hostname/ip
+ *
+ * @param host Host
+ * @return TCPConnectionBuilder
+ */
+ public TCPConnectionBuilder withHost(final String host) {
+ this.host = host;
+ return this;
+ }
+
+ /**
+ * use port, default is 102
+ *
+ * @param port Port
+ * @return TCPConnectionBuilder
+ */
+ public TCPConnectionBuilder withPort(final int port) {
+ this.port = port;
+ return this;
+ }
+
+ /**
+ * use rack, default is 0
+ *
+ * @param rack Rack
+ * @return TCPConnectionBuilder
+ */
+ public TCPConnectionBuilder withRack(final int rack) {
+ this.rack = rack;
+ return this;
+ }
+
+ /**
+ * use slot, default is 2
+ *
+ * @param slot Slot
+ * @return TCPConnectionBuilder
+ */
+ public TCPConnectionBuilder withSlot(final int slot) {
+ this.slot = slot;
+ return this;
+ }
+
+ /**
+ * use timeout, default is 2000
+ *
+ * @param timeout Timeout
+ * @return TCPConnectionBuilder
+ */
+ public TCPConnectionBuilder withTimeout(final int timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/factory/S7SerializerFactory.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/factory/S7SerializerFactory.java
new file mode 100644
index 0000000..45eff4d
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/factory/S7SerializerFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.factory;
+
+import org.nl.common.exception.ExceptionConstant;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Connector;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializer;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.S7SerializerImpl;
+
+/**
+ * S7 Serializer factory
+ *
+ * @author Thomas Rudin
+ */
+public class S7SerializerFactory {
+
+ private S7SerializerFactory() {
+ throw new IllegalStateException(ExceptionConstant.UTILITY_CLASS);
+ }
+
+ /**
+ * Builds a new serializer with given connector
+ *
+ * @param connector the connector to use
+ * @return a serializer instance
+ */
+ public static S7Serializer buildSerializer(final S7Connector connector) {
+ return new S7SerializerImpl(connector);
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/S7BaseConnection.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/S7BaseConnection.java
new file mode 100644
index 0000000..bddc2de
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/S7BaseConnection.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.DaveArea;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Connector;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave.Nodave;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave.S7Connection;
+
+/**
+ * Base connection implementation for the S7 PLC communication using the Libnodave library.
+ * Libnodave is an open-source library for communicating with Siemens S7 PLCs.
+ * For more information, visit: http://libnodave.sourceforge.net/
+ *
+ * @author Thomas Rudin
+ */
+public abstract class S7BaseConnection implements S7Connector {
+
+ /**
+ * The Constant PROPERTY_AREA.
+ */
+ public static final String PROPERTY_AREA = "area";
+ /**
+ * The Constant PROPERTY_AREANUMBER.
+ */
+ public static final String PROPERTY_AREANUMBER = "areanumber";
+ /**
+ * The Constant PROPERTY_BYTES.
+ */
+ public static final String PROPERTY_BYTES = "bytes";
+ /**
+ * The Constant PROPERTY_OFFSET.
+ */
+ public static final String PROPERTY_OFFSET = "offset";
+ /**
+ * The Constant MAX_SIZE.
+ */
+ private static final int MAX_SIZE = 96;
+ /**
+ * The dc.
+ */
+ private S7Connection dc;
+
+ /**
+ * Checks the Result.
+ *
+ * @param libnodaveResult the libnodave result
+ */
+ public static void checkResult(final int libnodaveResult) {
+ if (libnodaveResult != Nodave.RESULT_OK) {
+ final String msg = Nodave.strerror(libnodaveResult);
+ throw new IllegalArgumentException("Result: " + msg);
+ }
+ }
+
+ /**
+ * Dump data
+ *
+ * @param b the byte stream
+ */
+ protected static void dump(final byte[] b) {
+ for (final byte element : b) {
+ System.out.print(Integer.toHexString(element & 0xFF) + ",");
+ }
+ }
+
+ /**
+ * Initialize the connection
+ *
+ * @param dc the connection instance
+ */
+ protected void init(final S7Connection dc) {
+ this.dc = dc;
+ }
+
+ @Override
+ public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset) {
+ if (bytes > MAX_SIZE) {
+ final byte[] ret = new byte[bytes];
+
+ final byte[] currentBuffer = this.read(area, areaNumber, MAX_SIZE, offset);
+ System.arraycopy(currentBuffer, 0, ret, 0, currentBuffer.length);
+
+ final byte[] nextBuffer = this.read(area, areaNumber, bytes - MAX_SIZE, offset + MAX_SIZE);
+ System.arraycopy(nextBuffer, 0, ret, currentBuffer.length, nextBuffer.length);
+
+ return ret;
+ } else {
+ final byte[] buffer = new byte[bytes];
+ final int ret = this.dc.readBytes(area, areaNumber, offset, bytes, buffer);
+
+ checkResult(ret);
+ return buffer;
+ }
+ }
+
+
+ @Override
+ public synchronized void write(final DaveArea area, final int areaNumber, final int offset, final byte[] buffer) {
+ if (buffer.length > MAX_SIZE) {
+ // Split buffer
+ final byte[] subBuffer = new byte[MAX_SIZE];
+ final byte[] nextBuffer = new byte[buffer.length - subBuffer.length];
+
+ System.arraycopy(buffer, 0, subBuffer, 0, subBuffer.length);
+ System.arraycopy(buffer, MAX_SIZE, nextBuffer, 0, nextBuffer.length);
+
+ this.write(area, areaNumber, offset, subBuffer);
+ this.write(area, areaNumber, offset + subBuffer.length, nextBuffer);
+ } else {
+ // Size fits
+ final int ret = this.dc.writeBytes(area, areaNumber, offset, buffer.length, buffer);
+ // Check return-value
+ checkResult(ret);
+ }
+ }
+
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/S7TCPConnection.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/S7TCPConnection.java
new file mode 100644
index 0000000..457c163
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/S7TCPConnection.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.S7Exception;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.DaveArea;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.SiemensPLCS;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave.Nodave;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave.PLCinterface;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave.TCPConnection;
+
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+/**
+ * TCP_Connection to a S7 PLC
+ *
+ * 参考: http://libnodave.sourceforge.net
+ *
+ * @author Thomas Rudin
+ */
+public final class S7TCPConnection extends S7BaseConnection {
+
+ /**
+ * The Host to connect to
+ */
+ private final String host;
+ /**
+ * The port to connect to
+ */
+ private final int port;
+ /**
+ * Rack number
+ */
+ private final int rack;
+ /**
+ * Slot number
+ */
+ private final int slot;
+ /**
+ * Timeout number
+ */
+ private final int timeout;
+ /**
+ * To connect device type,such as S200
+ */
+ private final SiemensPLCS siemensPLCS;
+ /**
+ * The Connection
+ */
+ private TCPConnection tcpConnection;
+ /**
+ * The Interface
+ */
+ private PLCinterface plCinterface;
+ /**
+ * The Socket
+ */
+ private Socket socket;
+
+ /**
+ * Creates a new Instance to the given host, rack, slot and port
+ *
+ * @param host Host
+ * @param rack Rack
+ * @param slot Slot
+ * @param port Port
+ * @param timeout Timeout
+ * @param siemensPLCS SiemensPLCS
+ * @throws S7Exception S7Exception
+ */
+ public S7TCPConnection(final String host, final int rack, final int slot, final int port, final int timeout, final SiemensPLCS siemensPLCS) throws S7Exception {
+ this.host = host;
+ this.rack = rack;
+ this.slot = slot;
+ this.port = port;
+ this.timeout = timeout;
+ this.siemensPLCS = siemensPLCS;
+ this.setupSocket();
+ }
+
+ @Override
+ public void close() {
+ try {
+ this.socket.close();
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Sets up the socket
+ */
+ private void setupSocket() {
+ try {
+ this.socket = new Socket();
+ this.socket.setSoTimeout(2000);
+ this.socket.connect(new InetSocketAddress(this.host, this.port), this.timeout);
+
+ //select the plc interface protocol by the plcsType
+ int protocol;
+ switch (this.siemensPLCS) {
+ case S_200:
+ protocol = Nodave.PROTOCOL_ISOTCP243;
+ break;
+ case S_NON_200:
+ case S_300:
+ case S_400:
+ case S_1200:
+ case S_1500:
+ case S_200_SMART:
+ default:
+ protocol = Nodave.PROTOCOL_ISOTCP;
+ break;
+ }
+ this.plCinterface = new PLCinterface(this.socket.getOutputStream(), this.socket.getInputStream(), "IF1",
+ DaveArea.LOCAL.getCode(), // TODO Local MPI-Address?
+ protocol);
+
+ this.tcpConnection = new TCPConnection(this.plCinterface, this.rack, this.slot);
+ final int res = this.tcpConnection.connectPLC();
+ checkResult(res);
+
+ super.init(this.tcpConnection);
+ } catch (final Exception e) {
+ throw new S7Exception("constructor", e);
+ }
+
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/Nodave.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/Nodave.java
new file mode 100644
index 0000000..f341224
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/Nodave.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/*
+ Part of Libnodave, a free communication libray for Siemens S7
+
+ (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005.
+
+ Libnodave is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ Libnodave is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave;
+
+/**
+ * @author Thomas Rudin
+ */
+public final class Nodave {
+ public final static int MAX_RAW_LEN = 2048;
+ public final static int MPIReachable = 0x30;
+ public final static int MPIunused = 0x10;
+ public final static int OrderCodeSize = 21;
+
+ public final static int PartnerListSize = 126;
+
+ public final static int PROTOCOL_ISOTCP = 4;
+ public final static int PROTOCOL_ISOTCP243 = 5;
+ public final static int PROTOCOL_MPI_IBH = 223; // MPI with IBH NetLink MPI
+ // to ethernet gateway
+ public final static int PROTOCOL_MPI_NLPRO = 230; // MPI with IBH NetLink
+ // MPI to ethernet
+ // gateway
+ public final static int PROTOCOL_NLPRO = 230; // MPI with IBH NetLink MPI to
+ // ethernet gateway
+ // to ethernet gateway
+ public final static int PROTOCOL_PPI_IBH = 224; // PPI with IBH NetLink MPI
+
+ public final static int RESULT_ADDRESS_OUT_OF_RANGE = 5;
+ /* means the write data size doesn't fit item size */
+ public final static int RESULT_CANNOT_EVALUATE_PDU = -123;
+ public final static int RESULT_CPU_RETURNED_NO_DATA = -124;
+ public final static int RESULT_EMPTY_RESULT_ERROR = -126;
+
+ public final static int RESULT_EMPTY_RESULT_SET_ERROR = -127;
+
+ public final static int RESULT_ITEM_NOT_AVAILABLE = 10;
+ /* means a a piece of data is not available in the CPU, e.g. */
+ /* when trying to read a non existing DB */
+ /* CPU tells it doesn't support to read a bit block with a */
+ /* length other than 1 bit. */
+ public final static int RESULT_ITEM_NOT_AVAILABLE200 = 3;
+ /* means a a piece of data is not available in the CPU, e.g. */
+ /* when trying to read a non existing DB or bit bloc of length<>1 */
+ /* This code seems to be specific to 200 family. */
+ /* CPU tells there is no peripheral at address */
+ public final static int RESULT_MULTIPLE_BITS_NOT_SUPPORTED = 6;
+ public final static int RESULT_NO_PERIPHERAL_AT_ADDRESS = 1;
+
+ public final static int RESULT_OK = 0; /* means all ok */
+ public final static int RESULT_SHORT_PACKET = -1024;
+ public final static int RESULT_TIMEOUT = -1025;
+ public final static int RESULT_UNEXPECTED_FUNC = -128;
+ public final static int RESULT_UNKNOWN_DATA_UNIT_SIZE = -129;
+
+ public final static int RESULT_UNKNOWN_ERROR = -125;
+ /* means the data address is beyond the CPUs address range */
+ public final static int RESULT_WRITE_DATA_SIZE_MISMATCH = 7;
+
+ private Nodave() {
+ // Not needed because of utility class
+ }
+
+ public static float BEFloat(final byte[] b, final int pos) {
+ int i = 0;
+ // System.out.println("pos" + pos);
+
+ i |= Nodave.USByte(b, pos);
+ i <<= 8;
+ i |= Nodave.USByte(b, pos + 1);
+ i <<= 8;
+ i |= Nodave.USByte(b, pos + 2);
+ i <<= 8;
+ i |= Nodave.USByte(b, pos + 3);
+ final float f = Float.intBitsToFloat(i);
+ return (f);
+ }
+
+ public static byte[] bswap_16(int a) {
+ final byte[] b = new byte[2];
+ b[1] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[0] = (byte) (a & 0xff);
+ return b;
+ }
+
+ public static byte[] bswap_32(int a) {
+ final byte[] b = new byte[4];
+ b[3] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[2] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[1] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[0] = (byte) (a & 0xff);
+ return b;
+ }
+
+ public static byte[] bswap_32(long a) {
+ final byte[] b = new byte[4];
+ b[3] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[2] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[1] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[0] = (byte) (a & 0xff);
+ return b;
+ }
+
+ /**
+ * This doesn't swap anything, but the name fits into the series
+ *
+ * @param a value
+ * @return Byte Array
+ */
+ public static byte[] bswap_8(final int a) {
+ final byte[] b = new byte[1];
+ b[0] = (byte) (a & 0xff);
+ return b;
+ }
+
+ /**
+ * Dumps len hex codes from byte array mem beginning at index start
+ *
+ * @param text Text
+ * @param mem Mem
+ * @param start Start
+ * @param len Length
+ */
+ public static void dump(final String text, final byte[] mem, final int start, final int len) {
+ System.out.print(text + " ");
+ for (int i = start; i < (start + len); i++) {
+ int j = mem[i];
+ if (j < 0) {
+ j += 256;
+ }
+ String s = Integer.toHexString(j);
+ if (s.length() < 2) {
+ s = "0" + s;
+ }
+ System.out.print(s + ",");
+ }
+ System.out.println(" ");
+ }
+
+ public static long SBELong(final byte[] b, final int pos) {
+ final int i = b[pos];
+ int j = b[pos + 1];
+ int k = b[pos + 2];
+ int l = b[pos + 3];
+ // if (i < 0)
+ // i += 256;
+ if (j < 0) {
+ j += 256;
+ }
+ if (k < 0) {
+ k += 256;
+ }
+ if (l < 0) {
+ l += 256;
+ }
+ return ((256 * k) + l) + (65536L * ((256 * i) + j));
+ }
+
+ public static int SBEWord(final byte[] b, final int pos) {
+ final int i = b[pos];
+ int k = b[pos + 1];
+ // if (i < 0)
+ // i += 256;
+ if (k < 0) {
+ k += 256;
+ }
+ return ((256 * i) + k);
+ }
+
+ public static int SByte(final byte[] b, final int pos) {
+ final int i = b[pos];
+ return (i);
+ }
+
+ public static void setBEFloat(final byte[] b, final int pos, final float f) {
+ int a = Float.floatToIntBits(f);
+ b[pos + 3] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[pos + 2] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[pos + 1] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[pos] = (byte) (a & 0xff);
+ }
+
+ public static void setUSBELong(final byte[] b, final int pos, long a) {
+ b[pos + 3] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[pos + 2] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[pos + 1] = (byte) (a & 0xff);
+ a = a >> 8;
+ b[pos] = (byte) (a & 0xff);
+ }
+
+ public static void setUSBEWord(final byte[] b, final int pos, final int val) {
+ b[pos] = ((byte) (val / 0x100));
+ b[pos + 1] = ((byte) (val % 0x100));
+ }
+
+ public static void setUSByte(final byte[] b, final int pos, final int val) {
+ b[pos] = ((byte) (val & 0xff));
+ }
+
+ public static String strerror(final int code) {
+ switch (code) {
+ case RESULT_OK:
+ return "ok";
+ case RESULT_MULTIPLE_BITS_NOT_SUPPORTED:
+ return "the CPU doesn't support reading a bit block of length<>1";
+ case RESULT_ITEM_NOT_AVAILABLE:
+ return "the desired item is not available in the PLC";
+ case RESULT_ITEM_NOT_AVAILABLE200:
+ return "the desired item is not available in the PLC (200 family)";
+ case RESULT_ADDRESS_OUT_OF_RANGE:
+ return "the desired address is beyond limit for this PLC";
+ case RESULT_CPU_RETURNED_NO_DATA:
+ return "the PLC returned a packet with no result data";
+ case Nodave.RESULT_UNKNOWN_ERROR:
+ return "the PLC returned an error code not understood by this library";
+ case Nodave.RESULT_EMPTY_RESULT_ERROR:
+ return "this result contains no data";
+ case Nodave.RESULT_EMPTY_RESULT_SET_ERROR:
+ return "can't work with an undefined result set";
+ case Nodave.RESULT_CANNOT_EVALUATE_PDU:
+ return "can't evaluate the received PDU";
+ case Nodave.RESULT_WRITE_DATA_SIZE_MISMATCH:
+ return "Write data size error";
+ case Nodave.RESULT_NO_PERIPHERAL_AT_ADDRESS:
+ return "No data from I/O module";
+ case Nodave.RESULT_UNEXPECTED_FUNC:
+ return "Unexpected function code in answer";
+ case Nodave.RESULT_UNKNOWN_DATA_UNIT_SIZE:
+ return "PLC responds wit an unknown data type";
+ case Nodave.RESULT_SHORT_PACKET:
+ return "Short packet from PLC";
+ case Nodave.RESULT_TIMEOUT:
+ return "Timeout when waiting for PLC response";
+ case 0x8000:
+ return "function already occupied.";
+ case 0x8001:
+ return "not allowed in current operating status.";
+ case 0x8101:
+ return "hardware fault.";
+ case 0x8103:
+ return "object access not allowed.";
+ case 0x8104:
+ return "context is not supported.";
+ case 0x8105:
+ return "invalid address.";
+ case 0x8106:
+ return "data type not supported.";
+ case 0x8107:
+ return "data type not consistent.";
+ case 0x810A:
+ return "object doesn't exist.";
+ case 0x8500:
+ return "incorrect PDU size.";
+ case 0x8702:
+ return "address invalid.";
+ case 0xd201:
+ return "block name syntax error.";
+ case 0xd202:
+ return "syntax error function parameter.";
+ case 0xd203:
+ return "syntax error block type.";
+ case 0xd204:
+ return "no linked block in storage medium.";
+ case 0xd205:
+ return "object already exists.";
+ case 0xd206:
+ return "object already exists.";
+ case 0xd207:
+ return "block exists in EPROM.";
+ case 0xd209:
+ return "block doesn't exist.";
+ case 0xd20e:
+ return "no block doesn't exist.";
+ case 0xd210:
+ return "block number too big.";
+ case 0xd240:
+ return "unfinished block transfer in progress?";
+ case 0xd241:
+ return "protected by password.";
+ default:
+ return "no message defined for code: " + code + "!";
+ }
+ }
+
+ public static byte[] toPLCfloat(final double d) {
+ final float f = (float) d;
+ return toPLCfloat(f);
+ }
+
+ public static byte[] toPLCfloat(final float f) {
+ final int i = Float.floatToIntBits(f);
+ return bswap_32(i);
+ }
+
+ public static long USBELong(final byte[] b, final int pos) {
+ int i = b[pos];
+ int j = b[pos + 1];
+ int k = b[pos + 2];
+ int l = b[pos + 3];
+ // System.out.println(
+ // pos + " 0:" + i + " 1:" + j + " 2:" + k + " 3:" + l);
+ if (i < 0) {
+ i += 256;
+ }
+ if (j < 0) {
+ j += 256;
+ }
+ if (k < 0) {
+ k += 256;
+ }
+ if (l < 0) {
+ l += 256;
+ }
+ return ((256 * k) + l) + (65536L * ((256 * i) + j));
+ }
+
+ public static int USBEWord(final byte[] b, final int pos) {
+ int i = b[pos];
+ int k = b[pos + 1];
+ if (i < 0) {
+ i += 256;
+ }
+ if (k < 0) {
+ k += 256;
+ }
+ return ((256 * i) + k);
+ }
+
+ public static int USByte(final byte[] b, final int pos) {
+ int i = b[pos];
+ if (i < 0) {
+ i += 256;
+ }
+ return (i);
+ }
+
+}
\ No newline at end of file
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/PDU.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/PDU.java
new file mode 100644
index 0000000..6bb4449
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/PDU.java
@@ -0,0 +1,496 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/*
+ Part of Libnodave, a free communication libray for Siemens S7
+
+ (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005.
+
+ Libnodave is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ Libnodave is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.DaveArea;
+
+/**
+ * @author Thomas Rudin
+ */
+public final class PDU {
+ /**
+ * known function codes
+ */
+ public final static byte FUNC_READ = 4;
+
+ public final static byte FUNC_WRITE = 5;
+
+ public int data;
+ public int param; // the position of the parameters;
+ public int plen;
+ public int udata;
+ public int udlen;
+ int dlen;
+ int error;
+ int header; // the position of the header;
+ int hlen;
+ byte[] mem;
+
+ /**
+ * set up the PDU information
+ *
+ * @param mem Mem
+ * @param pos Pos
+ */
+ public PDU(final byte[] mem, final int pos) {
+ this.mem = mem;
+ this.header = pos;
+ }
+
+ public int addBitVarToReadRequest(final int area, final int DBnum, final int start, final int len) {
+ final byte pa[] = {0x12, 0x0a, 0x10, 0x01, /* single bits */
+ 0x00, 0x1A, /* insert length in bytes here */
+ 0x00, 0x0B, /* insert DB number here */
+ (byte) 0x84, /* change this to real area code */
+ 0x00, 0x00, (byte) 0xC0 /* insert start address in bits */
+ };
+ Nodave.setUSBEWord(pa, 4, len);
+ Nodave.setUSBEWord(pa, 6, DBnum);
+ Nodave.setUSBELong(pa, 8, start);
+ Nodave.setUSByte(pa, 8, area);
+
+ this.mem[this.param + 1]++;
+ System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
+ this.plen += pa.length;
+ Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
+ return 0;
+
+ }
+
+ public void addBitVarToWriteRequest(final DaveArea area, final int DBnum, final int start, final int byteCount,
+ final byte[] buffer) {
+ final byte da[] = {0, 3, 0, 0,};
+ final byte pa[] = {0x12, 0x0a, 0x10, 0x01, /* single bit */
+ 0, 0, /* insert length in bytes here */
+ 0, 0, /* insert DB number here */
+ 0, /* change this to real area code */
+ 0, 0, 0 /* insert start address in bits */
+ };
+ if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
+ || (area == DaveArea.COUNTER200)) {
+ pa[3] = (byte) area.getCode();
+ pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
+ pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
+ } else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
+ pa[3] = 4;
+ pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
+ pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
+ } else {
+ pa[4] = (byte) (byteCount / 0x100);
+ pa[5] = (byte) (byteCount & 0xff);
+ }
+ pa[6] = (byte) (DBnum / 256);
+ pa[7] = (byte) (DBnum & 0xff);
+ pa[8] = (byte) area.getCode();
+ pa[11] = (byte) (start & 0xff);
+ pa[10] = (byte) ((start / 0x100) & 0xff);
+ pa[9] = (byte) (start / 0x10000);
+
+ if ((this.dlen % 2) != 0) {
+ this.addData(da, 1);
+ }
+
+ this.mem[this.param + 1]++;
+ if (this.dlen > 0) {
+ final byte[] saveData = new byte[this.dlen];
+ System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
+ System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
+ }
+ System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
+ this.plen += pa.length;
+ Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
+ this.data = this.param + this.plen;
+
+ this.addData(da);
+ this.addValue(buffer);
+ }
+
+ /**
+ * Add data after parameters, set dlen as needed. Needs valid header and
+ * parameters
+ */
+ void addData(final byte[] newData) {
+ final int appPos = this.data + this.dlen; // append to this position
+ this.dlen += newData.length;
+ System.arraycopy(newData, 0, this.mem, appPos, newData.length);
+ Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
+ }
+
+ /**
+ * Add len bytes of len after parameters from a maybe longer block of bytes.
+ * Set dlen as needed. Needs valid header and parameters
+ *
+ * @param newData New Data
+ * @param len Length
+ */
+ public void addData(final byte[] newData, final int len) {
+ final int appPos = this.data + this.dlen; // append to this position
+ this.dlen += len;
+ System.arraycopy(newData, 0, this.mem, appPos, len);
+ Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
+ }
+
+ public void addParam(final byte[] pa) {
+ this.plen = pa.length;
+ System.arraycopy(pa, 0, this.mem, this.param, this.plen);
+ Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
+ // mem[header + 6] = (byte) (pa.length / 256);
+ // mem[header + 7] = (byte) (pa.length % 256);
+ this.data = this.param + this.plen;
+ this.dlen = 0;
+ }
+
+ /*
+ * add data in user data. Add a user data header, if not yet present.
+ */
+ public void addUserData(final byte[] da) {
+ final byte udh[] = {(byte) 0xff, 9, 0, 0};
+ if (this.dlen == 0) {
+ this.addData(udh);
+ }
+ this.addValue(da);
+ }
+
+ /**
+ * Add values after value header in data, adjust dlen and data count. Needs
+ * valid header,parameters,data,dlen
+ */
+ void addValue(final byte[] values) {
+ int valCount = (0x100 * this.mem[this.data + 2]) + this.mem[this.data + 3];
+ if (this.mem[this.data + 1] == 4) { // bit data, length is in bits
+ valCount += 8 * values.length;
+ } else if (this.mem[this.data + 1] == 9) { // byte data, length is in
+ // bytes
+ valCount += values.length;
+ } else {
+ // XXX
+ }
+ if (this.udata == 0) {
+ this.udata = this.data + 4;
+ }
+ this.udlen += values.length;
+ Nodave.setUSBEWord(this.mem, this.data + 2, valCount);
+ this.addData(values);
+ }
+
+ public int addVarToReadRequest(final DaveArea area, final int DBnum, int start, final int len) {
+ final byte[] pa = {0x12, 0x0a, 0x10,
+ 0x02, /* 1=single bit, 2=byte, 4=word */
+ 0x00, 0x1A, /* length in bytes */
+ 0x00, 0x0B, /* DB number */
+ (byte) 0x84, // * area code */
+ 0x00, 0x00, (byte) 0xC0 /* start address in bits */
+ };
+
+ if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
+ pa[3] = 4;
+ start *= 8; /* bits */
+ } else if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
+ || (area == DaveArea.COUNTER200)) {
+ pa[3] = (byte) area.getCode();
+ } else {
+ start *= 8; /* bits */
+ }
+
+ Nodave.setUSBEWord(pa, 4, len);
+ Nodave.setUSBEWord(pa, 6, DBnum);
+ Nodave.setUSBELong(pa, 8, start);
+ Nodave.setUSByte(pa, 8, area.getCode());
+
+ this.mem[this.param + 1]++;
+ System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
+ this.plen += pa.length;
+ Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
+ /**
+ * TODO calc length of result. Do not add variable if it would exceed
+ * max. result length.
+ */
+ return 0;
+ }
+
+ public void addVarToWriteRequest(final DaveArea area, final int DBnum, int start, final int byteCount,
+ final byte[] buffer) {
+ final byte da[] = {0, 4, 0, 0,};
+ final byte pa[] = {0x12, 0x0a, 0x10, 0x02,
+ /* unit (for count?, for consistency?) byte */
+ 0, 0, /* length in bytes */
+ 0, 0, /* DB number */
+ 0, /* area code */
+ 0, 0, 0 /* start address in bits */
+ };
+ if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
+ || (area == DaveArea.COUNTER200)) {
+ pa[3] = (byte) area.getCode();
+ pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
+ pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
+ } else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
+ pa[3] = 4;
+ pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
+ pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
+ } else {
+ pa[4] = (byte) (byteCount / 0x100);
+ pa[5] = (byte) (byteCount & 0xff);
+ }
+ pa[6] = (byte) (DBnum / 256);
+ pa[7] = (byte) (DBnum & 0xff);
+ pa[8] = (byte) (area.getCode());
+ start *= 8; /* number of bits */
+ pa[11] = (byte) (start & 0xff);
+ pa[10] = (byte) ((start / 0x100) & 0xff);
+ pa[9] = (byte) (start / 0x10000);
+ if ((this.dlen % 2) != 0) {
+ this.addData(da, 1);
+ }
+ this.mem[this.param + 1]++;
+ if (this.dlen > 0) {
+ final byte[] saveData = new byte[this.dlen];
+ System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
+ System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
+ }
+ System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
+ this.plen += pa.length;
+ Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
+ this.data = this.param + this.plen;
+ this.addData(da);
+ this.addValue(buffer);
+ }
+
+ /**
+ * construct a write request for a single item in PLC memory.
+ */
+ /*
+ * void constructWriteRequest( int area, int DBnum, int start, int len,
+ * byte[] buffer) { byte pa[] = new byte[14]; byte da[] = { 0, 4, 0, 0 };
+ * pa[0] = PDU.FUNC_WRITE; pa[1] = (byte) 0x01; pa[2] = (byte) 0x12; pa[3] =
+ * (byte) 0x0a; pa[4] = (byte) 0x10; pa[5] = (byte) 0x02;
+ *
+ * Nodave.setUSBEWord(pa, 6, len); Nodave.setUSBEWord(pa, 8, DBnum);
+ * Nodave.setUSBELong(pa, 10, 8 * start); // the bit address
+ * Nodave.setUSByte(pa, 10, area); initHeader(1); addParam(pa); addData(da);
+ * addValue(buffer); if ((Nodave.Debug & Nodave.DEBUG_PDU) != 0) { dump(); }
+ * }
+ */
+
+ /**
+ * display information about a PDU
+ */
+ public void dump() {
+ Nodave.dump("PDU header ", this.mem, this.header, this.hlen);
+ System.out.println("plen: " + this.plen + " dlen: " + this.dlen);
+ Nodave.dump("Parameter", this.mem, this.param, this.plen);
+ if (this.dlen > 0) {
+ Nodave.dump("Data ", this.mem, this.data, this.dlen);
+ }
+ if (this.udlen > 0) {
+ Nodave.dump("result Data ", this.mem, this.udata, this.udlen);
+ }
+ }
+
+ public int getError() {
+ return this.error;
+ }
+
+ /**
+ * return the function code of the PDU
+ *
+ * @return Function Code Of PDU
+ */
+ public int getFunc() {
+ return Nodave.USByte(this.mem, this.param + 0);
+ }
+
+ /*
+ * typedef struct { uc P; // allways 0x32 uc type; // a type? type 2 and 3
+ * headers are two bytes longer. uc a,b; // currently unknown us number; //
+ * Number, can be used to identify answers corresponding to requests us
+ * plen; // length of parameters which follow this header us dlen; // length
+ * of data which follows the parameters uc x[2]; // only present in type 2
+ * and 3 headers. This may contain error information. } PDUHeader;
+ */
+
+ /**
+ * return the number of the PDU
+ *
+ * @return number
+ */
+ public int getNumber() {
+ return Nodave.USBEWord(this.mem, this.header + 4);
+ }
+
+ /**
+ * set the number of the PDU
+ *
+ * @param n number
+ */
+ public void setNumber(final int n) {
+ Nodave.setUSBEWord(this.mem, this.header + 4, n);
+ }
+
+ /**
+ * reserve space for the header of a new PDU
+ *
+ * @param type Type
+ */
+ public void initHeader(final int type) {
+ if ((type == 2) || (type == 3)) {
+ this.hlen = 12;
+ } else {
+ this.hlen = 10;
+ }
+ for (int i = 0; i < this.hlen; i++) {
+ this.mem[this.header + i] = 0;
+ }
+ this.param = this.header + this.hlen;
+ this.mem[this.header] = (byte) 0x32;
+ this.mem[this.header + 1] = (byte) type;
+ this.dlen = 0;
+ this.plen = 0;
+ this.udlen = 0;
+ this.data = 0;
+ this.udata = 0;
+ }
+
+ public void initReadRequest() {
+ final byte pa[] = new byte[2];
+ pa[0] = PDU.FUNC_READ;
+ pa[1] = (byte) 0x00;
+ this.initHeader(1);
+ this.addParam(pa);
+ }
+
+ /**
+ * prepare a read request with no item.
+ */
+ public void prepareReadRequest() {
+ final byte pa[] = new byte[2];
+ pa[0] = PDU.FUNC_READ;
+ pa[1] = (byte) 0x00;
+ this.initHeader(1);
+ this.addParam(pa);
+ }
+
+ /**
+ * prepare a write request with no item.
+ */
+ public void prepareWriteRequest() {
+ final byte pa[] = new byte[2];
+ pa[0] = PDU.FUNC_WRITE;
+ pa[1] = (byte) 0x00;
+ this.initHeader(1);
+ this.addParam(pa);
+ }
+
+ /**
+ * Set up a PDU instance to reflect the structure of data present in the
+ * memory area given to initHeader. Needs valid header.
+ *
+ * @return Result
+ */
+ public int setupReceivedPDU() {
+ int res = Nodave.RESULT_CANNOT_EVALUATE_PDU; // just assume the worst
+ if ((this.mem[this.header + 1] == 2) || (this.mem[this.header + 1] == 3)) {
+ this.hlen = 12;
+ res = Nodave.USBEWord(this.mem, this.header + 10);
+ } else {
+ this.error = 0;
+ this.hlen = 10;
+ res = 0;
+ }
+ this.param = this.header + this.hlen;
+ this.plen = Nodave.USBEWord(this.mem, this.header + 6);
+ this.data = this.param + this.plen;
+ this.dlen = Nodave.USBEWord(this.mem, this.header + 8);
+ this.udlen = 0;
+ this.udata = 0;
+ return res;
+ }
+
+ public int testPGReadResult() {
+ if (this.mem[this.param] != 0) {
+ return Nodave.RESULT_UNEXPECTED_FUNC;
+ }
+ return this.testResultData();
+ }
+
+ ;
+
+ int testReadResult() {
+ if (this.mem[this.param] != FUNC_READ) {
+ return Nodave.RESULT_UNEXPECTED_FUNC;
+ }
+ return this.testResultData();
+ }
+
+ /*
+
+ */
+ int testResultData() {
+ int res = Nodave.RESULT_CANNOT_EVALUATE_PDU; // just assume the worst
+ if ((this.mem[this.data] == (byte) 255) && (this.dlen > 4)) {
+ res = Nodave.RESULT_OK;
+ this.udata = this.data + 4;
+ // udlen=data[2]*0x100+data[3];
+ this.udlen = Nodave.USBEWord(this.mem, this.data + 2);
+ if (this.mem[this.data + 1] == 4) {
+ this.udlen >>= 3; /* len is in bits, adjust */
+ } else if (this.mem[this.data + 1] == 9) {
+ /* len is already in bytes, ok */
+ } else if (this.mem[this.data + 1] == 3) {
+ /* len is in bits, but there is a byte per result bit, ok */
+ } else {
+ res = Nodave.RESULT_UNKNOWN_DATA_UNIT_SIZE;
+ }
+ } else {
+ res = this.mem[this.data];
+ }
+ return res;
+ }
+
+ int testWriteResult() {
+ int res = Nodave.RESULT_CANNOT_EVALUATE_PDU;
+ if (this.mem[this.param] != FUNC_WRITE) {
+ return Nodave.RESULT_UNEXPECTED_FUNC;
+ }
+ if ((this.mem[this.data] == 255)) {
+ res = Nodave.RESULT_OK;
+ } else {
+ res = this.mem[this.data];
+ }
+ return res;
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/PLCinterface.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/PLCinterface.java
new file mode 100644
index 0000000..b24eda3
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/PLCinterface.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/*
+ Part of Libnodave, a free communication libray for Siemens S7
+
+ (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005.
+
+ Libnodave is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ Libnodave is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * @author Thomas Rudin
+ */
+public final class PLCinterface {
+ InputStream in;
+ int localMPI; // the adapter's MPI address
+ String name;
+
+ OutputStream out;
+ int protocol; // The kind of transport used on this interface.
+ int wp, rp;
+
+ public PLCinterface(final OutputStream out, final InputStream in, final String name, final int localMPI,
+ final int protocol) {
+ this.init(out, in, name, localMPI, protocol);
+ }
+
+ public void init(final OutputStream oStream, final InputStream iStream, final String name, final int localMPI,
+ final int protocol) {
+ this.out = oStream;
+ this.in = iStream;
+ this.name = name;
+ this.localMPI = localMPI;
+ this.protocol = protocol;
+ }
+
+ public int read(final byte[] b, int start, int len) {
+ int res;
+ try {
+ int retry = 0;
+ while ((this.in.available() <= 0) && (retry < 500)) {
+ try {
+ if (retry > 0) {
+ Thread.sleep(1);
+ }
+ retry++;
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ res = 0;
+ while ((this.in.available() > 0) && (len > 0)) {
+ res = this.in.read(b, start, len);
+ start += res;
+ len -= res;
+ }
+ return res;
+ } catch (final IOException e) {
+ e.printStackTrace();
+ return 0;
+ }
+ }
+
+ public void write(final byte[] b, final int start, final int len) {
+ try {
+ this.out.write(b, start, len);
+ } catch (final IOException e) {
+ System.err.println("Interface.write: " + e);
+ }
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/Result.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/Result.java
new file mode 100644
index 0000000..defcfa1
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/Result.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/*
+ Part of Libnodave, a free communication libray for Siemens S7
+
+ (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005.
+
+ Libnodave is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ Libnodave is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave;
+
+/**
+ * @author Thomas Hergenhahn
+ *
+ * To change the template for this generated type comment go to
+ * Window-Preferences-Java-Code Generation-Code and Comments
+ */
+public final class Result {
+ public int bufferStart;
+ public int error;
+ public int length;
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/ResultSet.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/ResultSet.java
new file mode 100644
index 0000000..4bff25e
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/ResultSet.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/*
+ Part of Libnodave, a free communication libray for Siemens S7
+
+ (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005.
+
+ Libnodave is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ Libnodave is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave;
+
+/**
+ * @author Thomas Hergenhahn
+ */
+public final class ResultSet {
+ public Result[] results;
+ private int errorState, numResults;
+
+ public int getErrorState() {
+ return this.errorState;
+ }
+
+ public void setErrorState(final int error) {
+ this.errorState = error;
+ }
+
+ ;
+
+ public int getNumResults() {
+ return this.numResults;
+ }
+
+ public void setNumResults(final int nr) {
+ this.numResults = nr;
+ }
+
+ ;
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/S7Connection.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/S7Connection.java
new file mode 100644
index 0000000..de35e58
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/S7Connection.java
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/*
+ Part of Libnodave, a free communication libray for Siemens S7
+
+ (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005.
+
+ Libnodave is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ Libnodave is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.DaveArea;
+
+import java.util.concurrent.Semaphore;
+
+/**
+ * This class comprises the variables and methods common to connections to an S7
+ * PLC regardless of the type of transport.
+ *
+ * @author Thomas Hergenhahn
+ */
+public abstract class S7Connection {
+ static int tmo_normal = 150;
+ public int maxPDUlength;
+ public byte messageNumber = 0;
+ public byte[] msgIn;
+ public byte[] msgOut;
+ public int packetNumber = 0; // packetNumber in transport layer
+ public int PDUstartIn;
+ public int PDUstartOut;
+ public Semaphore semaphore;
+ int answLen; // length of last message
+ /**
+ * position in result data, incremented when variables are extracted without
+ * position
+ */
+ int dataPointer;
+ PLCinterface iface; // pointer to used interface
+ PDU rcvdPDU;
+ /**
+ * absolute begin of result data
+ */
+ int udata;
+
+ public S7Connection(final PLCinterface ifa) {
+ this.iface = ifa;
+ this.msgIn = new byte[Nodave.MAX_RAW_LEN];
+ this.msgOut = new byte[Nodave.MAX_RAW_LEN];
+ this.PDUstartIn = 0;
+ this.PDUstartOut = 0;
+ this.semaphore = new Semaphore(1);
+ }
+
+ abstract public int exchange(PDU p1);
+
+ // int numResults;
+ /*
+ * class Result { int error; byte[] data; }
+ */
+ /*
+ * Read a predefined set of values from the PLC. Return ok or an error state
+ * If a buffer pointer is provided, data will be copied into this buffer. If
+ * it's NULL you can get your data from the resultPointer in daveConnection
+ * long as you do not send further requests.
+ */
+ public ResultSet execReadRequest(final PDU p) {
+ PDU p2;
+ int errorState;
+ errorState = this.exchange(p);
+
+ p2 = new PDU(this.msgIn, this.PDUstartIn);
+ p2.setupReceivedPDU();
+ /*
+ * if (p2.udlen == 0) { dataPointer = 0; answLen = 0; return
+ * Nodave.RESULT_CPU_RETURNED_NO_DATA; }
+ */
+ final ResultSet rs = new ResultSet();
+ if (p2.mem[p2.param + 0] == PDU.FUNC_READ) {
+ int numResults = p2.mem[p2.param + 1];
+ // System.out.println("Results " + numResults);
+ rs.results = new Result[numResults];
+ int pos = p2.data;
+ for (int i = 0; i < numResults; i++) {
+ final Result r = new Result();
+ r.error = Nodave.USByte(p2.mem, pos);
+ if (r.error == 255) {
+
+ final int type = Nodave.USByte(p2.mem, pos + 1);
+ int len = Nodave.USBEWord(p2.mem, pos + 2);
+ r.error = 0;
+ // System.out.println("Raw length " + len);
+ if (type == 4) {
+ len /= 8;
+ } else if (type == 3) {
+ ; // length is ok
+ }
+
+ // System.out.println("Byte length " + len);
+ // r.data = new byte[len];
+
+ // System.arraycopy(p2.mem, pos + 4, r.data, 0, len);
+ // Nodave.dump("Result " + i + ":", r.data, 0, len);
+ r.bufferStart = pos + 4;
+ pos += len;
+ if ((len % 2) == 1) {
+ pos++;
+ }
+ } else {
+ System.out.println("Error " + r.error);
+ }
+ pos += 4;
+ rs.results[i] = r;
+ }
+ numResults = p2.mem[p2.param + 1];
+ rs.setNumResults(numResults);
+ this.dataPointer = p2.udata;
+ this.answLen = p2.udlen;
+ // }
+ } else {
+ errorState |= 2048;
+ }
+ this.semaphore.release();
+ rs.setErrorState(errorState);
+ return rs;
+ }
+
+ public int getBYTE() {
+ this.dataPointer += 1;
+ return Nodave.SByte(this.msgIn, this.dataPointer - 1);
+ }
+
+ public int getBYTE(final int pos) {
+ return Nodave.SByte(this.msgIn, this.udata + pos);
+ }
+
+ public int getCHAR() {
+ this.dataPointer += 1;
+ return Nodave.SByte(this.msgIn, this.dataPointer - 1);
+ }
+
+ public int getCHAR(final int pos) {
+ return Nodave.SByte(this.msgIn, this.udata + pos);
+ }
+
+ /**
+ * get a signed 32bit value from the current position in result bytes
+ *
+ * @return value
+ */
+ public long getDINT() {
+ this.dataPointer += 4;
+ return Nodave.SBELong(this.msgIn, this.dataPointer - 4);
+ }
+
+ /**
+ * get a signed 32bit value from the specified position in result bytes
+ *
+ * @param pos Pos
+ * @return Value
+ */
+ public long getDINT(final int pos) {
+ return Nodave.SBELong(this.msgIn, this.udata + pos);
+ }
+
+ /**
+ * get an unsigned 32bit value from the specified position in result bytes
+ *
+ * @param pos Pos
+ * @return value
+ */
+ public long getDWORD(final int pos) {
+ // System.out.println("getDWORD pos " + pos);
+ return Nodave.USBELong(this.msgIn, this.udata + pos);
+ }
+
+ /**
+ * get a float value from the current position in result bytes
+ *
+ * @return value
+ */
+ public float getFloat() {
+ this.dataPointer += 4;
+ return Nodave.BEFloat(this.msgIn, this.dataPointer - 4);
+ }
+
+ /*
+ * The following methods are here to give Siemens users their usual data
+ * types:
+ */
+
+ /**
+ * get a float value from the specified position in result bytes
+ *
+ * @param pos Pos
+ * @return value
+ */
+ public float getFloat(final int pos) {
+ // System.out.println("getFloat pos " + pos);
+ return Nodave.BEFloat(this.msgIn, this.udata + pos);
+ }
+
+ public int getINT() {
+ this.dataPointer += 2;
+ return Nodave.SBEWord(this.msgIn, this.dataPointer - 2);
+ }
+
+ public int getINT(final int pos) {
+ return Nodave.SBEWord(this.msgIn, this.udata + pos);
+ }
+
+ public int getPPIresponse() {
+ return 0;
+ }
+
+ /*
+ * public void sendYOURTURN() { }
+ */
+ public int getResponse() {
+ return 0;
+ }
+
+ public int getS16(final int pos) {
+ return Nodave.SBEWord(this.msgIn, this.udata + pos);
+ }
+
+ public long getS32(final int pos) {
+ return Nodave.SBELong(this.msgIn, this.udata + pos);
+ }
+
+ public int getS8(final int pos) {
+ return Nodave.SByte(this.msgIn, this.udata + pos);
+ }
+
+ /**
+ * get an unsigned 32bit value from the current position in result bytes
+ *
+ * @return value
+ */
+ public long getU32() {
+ this.dataPointer += 4;
+ return Nodave.USBELong(this.msgIn, this.dataPointer - 4);
+ }
+
+ public int getUS16(final int pos) {
+ return Nodave.USBEWord(this.msgIn, this.udata + pos);
+ }
+
+ public long getUS32(final int pos) {
+ return Nodave.USBELong(this.msgIn, this.udata + pos);
+ }
+
+ public int getUS8(final int pos) {
+ return Nodave.USByte(this.msgIn, this.udata + pos);
+ }
+
+ /**
+ * get an unsigned 16bit value from the current position in result bytes
+ *
+ * @return word
+ */
+ public int getWORD() {
+ this.dataPointer += 2;
+ return Nodave.USBEWord(this.msgIn, this.dataPointer - 2);
+ }
+
+ /**
+ * get an unsigned 16bit value from the specified position in result bytes
+ *
+ * @param pos Pos
+ * @return word
+ */
+ public int getWORD(final int pos) {
+ return Nodave.USBEWord(this.msgIn, this.udata + pos);
+ }
+
+ /**
+ * build the PDU for a PDU length negotiation
+ *
+ * @return word
+ */
+ public int negPDUlengthRequest() {
+ int res;
+ final PDU p = new PDU(this.msgOut, this.PDUstartOut);
+ final byte pa[] = {(byte) 0xF0, 0, 0x00, 0x01, 0x00, 0x01, 0x03, (byte) 0xC0,};
+ p.initHeader(1);
+ p.addParam(pa);
+ res = this.exchange(p);
+ if (res != 0) {
+ return res;
+ }
+ final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
+ res = p2.setupReceivedPDU();
+ if (res != 0) {
+ return res;
+ }
+ this.maxPDUlength = Nodave.USBEWord(this.msgIn, p2.param + 6);
+ return res;
+ }
+
+ public int readBytes(final DaveArea area, final int DBnum, final int start, final int len, final byte[] buffer) {
+ int res = 0;
+ try {
+ this.semaphore.acquire();
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
+ final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
+ p1.initReadRequest();
+ p1.addVarToReadRequest(area, DBnum, start, len);
+
+ res = this.exchange(p1);
+ if (res != Nodave.RESULT_OK) {
+ this.semaphore.release();
+ return res;
+ }
+ final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
+ res = p2.setupReceivedPDU();
+ if (res != Nodave.RESULT_OK) {
+ this.semaphore.release();
+ return res;
+ }
+
+ res = p2.testReadResult();
+ if (res != Nodave.RESULT_OK) {
+ this.semaphore.release();
+ return res;
+ }
+ if (p2.udlen == 0) {
+ this.semaphore.release();
+ return Nodave.RESULT_CPU_RETURNED_NO_DATA;
+ }
+ /*
+ * copy to user buffer and setup internal buffer pointers:
+ */
+ if (buffer != null) {
+ System.arraycopy(p2.mem, p2.udata, buffer, 0, p2.udlen);
+ }
+
+ this.dataPointer = p2.udata;
+ this.udata = p2.udata;
+ this.answLen = p2.udlen;
+ this.semaphore.release();
+ return res;
+ }
+
+ public int sendMsg(final PDU p) {
+ return 0;
+ }
+
+ public void sendRequestData(final int alt) {
+ }
+
+ public int useResult(final ResultSet rs, final int number) {
+ System.out.println("rs.getNumResults: " + rs.getNumResults() + " number: " + number);
+ if (rs.getNumResults() > number) {
+ this.dataPointer = rs.results[number].bufferStart;
+ return 0;
+ // udata=rs.results[number].bufferStart;
+ }
+ return -33;
+ }
+
+ ;
+
+ /*
+ * Write len bytes to PLC memory area "area", data block DBnum.
+ */
+ public int writeBytes(final DaveArea area, final int DBnum, final int start, final int len, final byte[] buffer) {
+ int errorState = 0;
+ this.semaphore.release();
+ final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
+
+ // p1.constructWriteRequest(area, DBnum, start, len, buffer);
+ p1.prepareWriteRequest();
+ p1.addVarToWriteRequest(area, DBnum, start, len, buffer);
+
+ errorState = this.exchange(p1);
+
+ if (errorState == 0) {
+ final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
+ p2.setupReceivedPDU();
+
+ if (p2.mem[p2.param + 0] == PDU.FUNC_WRITE) {
+ if (p2.mem[p2.data + 0] == (byte) 0xFF) {
+ this.semaphore.release();
+ return 0;
+ }
+ } else {
+ errorState |= 4096;
+ }
+ }
+ this.semaphore.release();
+ return errorState;
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/TCPConnection.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/TCPConnection.java
new file mode 100644
index 0000000..ac294b8
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/nodave/TCPConnection.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/*
+ Part of Libnodave, a free communication libray for Siemens S7
+
+ (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005.
+
+ Libnodave is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ Libnodave is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.nodave;
+
+/**
+ * The Class TCPConnection.
+ *
+ * @author Thomas Rudin
+ */
+public final class TCPConnection extends S7Connection {
+
+ /**
+ * The rack.
+ */
+ int rack;
+
+ /**
+ * The slot.
+ */
+ int slot;
+
+ /**
+ * Instantiates a new TCP connection.
+ *
+ * @param ifa the plc interface
+ * @param rack the rack
+ * @param slot the slot
+ */
+ public TCPConnection(final PLCinterface ifa, final int rack, final int slot) {
+ super(ifa);
+ this.rack = rack;
+ this.slot = slot;
+ this.PDUstartIn = 7;
+ this.PDUstartOut = 7;
+ }
+
+ /**
+ * We have our own connectPLC(), but no disconnect() Open connection to a
+ * PLC. This assumes that dc is initialized by daveNewConnection and is not
+ * yet used. (or reused for the same PLC ?)
+ *
+ * @return the int
+ */
+ public int connectPLC() {
+ int packetLength;
+ if (iface.protocol == Nodave.PROTOCOL_ISOTCP243) {
+ final byte[] b243 = {
+ (byte) 0x11, (byte) 0xE0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+ (byte) 0xC1, (byte) 0x02, (byte) 0x4D, (byte) 0x57, (byte) 0xC2, (byte) 0x02, (byte) 0x4D, (byte) 0x57,
+ (byte) 0xC0, (byte) 0x01, (byte) 0x09
+ };
+ System.arraycopy(b243, 0, this.msgOut, 4, b243.length);
+ packetLength = b243.length;
+ } else {
+ final byte[] b4 = {
+ (byte) 0x11, (byte) 0xE0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+ (byte) 0xC1, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0xC2, (byte) 0x02, (byte) 0x01, (byte) 0x02,
+ (byte) 0xC0, (byte) 0x01, (byte) 0x09
+ };
+ System.arraycopy(b4, 0, this.msgOut, 4, b4.length);
+ this.msgOut[17] = (byte) (this.rack + 1);
+ this.msgOut[18] = (byte) this.slot;
+ packetLength = b4.length;
+ }
+ this.sendISOPacket(packetLength);
+ this.readISOPacket();
+ /*
+ * PDU p = new PDU(msgOut, 7); p.initHeader(1); p.addParam(b61);
+ * exchange(p); return (0);
+ */
+ return this.negPDUlengthRequest();
+ }
+
+ @Override
+ public int exchange(final PDU p1) {
+ this.msgOut[4] = (byte) 0x02;
+ this.msgOut[5] = (byte) 0xf0;
+ this.msgOut[6] = (byte) 0x80;
+ this.sendISOPacket(3 + p1.hlen + p1.plen + p1.dlen);
+ this.readISOPacket();
+ return 0;
+ }
+
+ /**
+ * Read iso packet.
+ *
+ * @return the int
+ */
+ protected int readISOPacket() {
+ int res = this.iface.read(this.msgIn, 0, 4);
+ if (res == 4) {
+ final int len = (0x100 * this.msgIn[2]) + this.msgIn[3];
+ res += this.iface.read(this.msgIn, 4, len);
+ } else {
+ return 0;
+ }
+ return res;
+ }
+
+ /**
+ * Send iso packet.
+ *
+ * @param size the size
+ * @return the int
+ */
+ protected int sendISOPacket(int size) {
+ size += 4;
+ this.msgOut[0] = (byte) 0x03;
+ this.msgOut[1] = (byte) 0x0;
+ this.msgOut[2] = (byte) (size / 0x100);
+ this.msgOut[3] = (byte) (size % 0x100);
+ /*
+ * if (messageNumber == 0) { messageNumber = 1; msgOut[11] = (byte)
+ * ((messageNumber + 1) & 0xff); messageNumber++; messageNumber &= 0xff;
+ * //!! }
+ */
+
+ this.iface.write(this.msgOut, 0, size);
+ return 0;
+ }
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/S7SerializerImpl.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/S7SerializerImpl.java
new file mode 100644
index 0000000..489a8ea
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/S7SerializerImpl.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.PlcS7PointVariable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.S7Exception;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.DaveArea;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Connector;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializer;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.parser.BeanEntry;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.parser.BeanParseResult;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.parser.BeanParser;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Array;
+
+/**
+ * The Class S7Serializer is responsible for serializing S7 TCP Connection
+ */
+@Slf4j
+public final class S7SerializerImpl implements S7Serializer {
+
+ /**
+ * The Connector.
+ */
+ private final S7Connector connector;
+
+ /**
+ * Instantiates a new s7 serializer.
+ *
+ * @param connector the connector
+ */
+ public S7SerializerImpl(final S7Connector connector) {
+ this.connector = connector;
+ }
+
+ public static Object extractBytes(PlcS7PointVariable plcs7PointVariable, final byte[] buffer, final int byteOffset) {
+ try {
+ final BeanEntry entry = BeanParser.parse(plcs7PointVariable);
+ return entry.serializer.extract(entry.type, buffer, entry.byteOffset + byteOffset, entry.bitOffset);
+ } catch (Exception e) {
+ throw new S7Exception("extractBytes", e);
+ }
+ }
+
+ /**
+ * Extracts bytes from a buffer.
+ *
+ * @param the generic type
+ * @param beanClass the bean class
+ * @param buffer the buffer
+ * @param byteOffset the byte offset
+ * @return the t
+ */
+ public static T extractBytes(final Class beanClass, final byte[] buffer, final int byteOffset) {
+ log.trace("Extracting type {} from buffer with size: {} at offset {}", beanClass.getName(), buffer.length, byteOffset);
+
+ try {
+ final T obj = beanClass.newInstance();
+ final BeanParseResult result = BeanParser.parse(beanClass);
+ for (final BeanEntry entry : result.entries) {
+ Object value = null;
+ if (entry.isArray) {
+ value = Array.newInstance(entry.type, entry.arraySize);
+ for (int i = 0; i < entry.arraySize; i++) {
+ final Object component = entry.serializer.extract(entry.type, buffer,
+ entry.byteOffset + byteOffset + (i * entry.s7type.getByteSize()),
+ entry.bitOffset + (i * entry.s7type.getBitSize()));
+ Array.set(value, i, component);
+ }
+ } else {
+ value = entry.serializer.extract(entry.type, buffer, entry.byteOffset + byteOffset, entry.bitOffset);
+ }
+
+ if (entry.field.getType() == byte[].class) {
+ //Special case issue #45
+ Byte[] oldValue = (Byte[]) value;
+
+ value = new byte[oldValue.length];
+
+ for (int i = 0; i < oldValue.length; i++) {
+ ((byte[]) value)[i] = oldValue[i];
+ }
+ }
+
+ entry.field.set(obj, value);
+ }
+
+ return obj;
+ } catch (final Exception e) {
+ throw new S7Exception("extractBytes", e);
+ }
+ }
+
+ /**
+ * Inserts the bytes to the buffer.
+ *
+ * @param bean the bean
+ * @param buffer the buffer
+ * @param byteOffset the byte offset
+ */
+ public static void insertBytes(final Object bean, final byte[] buffer, final int byteOffset) {
+ log.trace("Inerting buffer with size: {} at offset {} into bean: {}", buffer.length, byteOffset, bean);
+
+ try {
+ final BeanParseResult result = BeanParser.parse(bean);
+
+ for (final BeanEntry entry : result.entries) {
+ final Object fieldValue = entry.field.get(bean);
+
+ if (fieldValue != null) {
+ if (entry.isArray) {
+ for (int i = 0; i < entry.arraySize; i++) {
+ final Object arrayItem = Array.get(fieldValue, i);
+
+ if (arrayItem != null) {
+ entry.serializer.insert(arrayItem, buffer,
+ entry.byteOffset + byteOffset + (i * entry.s7type.getByteSize()),
+ entry.bitOffset + (i * entry.s7type.getBitSize()), entry.size);
+ }
+ }
+ } else {
+ entry.serializer.insert(fieldValue, buffer, entry.byteOffset + byteOffset, entry.bitOffset,
+ entry.size);
+ }
+ }
+ }
+ } catch (final Exception e) {
+ throw new S7Exception("insertBytes", e);
+ }
+ }
+
+ @Override
+ public synchronized T dispense(final Class beanClass, final int dbNum, final int byteOffset) throws S7Exception {
+ try {
+ final BeanParseResult result = BeanParser.parse(beanClass);
+ final byte[] buffer = this.connector.read(DaveArea.DB, dbNum, result.blockSize, byteOffset);
+ return extractBytes(beanClass, buffer, 0);
+ } catch (final Exception e) {
+ throw new S7Exception("dispense", e);
+ }
+ }
+
+ @Override
+ public synchronized T dispense(final Class beanClass, final int dbNum, final int byteOffset, final int blockSize) throws S7Exception {
+ try {
+ final byte[] buffer = this.connector.read(DaveArea.DB, dbNum, blockSize, byteOffset);
+ return extractBytes(beanClass, buffer, 0);
+ } catch (final Exception e) {
+ throw new S7Exception("dispense dbnum(" + dbNum + ") byteoffset(" + byteOffset + ") blocksize(" + blockSize + ")", e);
+ }
+ }
+
+ /**
+ * add by pnoker
+ */
+ @Override
+ public Object dispense(PlcS7PointVariable plcs7PointVariable) throws S7Exception {
+ try {
+ final byte[] buffer = this.connector.read(DaveArea.DB, plcs7PointVariable.getDbNum(), plcs7PointVariable.getSize(), plcs7PointVariable.getByteOffset());
+ return extractBytes(plcs7PointVariable, buffer, 0);
+ } catch (final Exception e) {
+ throw new S7Exception("dispense dbnum(" + plcs7PointVariable.getDbNum() + ") byteoffset(" + plcs7PointVariable.getByteOffset() + ") blocksize(" + plcs7PointVariable.getSize() + ")", e);
+ }
+ }
+
+ @Override
+ public synchronized void store(final Object bean, final int dbNum, final int byteOffset) {
+ try {
+ final BeanParseResult result = BeanParser.parse(bean);
+
+ final byte[] buffer = new byte[result.blockSize];
+ log.trace("store-buffer-size: " + buffer.length);
+
+ insertBytes(bean, buffer, 0);
+
+ this.connector.write(DaveArea.DB, dbNum, byteOffset, buffer);
+ } catch (final Exception e) {
+ throw new S7Exception("store", e);
+ }
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/BitConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/BitConverter.java
new file mode 100644
index 0000000..0aa7a93
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/BitConverter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+/**
+ * The Class BitConverter is responsible for converting bit values
+ */
+public final class BitConverter implements S7Serializable {
+
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ final byte bufValue = buffer[byteOffset];
+ return targetClass.cast(bufValue == (bufValue | (0x01 << bitOffset)));
+ }
+
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.BOOL;
+ }
+
+
+ @Override
+ public int getSizeInBits() {
+ return 1;
+ }
+
+
+ @Override
+ public int getSizeInBytes() {
+ return 0;
+ }
+
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final Boolean value = (Boolean) javaType;
+
+ //thx to @mfriedemann (https://github.com/mfriedemann)
+ if (value) {
+ buffer[byteOffset] |= (0x01 << bitOffset);
+ } else {
+ buffer[byteOffset] &= ~(0x01 << bitOffset);
+ }
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/ByteConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/ByteConverter.java
new file mode 100644
index 0000000..c420e91
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/ByteConverter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+public class ByteConverter implements S7Serializable {
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ return targetClass.cast(buffer[byteOffset]);
+ }
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.BYTE;
+ }
+
+ @Override
+ public int getSizeInBits() {
+ return 0;
+ }
+
+ @Override
+ public int getSizeInBytes() {
+ return 1;
+ }
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final Byte value = (Byte) javaType;
+ buffer[byteOffset] = value;
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/DateAndTimeConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/DateAndTimeConverter.java
new file mode 100644
index 0000000..6ae68ff
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/DateAndTimeConverter.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+import java.util.Calendar;
+import java.util.Date;
+
+public final class DateAndTimeConverter extends ByteConverter {
+
+ public static final int OFFSET_DAY = 2;
+ public static final int OFFSET_HOUR = 3;
+ public static final int OFFSET_MILLIS_1_AND_DOW = 7;
+ public static final int OFFSET_MILLIS_100_10 = 6;
+ public static final int OFFSET_MINUTE = 4;
+ public static final int OFFSET_MONTH = 1;
+ public static final int OFFSET_SECOND = 5;
+ public static final int OFFSET_YEAR = 0;
+
+ // 18, 1,16,16, 5,80,0,3, (dec)
+ // 12, 1,10,10, 5,50,0,3, (hex)
+ // 12-01-10 10:05:50.000
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ final Calendar c = Calendar.getInstance();
+ c.clear();
+
+ int year = this.getFromPLC(buffer, OFFSET_YEAR + byteOffset);
+
+ if (year < 90) {
+ // 1900 - 1989
+ year += 2000;
+ } else {
+ // 2000 - 2090
+ year += 1900;
+ }
+
+ int month = this.getFromPLC(buffer, OFFSET_MONTH + byteOffset);
+
+ if (month > 0) {
+ month--;
+ }
+
+ c.set(Calendar.YEAR, year);
+ c.set(Calendar.MONTH, month);
+ c.set(Calendar.DAY_OF_MONTH, this.getFromPLC(buffer, OFFSET_DAY + byteOffset));
+ c.set(Calendar.HOUR_OF_DAY, this.getFromPLC(buffer, OFFSET_HOUR + byteOffset));
+ c.set(Calendar.MINUTE, this.getFromPLC(buffer, OFFSET_MINUTE + byteOffset));
+ c.set(Calendar.SECOND, this.getFromPLC(buffer, OFFSET_SECOND + byteOffset));
+
+ /*
+ * TODO byte upperMillis = super.extract(Byte.class, buffer,
+ * OFFSET_MILLIS_100_10+byteOffset, bitOffset); byte lowerMillis =
+ * super.extract(Byte.class, buffer, OFFSET_MILLIS_1_AND_DOW+byteOffset,
+ * bitOffset);
+ *
+ * int ms100 = ( upperMillis >> 4 ); int ms10 = ( upperMillis & 0x0F );
+ * int ms1 = ( lowerMillis >> 4 );
+ *
+ * int millis = ms1 + ( 10*ms10 ) + ( 100*ms100 );
+ * c.set(Calendar.MILLISECOND, millis);
+ *
+ * int dow = ( lowerMillis & 0x0F ); c.set(Calendar.DAY_OF_WEEK, dow);
+ */
+
+ return targetClass.cast(c.getTime());
+ }
+
+ /**
+ * Dec to Hex 10 = 0a 16 = 0f 17 = 10
+ *
+ * @param buffer Byte Array
+ * @param offset Offset
+ * @return Byte
+ */
+ public byte getFromPLC(final byte[] buffer, final int offset) {
+ try {
+ final byte ret = super.extract(Byte.class, buffer, offset, 0);
+ return (byte) Integer.parseInt(Integer.toHexString(ret & 0xFF));
+ } catch (final NumberFormatException e) {
+ return 0;
+ }
+ }
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.DATE_AND_TIME;
+ }
+
+ @Override
+ public int getSizeInBits() {
+ return 0;
+ }
+
+ @Override
+ public int getSizeInBytes() {
+ return 8;
+ }
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final Date date = (Date) javaType;
+ final Calendar c = Calendar.getInstance();
+ c.setTime(date);
+
+ int year = c.get(Calendar.YEAR);
+
+ /*
+ * if (year < 1990 || year > 2090) throw new
+ * S7Exception("Invalid year: " + year + " @ offset: " + byteOffset);
+ */
+
+ if (year < 2000) {
+ // 1990 -1999
+ year -= 1900;
+ } else {
+ // 2000 - 2089
+ year -= 2000;
+ }
+
+ this.putToPLC(buffer, byteOffset + OFFSET_YEAR, year);
+ this.putToPLC(buffer, byteOffset + OFFSET_MONTH, c.get(Calendar.MONTH) + 1);
+ this.putToPLC(buffer, byteOffset + OFFSET_DAY, c.get(Calendar.DAY_OF_MONTH));
+ this.putToPLC(buffer, byteOffset + OFFSET_HOUR, c.get(Calendar.HOUR_OF_DAY));
+ this.putToPLC(buffer, byteOffset + OFFSET_MINUTE, c.get(Calendar.MINUTE));
+ this.putToPLC(buffer, byteOffset + OFFSET_SECOND, c.get(Calendar.SECOND));
+
+ /*
+ * TODO int msec1 = 0, msec10 = 0, msec100 = 0; Integer millis =
+ * c.get(Calendar.MILLISECOND); String mStr = millis.toString();
+ *
+ * if (mStr.length() > 2) { msec100 = Integer.parseInt(
+ * mStr.substring(0, 1) ); msec10 = Integer.parseInt( mStr.substring(1,
+ * 2) ); msec1 = Integer.parseInt( mStr.substring(2, 3) ); } else if
+ * (mStr.length() > 1) { msec10 = Integer.parseInt( mStr.substring(0, 1)
+ * ); msec1 = Integer.parseInt( mStr.substring(1, 2) ); } else { msec1 =
+ * Integer.parseInt( mStr.substring(0, 1) ); }
+ *
+ * super.insert( (byte)( (byte)msec10 | (byte)(msec100 << 4) ), buffer,
+ * OFFSET_MILLIS_100_10+byteOffset, 0, 1);
+ *
+ * int dow = c.get(Calendar.DAY_OF_WEEK);
+ *
+ * super.insert( (byte)( (byte)dow | (byte)(msec1 << 4) ), buffer,
+ * OFFSET_MILLIS_1_AND_DOW+byteOffset, 0, 1);
+ */
+ }
+
+ /**
+ * Hex to dec 0a = 10 0f = 16 10 = 17
+ *
+ * @param buffer Byte Array
+ * @param offset Offset
+ * @param i int
+ */
+ public void putToPLC(final byte[] buffer, final int offset, final int i) {
+ try {
+ final int ret = Integer.parseInt("" + i, 16);
+ buffer[offset] = (byte) ret;
+ } catch (final NumberFormatException e) {
+ return;
+ }
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/DateConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/DateConverter.java
new file mode 100644
index 0000000..26e1a73
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/DateConverter.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+import java.util.Calendar;
+import java.util.Date;
+
+public final class DateConverter extends IntegerConverter {
+
+ private static final long MILLI_TO_DAY_FACTOR = 24 * 60 * 60 * 1000;
+
+ /**
+ * 1.1.1990
+ */
+ private static final long OFFSET_1990;
+
+ static {
+ final Calendar c = Calendar.getInstance();
+ c.clear();
+ c.set(Calendar.HOUR_OF_DAY, 0);
+ c.set(Calendar.YEAR, 1990);
+
+ OFFSET_1990 = c.getTime().getTime();
+ }
+
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ final long days = super.extract(Integer.class, buffer, byteOffset, bitOffset);
+
+ long millis = days * MILLI_TO_DAY_FACTOR;
+
+ millis += OFFSET_1990;
+
+ final Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(millis);
+ c.set(Calendar.MILLISECOND, 0);
+ c.set(Calendar.SECOND, 0);
+ c.set(Calendar.MINUTE, 0);
+ c.set(Calendar.HOUR_OF_DAY, 0);
+
+ return targetClass.cast(c.getTime());
+ }
+
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.DATE;
+ }
+
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final Date d = (Date) javaType;
+
+ long millis = d.getTime();
+
+ millis -= OFFSET_1990;
+
+ final double days = (double) millis / (double) MILLI_TO_DAY_FACTOR;
+
+ final long ROUND = 1000;
+
+ final long expected = (long) ((days * MILLI_TO_DAY_FACTOR) / ROUND);
+ final long actual = millis / ROUND;
+
+ if (expected != actual) {
+ throw new IllegalArgumentException("Expected: " + expected + " got: " + actual);
+ }
+
+ if (millis < 0) {
+ super.insert(0, buffer, byteOffset, bitOffset, 2);
+ } else {
+ super.insert((int) Math.round(days), buffer, byteOffset, bitOffset, 2);
+ }
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/IntegerConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/IntegerConverter.java
new file mode 100644
index 0000000..aab9db3
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/IntegerConverter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+public class IntegerConverter implements S7Serializable {
+
+ private static final int OFFSET_HIGH_BYTE = 0;
+ private static final int OFFSET_LOW_BYTE = 1;
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ final byte lower = buffer[byteOffset + OFFSET_LOW_BYTE];
+ final byte higher = buffer[byteOffset + OFFSET_HIGH_BYTE];
+
+ final Integer i = (lower & 0xFF) | ((higher << 8) & 0xFF00);
+
+ return targetClass.cast(i);
+ }
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.WORD;
+ }
+
+ @Override
+ public int getSizeInBits() {
+ return 0;
+ }
+
+ @Override
+ public int getSizeInBytes() {
+ return 2;
+ }
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final Integer value = (Integer) javaType;
+ final byte lower = (byte) ((value) & 0xFF);
+ final byte higher = (byte) ((value >> 8) & 0xFF);
+ buffer[byteOffset + OFFSET_LOW_BYTE] = lower;
+ buffer[byteOffset + OFFSET_HIGH_BYTE] = higher;
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/LongConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/LongConverter.java
new file mode 100644
index 0000000..9b2bcc4
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/LongConverter.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+public final class LongConverter implements S7Serializable {
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ final byte b1 = buffer[byteOffset];
+ final byte b2 = buffer[byteOffset + 1];
+ final byte b3 = buffer[byteOffset + 2];
+ final byte b4 = buffer[byteOffset + 3];
+
+ final Integer i = ((b4) & 0x000000FF) |
+ ((b3 << 8) & 0x0000FF00) |
+ ((b2 << 16) & 0x00FF0000) |
+ ((b1 << 24) & 0xFF000000);
+
+ return targetClass.cast(i.longValue());
+ }
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.DWORD;
+ }
+
+ @Override
+ public int getSizeInBits() {
+ return 0;
+ }
+
+ @Override
+ public int getSizeInBytes() {
+ return 4;
+ }
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final Long value = (Long) javaType;
+ final byte b4 = (byte) ((value) & 0xFF);
+ final byte b3 = (byte) ((value >> 8) & 0xFF);
+ final byte b2 = (byte) ((value >> 16) & 0xFF);
+ final byte b1 = (byte) ((value >> 24) & 0xFF);
+ buffer[byteOffset] = b1;
+ buffer[byteOffset + 1] = b2;
+ buffer[byteOffset + 2] = b3;
+ buffer[byteOffset + 3] = b4;
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/RealConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/RealConverter.java
new file mode 100644
index 0000000..34d50ca
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/RealConverter.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+public final class RealConverter implements S7Serializable {
+
+ private static final int OFFSET_POS1 = 0;
+ private static final int OFFSET_POS2 = 1;
+ private static final int OFFSET_POS3 = 2;
+ private static final int OFFSET_POS4 = 3;
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ final int iValue = ((buffer[byteOffset + OFFSET_POS4] & 0xFF))
+ | ((buffer[byteOffset + OFFSET_POS3] & 0xFF) << 8) | ((buffer[byteOffset + OFFSET_POS2] & 0xFF) << 16)
+ | ((buffer[byteOffset + OFFSET_POS1] & 0xFF) << 24);
+
+ final Float fValue = Float.intBitsToFloat(iValue);
+
+ Object ret = fValue;
+
+ if (targetClass == Double.class) {
+ ret = Double.parseDouble(fValue.toString());
+ }
+
+ return targetClass.cast(ret);
+ }
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.REAL;
+ }
+
+ @Override
+ public int getSizeInBits() {
+ return 0;
+ }
+
+ @Override
+ public int getSizeInBytes() {
+ return 4;
+ }
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final float fValue = Float.parseFloat(javaType.toString());
+
+ final int iValue = Float.floatToIntBits(fValue);
+
+ buffer[byteOffset + OFFSET_POS4] = (byte) ((iValue) & 0xFF);
+ buffer[byteOffset + OFFSET_POS3] = (byte) ((iValue >> 8) & 0xFF);
+ buffer[byteOffset + OFFSET_POS2] = (byte) ((iValue >> 16) & 0xFF);
+ buffer[byteOffset + OFFSET_POS1] = (byte) ((iValue >> 24) & 0xFF);
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/ShortConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/ShortConverter.java
new file mode 100644
index 0000000..8977cde
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/ShortConverter.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+public class ShortConverter implements S7Serializable {
+
+ private static final short OFFSET_HIGH_BYTE = 0;
+ private static final short OFFSET_LOW_BYTE = 1;
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ final byte lower = buffer[byteOffset + OFFSET_LOW_BYTE];
+ final byte higher = buffer[byteOffset + OFFSET_HIGH_BYTE];
+
+ final Integer i = (lower & 0xFF) | ((higher << 8) & 0xFF00);
+
+ return targetClass.cast(i.shortValue());
+
+ }
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.INT;
+ }
+
+ @Override
+ public int getSizeInBits() {
+ return 0;
+ }
+
+ @Override
+ public int getSizeInBytes() {
+ return 2;
+ }
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final Short value = (Short) javaType;
+ final byte lower = (byte) ((value) & 0xFF);
+ final byte higher = (byte) ((value >> 8) & 0xFF);
+ buffer[byteOffset + OFFSET_LOW_BYTE] = lower;
+ buffer[byteOffset + OFFSET_HIGH_BYTE] = higher;
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/StringConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/StringConverter.java
new file mode 100644
index 0000000..0ca5b14
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/StringConverter.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.common.util.DecodeUtil;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+public final class StringConverter implements S7Serializable {
+
+ private static final int OFFSET_CURRENT_LENGTH = 1;
+ private static final int OFFSET_OVERALL_LENGTH = 0;
+ private static final int OFFSET_START = 2;
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ final int len = buffer[byteOffset + OFFSET_CURRENT_LENGTH] & 0xFF;
+
+ return targetClass.cast(new String(buffer, byteOffset + OFFSET_START, len));
+ }
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.STRING;
+ }
+
+ @Override
+ public int getSizeInBits() {
+ // Not static
+ return 0;
+ }
+
+ @Override
+ public int getSizeInBytes() {
+ // Not static
+ return 2; // 2 bytes overhead
+ }
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final String value = (String) javaType;
+
+ final int len = value.length();
+
+ if (len > size) {
+ throw new IllegalArgumentException("String to big: " + len);
+ }
+
+ buffer[byteOffset + OFFSET_OVERALL_LENGTH] = (byte) size;
+ buffer[byteOffset + OFFSET_CURRENT_LENGTH] = (byte) len;
+
+ final byte[] strBytes = DecodeUtil.stringToByte(value);
+ System.arraycopy(strBytes, 0, buffer, byteOffset + OFFSET_START, len);
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/StructConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/StructConverter.java
new file mode 100644
index 0000000..0dc68a7
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/StructConverter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.S7SerializerImpl;
+
+public final class StructConverter implements S7Serializable {
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ return S7SerializerImpl.extractBytes(targetClass, buffer, byteOffset);
+ }
+
+ @Override
+ public S7Type getS7Type() {
+ return null;
+ }
+
+ @Override
+ public int getSizeInBits() {
+ return 0;
+ }
+
+ @Override
+ public int getSizeInBytes() {
+ return 0;
+ }
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ S7SerializerImpl.insertBytes(javaType, buffer, byteOffset);
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/TimeConverter.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/TimeConverter.java
new file mode 100644
index 0000000..e230c1b
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/converter/TimeConverter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.converter;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+public final class TimeConverter extends ByteConverter {
+
+ @Override
+ public T extract(final Class targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
+ final byte b1 = super.extract(Byte.class, buffer, byteOffset + 3, bitOffset);
+ final byte b2 = super.extract(Byte.class, buffer, byteOffset + 2, bitOffset);
+ final byte b3 = super.extract(Byte.class, buffer, byteOffset + 1, bitOffset);
+ final byte b4 = super.extract(Byte.class, buffer, byteOffset, bitOffset);
+
+ final long l = ((long) b1 & 0xFF) | ((long) b2 & 0xFF) << 8 | ((long) b3 & 0xFF) << 16
+ | ((long) b4 & 0xFF) << 24;
+
+ return targetClass.cast(l);
+ }
+
+ @Override
+ public S7Type getS7Type() {
+ return S7Type.TIME;
+ }
+
+ @Override
+ public int getSizeInBytes() {
+ return 4;
+ }
+
+ @Override
+ public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
+ final int size) {
+ final long l = (Long) javaType;
+
+ final byte b1 = (byte) ((byte) (l) & 0xFF);
+ final byte b2 = (byte) ((byte) (l >> 8) & 0xFF);
+ final byte b3 = (byte) ((byte) (l >> 16) & 0xFF);
+ final byte b4 = (byte) ((byte) (l >> 24) & 0xFF);
+
+ super.insert(b1, buffer, byteOffset + 3, bitOffset, 1);
+ super.insert(b2, buffer, byteOffset + 2, bitOffset, 1);
+ super.insert(b3, buffer, byteOffset + 1, bitOffset, 1);
+ super.insert(b4, buffer, byteOffset, bitOffset, 1);
+ }
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/parser/BeanEntry.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/parser/BeanEntry.java
new file mode 100644
index 0000000..afef7a1
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/parser/BeanEntry.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.parser;
+
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+
+import java.lang.reflect.Field;
+
+/**
+ * A Bean-Entry
+ *
+ * @author Thomas Rudin
+ */
+public final class BeanEntry {
+ /**
+ * The Array size
+ */
+ public int arraySize;
+
+ /**
+ * Offsets and size
+ */
+ public int byteOffset, bitOffset, size;
+
+ /**
+ * The corresponding field
+ */
+ public Field field;
+
+ /**
+ * Array type
+ */
+ public boolean isArray;
+
+ /**
+ * The S7 Type
+ */
+ public S7Type s7type;
+
+ /**
+ * The corresponding serializer
+ */
+ public S7Serializable serializer;
+
+ /**
+ * The Java type
+ */
+ public Class> type;
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/parser/BeanParseResult.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/parser/BeanParseResult.java
new file mode 100644
index 0000000..79b8874
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/parser/BeanParseResult.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.parser;
+
+import java.util.Vector;
+
+public final class BeanParseResult {
+
+ /**
+ * The needed blocksize
+ */
+ public int blockSize;
+
+ /**
+ * The Bean entries
+ */
+ public Vector entries = new Vector();
+
+}
diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/parser/BeanParser.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/parser/BeanParser.java
new file mode 100644
index 0000000..2025c2a
--- /dev/null
+++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/com/github/s7/api/impl/serializer/parser/BeanParser.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2016-present the IoT DC3 original author or authors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.impl.serializer.parser;
+
+import org.nl.common.exception.ExceptionConstant;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.PlcS7PointVariable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Serializable;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.S7Type;
+import org.nl.iot.core.driver.protocol.plcs7.com.github.s7.api.annotation.S7Variable;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+
+@Slf4j
+public final class BeanParser {
+
+ private BeanParser() {
+ throw new IllegalStateException(ExceptionConstant.UTILITY_CLASS);
+ }
+
+ /**
+ * Returns the wrapper for the primitive type
+ *
+ * @param primitiveType Class
+ * @return Class
+ */
+ private static Class> getWrapperForPrimitiveType(final Class> primitiveType) {
+ if (primitiveType == boolean.class) {
+ return Boolean.class;
+ } else if (primitiveType == byte.class) {
+ return Byte.class;
+ } else if (primitiveType == int.class) {
+ return Integer.class;
+ } else if (primitiveType == float.class) {
+ return Float.class;
+ } else if (primitiveType == double.class) {
+ return Double.class;
+ } else if (primitiveType == long.class) {
+ return Long.class;
+ } else {
+ // Fallback
+ return primitiveType;
+ }
+ }
+
+
+ public static BeanEntry parse(PlcS7PointVariable plcs7PointVariable) throws Exception {
+ final BeanEntry entry = new BeanEntry();
+ entry.byteOffset = plcs7PointVariable.getByteOffset();
+ entry.bitOffset = plcs7PointVariable.getBitOffset();
+ entry.size = plcs7PointVariable.getSize();
+ entry.s7type = plcs7PointVariable.getType();
+ entry.type = getWrapperForPrimitiveType(plcs7PointVariable.getFieldType());
+ entry.serializer = entry.s7type.getSerializer().getDeclaredConstructor().newInstance();
+
+ return entry;
+ }
+
+ /**
+ * Parses a Class
+ *
+ * @param jclass Class
+ * @return BeanParseResult
+ * @throws Exception Exception
+ */
+ public static BeanParseResult parse(final Class> jclass) throws Exception {
+ final BeanParseResult res = new BeanParseResult();
+ log.trace("Parsing: " + jclass.getName());
+
+ for (final Field field : jclass.getFields()) {
+ final S7Variable dataAnnotation = field.getAnnotation(S7Variable.class);
+
+ if (dataAnnotation != null) {
+ log.trace("Parsing field: " + field.getName());
+ log.trace(" type: " + dataAnnotation.type());
+ log.trace(" byteOffset: " + dataAnnotation.byteOffset());
+ log.trace(" bitOffset: " + dataAnnotation.bitOffset());
+ log.trace(" size: " + dataAnnotation.size());
+ log.trace(" arraySize: " + dataAnnotation.arraySize());
+
+ final int offset = dataAnnotation.byteOffset();
+
+ // update max offset
+ if (offset > res.blockSize) {
+ res.blockSize = offset;
+ }
+
+ if (dataAnnotation.type() == S7Type.STRUCT) {
+ // recurse
+ log.trace("Recursing...");
+ final BeanParseResult subResult = parse(field.getType());
+ res.blockSize += subResult.blockSize;
+ log.trace(" New blocksize: " + res.blockSize);
+ }
+
+ log.trace(" New blocksize (+offset): " + res.blockSize);
+
+ // Add dynamic size
+ res.blockSize += dataAnnotation.size();
+
+ // Plain element
+ final BeanEntry entry = new BeanEntry();
+ entry.byteOffset = dataAnnotation.byteOffset();
+ entry.bitOffset = dataAnnotation.bitOffset();
+ entry.field = field;
+ entry.type = getWrapperForPrimitiveType(field.getType());
+ entry.size = dataAnnotation.size();
+ entry.s7type = dataAnnotation.type();
+ entry.isArray = field.getType().isArray();
+ entry.arraySize = dataAnnotation.arraySize();
+
+ if (entry.isArray) {
+ entry.type = getWrapperForPrimitiveType(entry.type.getComponentType());
+ }
+
+ // Create new serializer
+ final S7Serializable s = entry.s7type.getSerializer().getDeclaredConstructor().newInstance();
+ entry.serializer = s;
+
+ res.blockSize += (s.getSizeInBytes() * dataAnnotation.arraySize());
+ log.trace(" New blocksize (+array): " + res.blockSize);
+
+ if (s.getSizeInBits() > 0) {
+ boolean offsetOfBitAlreadyKnown = false;
+ for (final BeanEntry parsedEntry : res.entries) {
+ if (parsedEntry.byteOffset == entry.byteOffset) {
+ offsetOfBitAlreadyKnown = true;
+ }
+ }
+ if (!offsetOfBitAlreadyKnown) {
+ res.blockSize++;
+ }
+ }
+
+ res.entries.add(entry);
+ }
+ }
+
+ log.trace("Parsing done, overall size: " + res.blockSize);
+
+ return res;
+ }
+
+ /**
+ * Parses an Object
+ *
+ * @param obj Object
+ * @return BeanParseResult
+ * @throws Exception Exception
+ */
+ public static BeanParseResult parse(final Object obj) throws Exception {
+ return parse(obj.getClass());
+ }
+
+}
diff --git a/nl-vue/package.json b/nl-vue/package.json
index 0d1de68..f2dc4b2 100644
--- a/nl-vue/package.json
+++ b/nl-vue/package.json
@@ -10,7 +10,6 @@
"license": "Apache-2.0",
"author": "yubaoshan",
"scripts": {
- "install": "npm i",
"serve": "vite --host 0.0.0.0",
"dev": "vite --mode development --host 0.0.0.0",
"preview": "vite preview",
diff --git a/nl-web-app/src/test/java/org/nl/ApiTest.java b/nl-web-app/src/test/java/org/nl/ApiTest.java
index 9064125..0a1f1df 100644
--- a/nl-web-app/src/test/java/org/nl/ApiTest.java
+++ b/nl-web-app/src/test/java/org/nl/ApiTest.java
@@ -151,4 +151,9 @@ public class ApiTest {
e.printStackTrace();
}
}
+
+ @Test
+ public void plcS7TestRead() {
+
+ }
}