From 8446f991d3710fa45a30fc726804336ea501953a Mon Sep 17 00:00:00 2001 From: Nils Ritler <79571155+Slisls@users.noreply.github.com> Date: Fri, 2 Jun 2023 14:24:31 +0200 Subject: [PATCH] Field (#12) * ModbusAccessor finished and checked * read and write Field done. pushToField to do * field not finished, connection works * read csv file and add some comments --- src/main/java/ch/hevs/isi/core/DataPoint.java | 3 - .../ch/hevs/isi/field/BooleanRegister.java | 24 ++++++ .../ch/hevs/isi/field/FieldConnector.java | 83 +++++++++++++++++-- .../java/ch/hevs/isi/field/FloatRegister.java | 26 ++++++ .../ch/hevs/isi/field/ModbusAccessor.java | 74 +++++++++++------ .../ch/hevs/isi/field/ModbusRegister.java | 43 ++++++++++ src/main/java/ch/hevs/isi/field/PollTask.java | 10 +++ src/test/java/Field.java | 34 ++++++++ 8 files changed, 260 insertions(+), 37 deletions(-) create mode 100644 src/main/java/ch/hevs/isi/field/BooleanRegister.java create mode 100644 src/main/java/ch/hevs/isi/field/FloatRegister.java create mode 100644 src/main/java/ch/hevs/isi/field/ModbusRegister.java create mode 100644 src/main/java/ch/hevs/isi/field/PollTask.java create mode 100644 src/test/java/Field.java diff --git a/src/main/java/ch/hevs/isi/core/DataPoint.java b/src/main/java/ch/hevs/isi/core/DataPoint.java index 47f51e8..6923ae4 100644 --- a/src/main/java/ch/hevs/isi/core/DataPoint.java +++ b/src/main/java/ch/hevs/isi/core/DataPoint.java @@ -35,9 +35,6 @@ public abstract class DataPoint{ } } - - - /** * Just get the label of this DataPoint * @return the label in a string diff --git a/src/main/java/ch/hevs/isi/field/BooleanRegister.java b/src/main/java/ch/hevs/isi/field/BooleanRegister.java new file mode 100644 index 0000000..a71e5f0 --- /dev/null +++ b/src/main/java/ch/hevs/isi/field/BooleanRegister.java @@ -0,0 +1,24 @@ +package ch.hevs.isi.field; + +import ch.hevs.isi.core.BooleanDataPoint; +import ch.hevs.isi.core.DataPoint; + +public class BooleanRegister extends ModbusRegister{ + private boolean value; + private BooleanDataPoint bdp; + + public BooleanRegister(String label, boolean isOutput, int address){ + this.bdp = new BooleanDataPoint(label, isOutput); + value = bdp.getValue(); + updateMapOfRegisters(bdp, address); + } + @Override + public void read() { + bdp.setValue(ModbusAccessor.getMySelf().readBoolean(this.getAddress())); + } + + @Override + public void write() { + ModbusAccessor.getMySelf().writeBoolean(this.getAddress(), bdp.getValue()); + } +} diff --git a/src/main/java/ch/hevs/isi/field/FieldConnector.java b/src/main/java/ch/hevs/isi/field/FieldConnector.java index 3180d21..3d26045 100644 --- a/src/main/java/ch/hevs/isi/field/FieldConnector.java +++ b/src/main/java/ch/hevs/isi/field/FieldConnector.java @@ -4,14 +4,24 @@ import ch.hevs.isi.core.DataPoint; import ch.hevs.isi.core.DataPointListener; import ch.hevs.isi.core.FloatDataPoint; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.Timer; + public class FieldConnector implements DataPointListener { - private static FieldConnector mySelf = null; - private FieldConnector(){ - + initialize("LocalHost",1502, "C:/Nils/Hesso/4_Semester/SIN/Minecraft_Electrical_Age_Project/ModbusMap.csv"); } + /** + * static method to create a singleton pattern of the class + * checks if an instance of the class is already made + * if not, it creates an instance of the class FieldConnector + * @return instance of FieldConnector + */ public static FieldConnector getMySelf(){ if (mySelf == null){ mySelf = new FieldConnector(); @@ -19,16 +29,73 @@ public class FieldConnector implements DataPointListener { return mySelf; } - public void initialize(String host, int port){ + /** + * read the csv-file of the ModbusMap + * @param pathToFile path to the file of all modbus registers (C:/.../ModbusMap.csv) + */ + public static void createRegister(String pathToFile){ + try{ + BufferedReader csvFile = new BufferedReader(new FileReader(pathToFile)); + csvFile.readLine(); + while(csvFile.ready()){ + String line = csvFile.readLine(); // read one line + String[] splitLine = line.split(";"); // split line between ";" + + String label = splitLine[0]; // first split is the label of the register + boolean isOutput = splitLine[3].equals("N"); // third split declares if it is an output + int address = new Integer((splitLine[4])); // fourth split is the address of the register + float range = new Float(splitLine[5]); // if it is a floatDatapoint, the fifth split is the range of the data + float offset = new Float(splitLine[6]); // if it is a floatDatapoint, the sixth split is the offset of the data + + /* + // create a float or a boolean register + if (splitLine[1].equals("B")){ + BooleanRegister b = new BooleanRegister(label, isOutput, address); + } else if(splitLine[1].equals("F")){ + FloatRegister f = new FloatRegister(label, isOutput, address, range, offset); + } + */ + } + } + catch(FileNotFoundException e){ + e.printStackTrace(); + } + catch (IOException e){ + e.printStackTrace(); + } } - private void pushToField(DataPoint dp){ - System.out.println(dp.toString() + " -> Field"); + /** + * this method initialize the fieldConnector + * it connects the ModbusAccessor, reads the csv-file of the ModbusMap + * and starts the periodical polling of the modbus registers + * @param host ip address of the server + * @param port port of the server + * @param pathToFile path to the file of all modbus registers (C:/.../ModbusMap.csv) + */ + public void initialize(String host, int port, String pathToFile){ + ModbusAccessor.getMySelf().connect(host,port); + createRegister(pathToFile); + startPeriodicalPolling(); + } + private void pushToField(String label, String value){ + System.out.println("Field: " + label + " " + value); } - @Override public void onNewValue(DataPoint dp) { - pushToField(dp); + ModbusRegister mR = ModbusRegister.getRegisterFromDatapoint(dp); + mR.write(); + pushToField(dp.getLabel(),dp.toString()); + } + + /** + * method to start a periodical task + * in our case it is the reading of the modbus registers + */ + public void startPeriodicalPolling(){ + Timer pollTimer = new Timer(); + PollTask pollTask = new PollTask(); + pollTimer.scheduleAtFixedRate(pollTask,0,100); } } diff --git a/src/main/java/ch/hevs/isi/field/FloatRegister.java b/src/main/java/ch/hevs/isi/field/FloatRegister.java new file mode 100644 index 0000000..214bcf0 --- /dev/null +++ b/src/main/java/ch/hevs/isi/field/FloatRegister.java @@ -0,0 +1,26 @@ +package ch.hevs.isi.field; + +import ch.hevs.isi.core.DataPoint; +import ch.hevs.isi.core.FloatDataPoint; + +import java.util.HashMap; + +public class FloatRegister extends ModbusRegister{ + private Float value; + private FloatDataPoint fdp; + public FloatRegister(String label, boolean isOutPut, int address, float range, float offset) { + this.fdp = new FloatDataPoint(label, isOutPut); + value = fdp.getValue(); + updateMapOfRegisters(fdp,address); + } + + @Override + public void read() { + fdp.setValue(ModbusAccessor.getMySelf().readFloat(this.getAddress())); + } + + @Override + public void write() { + ModbusAccessor.getMySelf().writeFloat(this.getAddress(), fdp.getValue()); + } +} \ No newline at end of file diff --git a/src/main/java/ch/hevs/isi/field/ModbusAccessor.java b/src/main/java/ch/hevs/isi/field/ModbusAccessor.java index d5612ae..bff52b3 100644 --- a/src/main/java/ch/hevs/isi/field/ModbusAccessor.java +++ b/src/main/java/ch/hevs/isi/field/ModbusAccessor.java @@ -9,6 +9,7 @@ import com.serotonin.modbus4j.exception.ModbusTransportException; import com.serotonin.modbus4j.ip.IpParameters; import com.serotonin.modbus4j.ip.tcp.TcpMaster; import com.serotonin.modbus4j.locator.BaseLocator; +import com.sun.org.apache.xpath.internal.operations.Mod; public class ModbusAccessor { @@ -19,7 +20,6 @@ public class ModbusAccessor { * private constructor * */ private ModbusAccessor(){ - } /** @@ -63,27 +63,39 @@ public class ModbusAccessor { * method to write a boolean value in the correct modbus register * @param register address of the register * @param value the desired boolean value - * @throws ModbusTransportException - * @throws ErrorResponseException */ - public void writeBoolean (int register, boolean value) throws ModbusTransportException, ErrorResponseException{ + public void writeBoolean (int register, boolean value){ //first parameter = slaveID = always 1 because we only have one //second parameter = register address ==> it is named offset because it starts with 0 and goes to the desired address - this.master.setValue(BaseLocator.coilStatus(1,register), value); //set the desired value in the correct register + try{ + this.master.setValue(BaseLocator.coilStatus(1,register), value); //set the desired value in the correct register + } + catch (ModbusTransportException e){ + e.printStackTrace(); + } + catch (ErrorResponseException e){ + e.printStackTrace(); + } } /** * method to write a float value in the correct modbus register * @param register address of the register * @param value the desired float value - * @throws ModbusTransportException - * @throws ErrorResponseException */ - public void writeFloat (int register, float value) throws ModbusTransportException, ErrorResponseException{ + public void writeFloat (int register, float value){ //first parameter = slaveID = always 1 because we only have one //second parameter = register address ==> it is named offset because it starts with 0 and goes to the desired address //third parameter = DataType of the value. The max value is 3 Byte Float, but the class DataType has only 2 or 4 byte - this.master.setValue(BaseLocator.holdingRegister(1,register,DataType.FOUR_BYTE_FLOAT), value); + try{ + this.master.setValue(BaseLocator.holdingRegister(1,register,DataType.FOUR_BYTE_FLOAT), value); + } + catch (ModbusTransportException e){ + e.printStackTrace(); + } + catch (ErrorResponseException e){ + e.printStackTrace(); + } } //methods to read /** @@ -91,41 +103,55 @@ public class ModbusAccessor { * get the coil status of the register. * @param register address of register * @return boolean value of the desired register - * @throws ModbusTransportException - * @throws ErrorResponseException */ - public boolean readBoolean(int register) throws ModbusTransportException, ErrorResponseException { + public boolean readBoolean(int register){ //first parameter = slaveID = always 1 because we only have one //second parameter = register address ==> it is named offset because it starts with 0 and goes to the desired address - boolean booleanValue = this.master.getValue(BaseLocator.coilStatus(1,register)); - return booleanValue; + try{ + boolean booleanValue = this.master.getValue(BaseLocator.coilStatus(1,register)); + return booleanValue; + } + catch (ModbusTransportException e){ + e.printStackTrace(); + } + catch (ErrorResponseException e){ + e.printStackTrace(); + } + return false; } /** * method to read a boolean value in the correct modbus register * get the value from the holding register * @param register address of the register * @return float value of the desired register - * @throws ModbusTransportException - * @throws ErrorResponseException */ - public float readFloat(int register)throws ModbusTransportException, ErrorResponseException{ + public float readFloat(int register){ //first parameter = slaveID = always 1 because we only have one //second parameter = register address ==> it is named offset because it starts with 0 and goes to the desired address //third parameter = DataType of the value. The max value is 3 Byte Float, but the class DataType has only 2 or 4 byte - float floatValue = (float) this.master.getValue(BaseLocator.holdingRegister(1,register, DataType.FOUR_BYTE_FLOAT)); - return floatValue; + try { + float floatValue = (float) this.master.getValue(BaseLocator.holdingRegister(1,register, DataType.FOUR_BYTE_FLOAT)); + return floatValue; + } + catch (ModbusTransportException e){ + e.printStackTrace(); + } + catch (ErrorResponseException e){ + e.printStackTrace(); + } + return 0F; } /** * this main method is only for testing the ModbusAccessor class * @param args */ + /* public static void main(String[] args) { //create an instance of ModbusAccessor and connect it with the server ModbusAccessor test = ModbusAccessor.getMySelf(); test.connect("LocalHost", 1502); //do this all the time while(true){ - try{ //get a boolean value => solar SetPoint boolean solar_connect_st = test.readBoolean(609); //SOLAR_CONNECT_ST //get a float value => factory SetPoint @@ -137,7 +163,7 @@ public class ModbusAccessor { test.writeBoolean(401,false); //REMOTE_SOLAR_SW //check the factory SetPoint - System.out.println("Factory Setpoint is: " + factory_st); + System.out.println("Factory SetPoint is: " + factory_st); //check the solar SetPoint if(solar_connect_st){ @@ -145,13 +171,9 @@ public class ModbusAccessor { }else{ System.out.println("Solar is disconnected"); } - }catch (ModbusTransportException e){ - - }catch (ErrorResponseException e){ - - } } } + */ } diff --git a/src/main/java/ch/hevs/isi/field/ModbusRegister.java b/src/main/java/ch/hevs/isi/field/ModbusRegister.java new file mode 100644 index 0000000..f963845 --- /dev/null +++ b/src/main/java/ch/hevs/isi/field/ModbusRegister.java @@ -0,0 +1,43 @@ +package ch.hevs.isi.field; + +import ch.hevs.isi.core.DataPoint; +import ch.hevs.isi.core.FloatDataPoint; + +import java.util.HashMap; + +public abstract class ModbusRegister { + private int address; + + /** + * get the address of the modbus register + * @return address of the modbus register + */ + public int getAddress() { + return address; + } + private final static HashMap mapOfRegisters = new HashMap<>(); + + /** + * get the modbus register from the desired datapoint + * @param dp the desired datapoint + * @return modbus register + */ + public static ModbusRegister getRegisterFromDatapoint(DataPoint dp){ + return mapOfRegisters.get(dp); + } + public void updateMapOfRegisters(DataPoint dp, int address){ + this.address = address; + mapOfRegisters.put(dp,this); + } + + /** + * read periodically each modbus register + */ + public static void poll(){ + for (ModbusRegister mr : mapOfRegisters.values()){ + mr.read(); //read all values (registers) of the map + } + } + public abstract void read(); //abstract prototype of the method read + public abstract void write(); //abstract prototype of the method read +} diff --git a/src/main/java/ch/hevs/isi/field/PollTask.java b/src/main/java/ch/hevs/isi/field/PollTask.java new file mode 100644 index 0000000..a01ccc2 --- /dev/null +++ b/src/main/java/ch/hevs/isi/field/PollTask.java @@ -0,0 +1,10 @@ +package ch.hevs.isi.field; + +import java.util.TimerTask; + +public class PollTask extends TimerTask { + @Override + public void run() { + ModbusRegister.poll(); + } +} diff --git a/src/test/java/Field.java b/src/test/java/Field.java new file mode 100644 index 0000000..7cd5802 --- /dev/null +++ b/src/test/java/Field.java @@ -0,0 +1,34 @@ +import ch.hevs.isi.core.BooleanDataPoint; +import ch.hevs.isi.core.FloatDataPoint; +import ch.hevs.isi.field.BooleanRegister; +import ch.hevs.isi.field.FieldConnector; +import ch.hevs.isi.field.FloatRegister; + +public class Field { + public static void main(String[] args) { + + + //FloatRegister fRI = new FloatRegister("GRID_U_FLOAT",false,89); + BooleanRegister bRI = new BooleanRegister("SOLAR_CONNECT_ST", false ,609); + FieldConnector.getMySelf().startPeriodicalPolling(); + + //FloatRegister fRO = new FloatRegister("REMOTE_FACTORY_SP",true,205); + BooleanRegister bRO = new BooleanRegister("REMOTE_SOLAR_SW", true ,401); + + /* + fRO.fdp.setValue(0.8F); + bRO.bdp.setValue(true); + */ + + while(true) + { + /* + float value = fRI.dataPoint.getValue()*1000; + System.out.println(value); + */ + /* + System.out.println(bRI.bdp.getValue()); + */ + } + } +}